@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
|
@@ -7,7 +7,7 @@ import { DatabaseError } from "../../../errors/index.js";
|
|
|
7
7
|
import { HOMEPAGE_SECTION_FIELDS } from "../../../constants/field-names.js";
|
|
8
8
|
import { BaseRepository, prepareForFirestore, parseSieveDateValue, } from "../../../providers/db-firebase/index.js";
|
|
9
9
|
import { normalizeError } from "../../../errors/normalize.js";
|
|
10
|
-
import { HOMEPAGE_SECTIONS_COLLECTION, createHomepageSectionId, } from "../schemas/index.js";
|
|
10
|
+
import { DEFAULT_SECTION_SURFACE, HOMEPAGE_SECTIONS_COLLECTION, createHomepageSectionId, } from "../schemas/index.js";
|
|
11
11
|
export class HomepageSectionsRepository extends BaseRepository {
|
|
12
12
|
constructor() {
|
|
13
13
|
super(HOMEPAGE_SECTIONS_COLLECTION);
|
|
@@ -16,7 +16,9 @@ export class HomepageSectionsRepository extends BaseRepository {
|
|
|
16
16
|
return this.sieveQuery(model, HomepageSectionsRepository.SIEVE_FIELDS, { defaultPageSize: 50, maxPageSize: 200 });
|
|
17
17
|
}
|
|
18
18
|
async create(input) {
|
|
19
|
-
|
|
19
|
+
// Surface participates in the id, or a category `products` section would
|
|
20
|
+
// overwrite the homepage's — same type, same slug, one document.
|
|
21
|
+
const id = createHomepageSectionId(input.type, input.surface);
|
|
20
22
|
const sectionData = {
|
|
21
23
|
...input,
|
|
22
24
|
createdAt: new Date(),
|
|
@@ -68,14 +70,36 @@ export class HomepageSectionsRepository extends BaseRepository {
|
|
|
68
70
|
},
|
|
69
71
|
});
|
|
70
72
|
}
|
|
71
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Enabled sections for one surface, in `order`.
|
|
75
|
+
*
|
|
76
|
+
* 🛑 The parameter DEFAULTS to `"homepage"`, and that default is the safety
|
|
77
|
+
* property, not a convenience. This method previously returned every enabled
|
|
78
|
+
* row regardless of surface — so the moment a category-surface row exists,
|
|
79
|
+
* an unfiltered homepage would render it. Defaulting here means the existing
|
|
80
|
+
* homepage call site is correct with no change at all, and a caller that
|
|
81
|
+
* wants another surface has to say so.
|
|
82
|
+
*
|
|
83
|
+
* 🛑 The surface is matched IN MEMORY, deliberately. The only composite index
|
|
84
|
+
* on this collection is `(enabled, order)`;
|
|
85
|
+
* `where(enabled).where(surface).orderBy(order)` is a three-field composite it
|
|
86
|
+
* does not cover, and Firestore throws FAILED_PRECONDITION at RUNTIME rather
|
|
87
|
+
* than at build time. `MarketplaceHomepageView` already filters sections in
|
|
88
|
+
* memory for the listing-type gate — this follows that precedent. Section
|
|
89
|
+
* counts are tens, so the read is unchanged in cost.
|
|
90
|
+
*/
|
|
91
|
+
async getEnabledSections(surface = DEFAULT_SECTION_SURFACE) {
|
|
72
92
|
try {
|
|
73
93
|
const snapshot = await this.db
|
|
74
94
|
.collection(this.collection)
|
|
75
95
|
.where(HOMEPAGE_SECTION_FIELDS.ENABLED, "==", true)
|
|
76
96
|
.orderBy(HOMEPAGE_SECTION_FIELDS.ORDER, "asc")
|
|
77
97
|
.get();
|
|
78
|
-
return snapshot.docs
|
|
98
|
+
return snapshot.docs
|
|
99
|
+
.map((doc) => this.mapDoc(doc))
|
|
100
|
+
// Absent means "homepage" — every row written before `surface` existed
|
|
101
|
+
// was a homepage row, so this keeps all 23 of them on the homepage.
|
|
102
|
+
.filter((row) => (row.surface ?? DEFAULT_SECTION_SURFACE) === surface);
|
|
79
103
|
}
|
|
80
104
|
catch (error) {
|
|
81
105
|
void normalizeError(error);
|
|
@@ -96,17 +120,35 @@ export class HomepageSectionsRepository extends BaseRepository {
|
|
|
96
120
|
throw new DatabaseError(`Failed to retrieve disabled sections: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
97
121
|
}
|
|
98
122
|
}
|
|
99
|
-
|
|
123
|
+
/**
|
|
124
|
+
* 🛑 `surface` is NOT optional in spirit, even though it defaults.
|
|
125
|
+
*
|
|
126
|
+
* This was `where(type == X).limit(1)`, which assumed ONE document per type.
|
|
127
|
+
* With surfaces that assumption is false — a `products` section can exist on
|
|
128
|
+
* the homepage AND on a category page — and `limit(1)` would return whichever
|
|
129
|
+
* Firestore happened to order first. An arbitrary-but-plausible answer is the
|
|
130
|
+
* worst failure shape available here, because nothing errors.
|
|
131
|
+
*
|
|
132
|
+
* The surface is matched IN MEMORY rather than added as a second `where`: the
|
|
133
|
+
* only composite index on this collection is `(enabled, order)`, and
|
|
134
|
+
* `where(type).where(surface)` needs one that does not exist. Fetching the few
|
|
135
|
+
* rows of a type and picking by surface costs nothing at these counts.
|
|
136
|
+
*/
|
|
137
|
+
async getSectionByType(type, surface = DEFAULT_SECTION_SURFACE) {
|
|
100
138
|
try {
|
|
101
139
|
const snapshot = await this.db
|
|
102
140
|
.collection(this.collection)
|
|
103
141
|
.where(HOMEPAGE_SECTION_FIELDS.TYPE, "==", type)
|
|
104
|
-
.limit(1)
|
|
105
142
|
.get();
|
|
106
143
|
if (snapshot.empty)
|
|
107
144
|
return null;
|
|
108
|
-
const
|
|
109
|
-
|
|
145
|
+
const match = snapshot.docs.find((d) => {
|
|
146
|
+
const rowSurface = d.data().surface ?? DEFAULT_SECTION_SURFACE;
|
|
147
|
+
return rowSurface === surface;
|
|
148
|
+
});
|
|
149
|
+
if (!match)
|
|
150
|
+
return null;
|
|
151
|
+
return this.mapDoc(match);
|
|
110
152
|
}
|
|
111
153
|
catch (error) {
|
|
112
154
|
void normalizeError(error);
|
|
@@ -219,6 +261,14 @@ export class HomepageSectionsRepository extends BaseRepository {
|
|
|
219
261
|
HomepageSectionsRepository.SIEVE_FIELDS = {
|
|
220
262
|
type: { canFilter: true, canSort: false },
|
|
221
263
|
enabled: { canFilter: true, canSort: false },
|
|
264
|
+
/*
|
|
265
|
+
* 🛑 Required, not optional polish. `sieve.ts` sets
|
|
266
|
+
* `throwExceptions: false`, so a field absent from this allowlist does not
|
|
267
|
+
* raise — `findField()` returns undefined and the clause is silently
|
|
268
|
+
* DROPPED. `?filters=surface==category` would then return every section on
|
|
269
|
+
* every surface while looking like it had filtered. Root Cause #62.
|
|
270
|
+
*/
|
|
271
|
+
surface: { canFilter: true, canSort: false },
|
|
222
272
|
order: { canFilter: true, canSort: true },
|
|
223
273
|
createdAt: { canFilter: true, canSort: true, parseValue: parseSieveDateValue },
|
|
224
274
|
updatedAt: { canFilter: true, canSort: true, parseValue: parseSieveDateValue },
|
|
@@ -671,22 +671,125 @@ export interface GoogleReviewsSectionConfig {
|
|
|
671
671
|
linkToGoogleMaps?: boolean;
|
|
672
672
|
googleMapsUrl?: string;
|
|
673
673
|
}
|
|
674
|
-
|
|
674
|
+
/**
|
|
675
|
+
* Added 2026-10-19 promoting `HowItWorksSection` out of the orphan set — see
|
|
676
|
+
* `HowItWorksSection.tsx`'s own docstring for why `renderIcon`/`onCtaClick`
|
|
677
|
+
* (function props, not serialisable) became `iconKey`/`ctaLink`. `steps` is
|
|
678
|
+
* inline because the step count/order IS the authored content, same reasoning
|
|
679
|
+
* as `TestimonialsSectionConfig.testimonials` below.
|
|
680
|
+
*/
|
|
681
|
+
export interface HowItWorksStepConfig {
|
|
682
|
+
number: number;
|
|
683
|
+
title: string;
|
|
684
|
+
desc: string;
|
|
685
|
+
iconKey?: string;
|
|
686
|
+
iconColor?: string;
|
|
687
|
+
iconBg?: string;
|
|
688
|
+
badgeBg?: string;
|
|
689
|
+
}
|
|
690
|
+
export interface HowItWorksSectionConfig {
|
|
691
|
+
title: string;
|
|
692
|
+
subtitle?: string;
|
|
693
|
+
pillLabel?: string;
|
|
694
|
+
ctaLabel?: string;
|
|
695
|
+
ctaLink?: string;
|
|
696
|
+
steps: HowItWorksStepConfig[];
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Added 2026-10-19 promoting `TestimonialsCarousel` out of the orphan set.
|
|
700
|
+
* Deliberately NOT a read from the `testimonials` collection shape
|
|
701
|
+
* (`Testimonial` in `types/index.ts`) — `featured`/`sortOrder`/`active` are
|
|
702
|
+
* collection-row housekeeping with no meaning inside an already-ordered
|
|
703
|
+
* config array, and `avatarUrl` was declared there and never rendered. No
|
|
704
|
+
* `autoScroll`/`scrollInterval`/`loop` either: the component has no autoplay,
|
|
705
|
+
* arrows or dots — it is not actually a carousel, despite the name.
|
|
706
|
+
*/
|
|
707
|
+
/** An embedded sub-document with its own `id` — a type alias, not a Firestore collection root, so it does not extend `BaseDocument`. */
|
|
708
|
+
export type TestimonialConfigEntry = {
|
|
709
|
+
id: string;
|
|
710
|
+
name: string;
|
|
711
|
+
rating: 1 | 2 | 3 | 4 | 5;
|
|
712
|
+
text: string;
|
|
713
|
+
};
|
|
714
|
+
export interface TestimonialsSectionConfig {
|
|
715
|
+
eyebrow?: string;
|
|
716
|
+
heading?: string;
|
|
717
|
+
testimonials: TestimonialConfigEntry[];
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Added 2026-10-19 promoting `PromoGrid` out of the orphan set. `banners` is
|
|
721
|
+
* capped at `PROMO_GRID_MAX_BANNERS` (4) by the component itself — the
|
|
722
|
+
* layout has exactly one hero slot and three regular ones, so a 5th banner
|
|
723
|
+
* is silently dropped, not a bug. No admin background/colour field: the dark
|
|
724
|
+
* theme is intentionally hardcoded (Root Cause #67 — a themed background
|
|
725
|
+
* paired with fixed white ink would invert wrong in a light theme; this
|
|
726
|
+
* component is always dark, by design, so it never pairs the two).
|
|
727
|
+
*/
|
|
728
|
+
/** An embedded sub-document with its own `id` — a type alias, not a Firestore collection root, so it does not extend `BaseDocument`. */
|
|
729
|
+
export type PromoBannerConfigEntry = {
|
|
730
|
+
id: string;
|
|
731
|
+
title: string;
|
|
732
|
+
ctaLabel: string;
|
|
733
|
+
ctaUrl: string;
|
|
734
|
+
image: string;
|
|
735
|
+
};
|
|
736
|
+
export interface PromoGridSectionConfig {
|
|
737
|
+
eyebrow?: string;
|
|
738
|
+
heading?: string;
|
|
739
|
+
banners: PromoBannerConfigEntry[];
|
|
740
|
+
}
|
|
741
|
+
export type SectionType = "welcome" | "carousel" | "stats" | "trust-indicators" | "categories" | "brands" | "products" | "pre-orders" | "auctions" | "banner" | "features" | "reviews" | "whatsapp-community" | "faq" | "blog-articles" | "newsletter" | "stores" | "events" | "social-feed" | "custom-cards" | "google-reviews" | "featured-bundles" | "prize-draws" | "event-raffles" | "collection-cards" | "how-it-works" | "testimonials" | "promo-grid";
|
|
675
742
|
export type SectionConfig = CarouselSectionConfig | WelcomeSectionConfig | StatsSectionConfig | TrustIndicatorsSectionConfig | CategoriesSectionConfig | BrandsSectionConfig | ProductsSectionConfig | PreOrdersSectionConfig | AuctionsSectionConfig | BannerSectionConfig | FeaturesSectionConfig | ReviewsSectionConfig | WhatsAppCommunitySectionConfig | FAQSectionConfig | BlogArticlesSectionConfig | NewsletterSectionConfig | StoresSectionConfig | EventsSectionConfig | SocialFeedSectionConfig | CustomCardsSectionConfig | GoogleReviewsSectionConfig | FeaturedBundlesSectionConfig | PrizeDrawsSectionConfig | EventRafflesSectionConfig | CollectionCardsSectionConfig;
|
|
743
|
+
/**
|
|
744
|
+
* Which page a section row belongs to.
|
|
745
|
+
*
|
|
746
|
+
* One collection, one owner per surface. This does NOT reintroduce the
|
|
747
|
+
* `siteSettings.homepageLayout` that `sectionTemplates.ts` deliberately refuses
|
|
748
|
+
* — that note forbids a SECOND owner of the homepage's layout, and this keeps
|
|
749
|
+
* `homepageSections` the single source of truth while letting a category or a
|
|
750
|
+
* brand page own its own ordered list.
|
|
751
|
+
*/
|
|
752
|
+
export declare const SECTION_SURFACE_VALUES: readonly ["homepage", "category", "brand", "product", "store"];
|
|
753
|
+
export type SectionSurface = (typeof SECTION_SURFACE_VALUES)[number];
|
|
754
|
+
/** Absent means `"homepage"`. See the field comment below. */
|
|
755
|
+
export declare const DEFAULT_SECTION_SURFACE: SectionSurface;
|
|
676
756
|
export interface HomepageSectionDocument extends BaseDocument {
|
|
677
757
|
type: SectionType;
|
|
678
758
|
order: number;
|
|
679
759
|
enabled: boolean;
|
|
680
760
|
config: SectionConfig;
|
|
761
|
+
/**
|
|
762
|
+
* 🛑 OPTIONAL, and that is load-bearing. Every other field on this document
|
|
763
|
+
* is required, so a non-optional `surface` would make every one of the 23
|
|
764
|
+
* existing rows fail the type on read. Absent therefore means
|
|
765
|
+
* `DEFAULT_SECTION_SURFACE` — which is also the honest reading of history,
|
|
766
|
+
* since every row written before this existed was a homepage row.
|
|
767
|
+
*
|
|
768
|
+
* 🛑 Filter it IN MEMORY, never as a Firestore clause. The only composite
|
|
769
|
+
* index on this collection is `(enabled, order)`;
|
|
770
|
+
* `where(enabled).where(surface).orderBy(order)` is a three-field composite
|
|
771
|
+
* it does not cover and Firestore throws FAILED_PRECONDITION at RUNTIME, not
|
|
772
|
+
* at build time. `MarketplaceHomepageView` already filters sections in memory
|
|
773
|
+
* for the listing-type gate — follow that precedent. Section counts are tens.
|
|
774
|
+
*/
|
|
775
|
+
surface?: SectionSurface;
|
|
681
776
|
}
|
|
682
777
|
export declare const HOMEPAGE_SECTIONS_COLLECTION: "homepageSections";
|
|
683
778
|
export declare const HOMEPAGE_SECTIONS_INDEXED_FIELDS: readonly ["enabled", "order", "type"];
|
|
684
779
|
export declare const DEFAULT_SECTION_ORDER: Record<SectionType, number>;
|
|
685
780
|
export declare const BANNER_HEIGHTS: Record<BannerSectionConfig["height"], string>;
|
|
686
781
|
export type HomepageSectionCreateInput = Omit<HomepageSectionDocument, "id" | "createdAt" | "updatedAt">;
|
|
687
|
-
export type HomepageSectionUpdateInput = Partial<Pick<HomepageSectionDocument, "order" | "enabled" | "config">>;
|
|
782
|
+
export type HomepageSectionUpdateInput = Partial<Pick<HomepageSectionDocument, "order" | "enabled" | "config" | "surface">>;
|
|
688
783
|
export declare const homepageSectionQueryHelpers: {
|
|
689
784
|
readonly enabled: () => readonly ["enabled", "==", true];
|
|
690
785
|
readonly byType: (type: SectionType) => readonly ["type", "==", SectionType];
|
|
691
786
|
};
|
|
692
|
-
|
|
787
|
+
/**
|
|
788
|
+
* 🛑 The surface is part of the id, or a category's `products` section collides
|
|
789
|
+
* with the homepage's — same type, same generated slug, one document.
|
|
790
|
+
*
|
|
791
|
+
* `"homepage"` is omitted from the id so every existing row keeps the exact id
|
|
792
|
+
* it already has. A migration here would be a rename of 23 live documents to
|
|
793
|
+
* gain nothing.
|
|
794
|
+
*/
|
|
795
|
+
export declare function createHomepageSectionId(type: SectionType, surface?: SectionSurface): string;
|
|
@@ -67,6 +67,24 @@ export const ALLOWED_LIVE_COLLECTIONS = [
|
|
|
67
67
|
"bids",
|
|
68
68
|
];
|
|
69
69
|
export const COLLECTION_CARDS_MAX_ENTRIES = 3;
|
|
70
|
+
/**
|
|
71
|
+
* Which page a section row belongs to.
|
|
72
|
+
*
|
|
73
|
+
* One collection, one owner per surface. This does NOT reintroduce the
|
|
74
|
+
* `siteSettings.homepageLayout` that `sectionTemplates.ts` deliberately refuses
|
|
75
|
+
* — that note forbids a SECOND owner of the homepage's layout, and this keeps
|
|
76
|
+
* `homepageSections` the single source of truth while letting a category or a
|
|
77
|
+
* brand page own its own ordered list.
|
|
78
|
+
*/
|
|
79
|
+
export const SECTION_SURFACE_VALUES = [
|
|
80
|
+
"homepage",
|
|
81
|
+
"category",
|
|
82
|
+
"brand",
|
|
83
|
+
"product",
|
|
84
|
+
"store",
|
|
85
|
+
];
|
|
86
|
+
/** Absent means `"homepage"`. See the field comment below. */
|
|
87
|
+
export const DEFAULT_SECTION_SURFACE = "homepage";
|
|
70
88
|
export const HOMEPAGE_SECTIONS_COLLECTION = "homepageSections";
|
|
71
89
|
export const HOMEPAGE_SECTIONS_INDEXED_FIELDS = [
|
|
72
90
|
"enabled",
|
|
@@ -99,6 +117,9 @@ export const DEFAULT_SECTION_ORDER = {
|
|
|
99
117
|
"prize-draws": 21,
|
|
100
118
|
"event-raffles": 22,
|
|
101
119
|
"collection-cards": 23,
|
|
120
|
+
"how-it-works": 24,
|
|
121
|
+
testimonials: 25,
|
|
122
|
+
"promo-grid": 26,
|
|
102
123
|
};
|
|
103
124
|
export const BANNER_HEIGHTS = {
|
|
104
125
|
sm: "200px",
|
|
@@ -110,6 +131,15 @@ export const homepageSectionQueryHelpers = {
|
|
|
110
131
|
enabled: () => ["enabled", "==", true],
|
|
111
132
|
byType: (type) => ["type", "==", type],
|
|
112
133
|
};
|
|
113
|
-
|
|
114
|
-
|
|
134
|
+
/**
|
|
135
|
+
* 🛑 The surface is part of the id, or a category's `products` section collides
|
|
136
|
+
* with the homepage's — same type, same generated slug, one document.
|
|
137
|
+
*
|
|
138
|
+
* `"homepage"` is omitted from the id so every existing row keeps the exact id
|
|
139
|
+
* it already has. A migration here would be a rename of 23 live documents to
|
|
140
|
+
* gain nothing.
|
|
141
|
+
*/
|
|
142
|
+
export function createHomepageSectionId(type, surface = DEFAULT_SECTION_SURFACE) {
|
|
143
|
+
const base = generateHomepageSectionId({ type });
|
|
144
|
+
return surface === DEFAULT_SECTION_SURFACE ? base : `${base}-${surface}`;
|
|
115
145
|
}
|
|
@@ -1,7 +1,32 @@
|
|
|
1
1
|
export * from "./firestore";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import type { SectionType } from "./firestore";
|
|
3
4
|
import type { JsonValue } from "../../../schemas/types";
|
|
4
|
-
|
|
5
|
+
/**
|
|
6
|
+
* 🛑 GENUINELY derived from `SectionType`, not a parallel hand-written list.
|
|
7
|
+
*
|
|
8
|
+
* This used to be a literal `z.enum([...25 strings...])`, with a docstring one
|
|
9
|
+
* screen up claiming it was "derived from the union, so that gap cannot
|
|
10
|
+
* reopen." It was not derived — it was a hand-typed duplicate that happened to
|
|
11
|
+
* agree with `SectionType` on the day it was written, with nothing enforcing
|
|
12
|
+
* that agreement afterward. Adding a 26th section type without also editing
|
|
13
|
+
* this array would 400 every save of the new type — exactly the failure the
|
|
14
|
+
* docstring claimed was already closed.
|
|
15
|
+
*
|
|
16
|
+
* `DEFAULT_SECTION_ORDER: Record<SectionType, number>` (`./firestore.ts`) is
|
|
17
|
+
* already compile-checked exhaustive over `SectionType` — TypeScript refuses
|
|
18
|
+
* to compile it if a union member is missing a key, or if an extra key exists
|
|
19
|
+
* that isn't in the union. So `Object.keys(DEFAULT_SECTION_ORDER)` IS the
|
|
20
|
+
* `SectionType` value set, genuinely, every time this file is built — adding
|
|
21
|
+
* a type to the union without updating `DEFAULT_SECTION_ORDER` is now a `tsc`
|
|
22
|
+
* error at THAT assignment, not a runtime 400 discovered on save.
|
|
23
|
+
*
|
|
24
|
+
* The cast is sound, not a loosening: `Object.keys` returns `string[]` only
|
|
25
|
+
* because that's TypeScript's (overly conservative) built-in signature for
|
|
26
|
+
* it — the compile-time guarantee from `DEFAULT_SECTION_ORDER`'s own type
|
|
27
|
+
* is what actually makes the runtime values correct.
|
|
28
|
+
*/
|
|
29
|
+
export declare const homepageSectionTypeSchema: z.ZodEnum<[SectionType, ...SectionType[]]>;
|
|
5
30
|
export declare const homepageSectionFirestoreSchema: z.ZodObject<{
|
|
6
31
|
createdAt: z.ZodUnion<[z.ZodDate, z.ZodString, z.ZodObject<{
|
|
7
32
|
toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
|
|
@@ -18,12 +43,12 @@ export declare const homepageSectionFirestoreSchema: z.ZodObject<{
|
|
|
18
43
|
toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
|
|
19
44
|
}, z.ZodTypeAny, "passthrough">>]>;
|
|
20
45
|
id: z.ZodString;
|
|
21
|
-
type: z.ZodEnum<[
|
|
46
|
+
type: z.ZodEnum<[SectionType, ...SectionType[]]>;
|
|
22
47
|
order: z.ZodNumber;
|
|
23
48
|
enabled: z.ZodBoolean;
|
|
24
49
|
config: z.ZodRecord<z.ZodString, z.ZodType<JsonValue, z.ZodTypeDef, JsonValue>>;
|
|
25
50
|
}, "strip", z.ZodTypeAny, {
|
|
26
|
-
type:
|
|
51
|
+
type: SectionType;
|
|
27
52
|
id: string;
|
|
28
53
|
createdAt: string | Date | z.objectOutputType<{
|
|
29
54
|
toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
|
|
@@ -35,7 +60,7 @@ export declare const homepageSectionFirestoreSchema: z.ZodObject<{
|
|
|
35
60
|
order: number;
|
|
36
61
|
config: Record<string, JsonValue>;
|
|
37
62
|
}, {
|
|
38
|
-
type:
|
|
63
|
+
type: SectionType;
|
|
39
64
|
id: string;
|
|
40
65
|
createdAt: string | Date | z.objectInputType<{
|
|
41
66
|
toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
|
|
@@ -61,19 +86,23 @@ export declare const homepageSectionFirestoreSchema: z.ZodObject<{
|
|
|
61
86
|
* `type` comes from `homepageSectionTypeSchema`, which is derived from the
|
|
62
87
|
* union, so that gap cannot reopen.
|
|
63
88
|
*/
|
|
89
|
+
export declare const sectionSurfaceSchema: z.ZodEnum<["homepage", "category", "brand", "product", "store"]>;
|
|
64
90
|
export declare const homepageSectionCreateSchema: z.ZodObject<{
|
|
65
|
-
type: z.ZodEnum<[
|
|
91
|
+
type: z.ZodEnum<[SectionType, ...SectionType[]]>;
|
|
66
92
|
enabled: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
67
93
|
order: z.ZodOptional<z.ZodNumber>;
|
|
94
|
+
surface: z.ZodOptional<z.ZodEnum<["homepage", "category", "brand", "product", "store"]>>;
|
|
68
95
|
config: z.ZodRecord<z.ZodString, z.ZodType<JsonValue, z.ZodTypeDef, JsonValue>>;
|
|
69
96
|
}, "strip", z.ZodTypeAny, {
|
|
70
|
-
type:
|
|
97
|
+
type: SectionType;
|
|
71
98
|
enabled: boolean;
|
|
72
99
|
config: Record<string, JsonValue>;
|
|
100
|
+
surface?: "brand" | "category" | "store" | "product" | "homepage" | undefined;
|
|
73
101
|
order?: number | undefined;
|
|
74
102
|
}, {
|
|
75
|
-
type:
|
|
103
|
+
type: SectionType;
|
|
76
104
|
config: Record<string, JsonValue>;
|
|
105
|
+
surface?: "brand" | "category" | "store" | "product" | "homepage" | undefined;
|
|
77
106
|
enabled?: boolean | undefined;
|
|
78
107
|
order?: number | undefined;
|
|
79
108
|
}>;
|
|
@@ -10,34 +10,33 @@ export * from "./firestore.js";
|
|
|
10
10
|
// Here the `config` field is treated as a typed `Record<string, JsonValue>` —
|
|
11
11
|
// the section-builder schemas validate it at the form boundary.
|
|
12
12
|
import { z } from "zod";
|
|
13
|
+
import { DEFAULT_SECTION_ORDER, SECTION_SURFACE_VALUES } from "./firestore.js";
|
|
13
14
|
import { auditTimestampsShape, firestoreDateSchema } from "../../../schemas/firestore-helpers.js";
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"collection-cards",
|
|
40
|
-
]);
|
|
15
|
+
/**
|
|
16
|
+
* 🛑 GENUINELY derived from `SectionType`, not a parallel hand-written list.
|
|
17
|
+
*
|
|
18
|
+
* This used to be a literal `z.enum([...25 strings...])`, with a docstring one
|
|
19
|
+
* screen up claiming it was "derived from the union, so that gap cannot
|
|
20
|
+
* reopen." It was not derived — it was a hand-typed duplicate that happened to
|
|
21
|
+
* agree with `SectionType` on the day it was written, with nothing enforcing
|
|
22
|
+
* that agreement afterward. Adding a 26th section type without also editing
|
|
23
|
+
* this array would 400 every save of the new type — exactly the failure the
|
|
24
|
+
* docstring claimed was already closed.
|
|
25
|
+
*
|
|
26
|
+
* `DEFAULT_SECTION_ORDER: Record<SectionType, number>` (`./firestore.ts`) is
|
|
27
|
+
* already compile-checked exhaustive over `SectionType` — TypeScript refuses
|
|
28
|
+
* to compile it if a union member is missing a key, or if an extra key exists
|
|
29
|
+
* that isn't in the union. So `Object.keys(DEFAULT_SECTION_ORDER)` IS the
|
|
30
|
+
* `SectionType` value set, genuinely, every time this file is built — adding
|
|
31
|
+
* a type to the union without updating `DEFAULT_SECTION_ORDER` is now a `tsc`
|
|
32
|
+
* error at THAT assignment, not a runtime 400 discovered on save.
|
|
33
|
+
*
|
|
34
|
+
* The cast is sound, not a loosening: `Object.keys` returns `string[]` only
|
|
35
|
+
* because that's TypeScript's (overly conservative) built-in signature for
|
|
36
|
+
* it — the compile-time guarantee from `DEFAULT_SECTION_ORDER`'s own type
|
|
37
|
+
* is what actually makes the runtime values correct.
|
|
38
|
+
*/
|
|
39
|
+
export const homepageSectionTypeSchema = z.enum(Object.keys(DEFAULT_SECTION_ORDER));
|
|
41
40
|
// JsonValue Zod — used for section configs whose shape varies per section type.
|
|
42
41
|
// The section-builder schemas (W5 row 1) provide the per-type validation.
|
|
43
42
|
const jsonValueSchema = z.lazy(() => z.union([
|
|
@@ -70,10 +69,23 @@ export const homepageSectionFirestoreSchema = z.object({
|
|
|
70
69
|
* `type` comes from `homepageSectionTypeSchema`, which is derived from the
|
|
71
70
|
* union, so that gap cannot reopen.
|
|
72
71
|
*/
|
|
72
|
+
/*
|
|
73
|
+
* 🛑 Derived from SECTION_SURFACE_VALUES, not restated as a literal list —
|
|
74
|
+
* same discipline `homepageSectionTypeSchema` above now follows too (fixed
|
|
75
|
+
* 2026-10-19; it used to be the hand-written duplicate this comment used to
|
|
76
|
+
* warn about, with nothing enforcing parity with `SectionType`).
|
|
77
|
+
*/
|
|
78
|
+
export const sectionSurfaceSchema = z.enum(SECTION_SURFACE_VALUES);
|
|
73
79
|
export const homepageSectionCreateSchema = z.object({
|
|
74
80
|
type: homepageSectionTypeSchema,
|
|
75
81
|
enabled: z.boolean().optional().default(true),
|
|
76
82
|
order: z.number().int().optional(),
|
|
83
|
+
/*
|
|
84
|
+
* A plain `z.object()` STRIPS unknown keys silently, so without this line a
|
|
85
|
+
* caller's `surface` vanishes between the request and the handler with no
|
|
86
|
+
* error anywhere — Root Cause #76. Absent still means "homepage".
|
|
87
|
+
*/
|
|
88
|
+
surface: sectionSurfaceSchema.optional(),
|
|
77
89
|
// Deliberately open. Every section type carries a different config shape,
|
|
78
90
|
// and a closed schema here would silently STRIP the builder's output for any
|
|
79
91
|
// type it did not enumerate — the `productBaseSchema` failure, one domain
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
export * from "./actions";
|
|
2
|
-
export { HomepageSectionsRepository } from "./repository/homepage.repository";
|
|
3
2
|
export { carouselRepository } from "./repository/carousel.repository";
|
|
4
3
|
export { homepageSectionsRepository } from "./repository/homepage-sections.repository";
|
|
5
4
|
export { manifest } from "./manifest";
|
|
6
|
-
export { GET as homepageGET, GET, POST } from "./api/route";
|
|
7
|
-
export { homepageSectionItemGET, homepageSectionItemPATCH, homepageSectionItemDELETE, } from "./api/[id]/route";
|
|
8
5
|
export { carouselGET, carouselPOST } from "./api/carousel/route";
|
|
9
6
|
export { carouselItemGET, carouselItemPATCH, carouselItemDELETE, } from "./api/carousel/[id]/route";
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
export * from "./actions/index.js";
|
|
2
|
-
export { HomepageSectionsRepository } from "./repository/homepage.repository.js";
|
|
3
2
|
export { carouselRepository } from "./repository/carousel.repository.js";
|
|
4
3
|
export { homepageSectionsRepository } from "./repository/homepage-sections.repository.js";
|
|
5
4
|
export { manifest } from "./manifest.js";
|
|
6
|
-
export { GET as homepageGET, GET, POST } from "./api/route.js";
|
|
7
|
-
export { homepageSectionItemGET, homepageSectionItemPATCH, homepageSectionItemDELETE, } from "./api/[id]/route.js";
|
|
8
5
|
export { carouselGET, carouselPOST } from "./api/carousel/route.js";
|
|
9
6
|
export { carouselItemGET, carouselItemPATCH, carouselItemDELETE, } from "./api/carousel/[id]/route.js";
|
|
@@ -1,31 +1,3 @@
|
|
|
1
|
-
export type HomepageSectionType = "hero" | "featured_categories" | "featured_products" | "banner" | "testimonials" | "promotions" | "blog_posts" | "sellers" | "custom";
|
|
2
|
-
export interface HomepageSectionContent {
|
|
3
|
-
title?: string;
|
|
4
|
-
subtitle?: string;
|
|
5
|
-
ctaLabel?: string;
|
|
6
|
-
ctaUrl?: string;
|
|
7
|
-
imageUrl?: string;
|
|
8
|
-
videoUrl?: string;
|
|
9
|
-
itemIds?: string[];
|
|
10
|
-
html?: string;
|
|
11
|
-
}
|
|
12
|
-
export interface HomepageSection {
|
|
13
|
-
id: string;
|
|
14
|
-
type: HomepageSectionType;
|
|
15
|
-
title?: string;
|
|
16
|
-
/** Primary enable/disable flag stored in Firestore as `enabled` */
|
|
17
|
-
enabled?: boolean;
|
|
18
|
-
/** Alias kept for older consumers */
|
|
19
|
-
isVisible?: boolean;
|
|
20
|
-
order?: number;
|
|
21
|
-
content?: HomepageSectionContent;
|
|
22
|
-
mobile?: Partial<HomepageSectionContent>;
|
|
23
|
-
createdAt?: string;
|
|
24
|
-
updatedAt?: string;
|
|
25
|
-
}
|
|
26
|
-
export interface HomepageData {
|
|
27
|
-
sections: HomepageSection[];
|
|
28
|
-
}
|
|
29
1
|
export interface HotspotPin {
|
|
30
2
|
id: string;
|
|
31
3
|
name: string;
|
|
@@ -62,15 +34,6 @@ export interface Banner {
|
|
|
62
34
|
sortOrder: number;
|
|
63
35
|
active: boolean;
|
|
64
36
|
}
|
|
65
|
-
export interface PromoBanner {
|
|
66
|
-
id: string;
|
|
67
|
-
title: string;
|
|
68
|
-
ctaLabel: string;
|
|
69
|
-
ctaUrl: string;
|
|
70
|
-
image: string;
|
|
71
|
-
sortOrder: number;
|
|
72
|
-
active: boolean;
|
|
73
|
-
}
|
|
74
37
|
export type TrustBadgeIconKey = "shipping" | "support" | "rewards" | "secure";
|
|
75
38
|
export interface TrustBadge {
|
|
76
39
|
id: string;
|
|
@@ -80,16 +43,6 @@ export interface TrustBadge {
|
|
|
80
43
|
sortOrder: number;
|
|
81
44
|
active: boolean;
|
|
82
45
|
}
|
|
83
|
-
export interface Testimonial {
|
|
84
|
-
id: string;
|
|
85
|
-
name: string;
|
|
86
|
-
rating: 1 | 2 | 3 | 4 | 5;
|
|
87
|
-
text: string;
|
|
88
|
-
avatarUrl?: string;
|
|
89
|
-
featured: boolean;
|
|
90
|
-
sortOrder: number;
|
|
91
|
-
active: boolean;
|
|
92
|
-
}
|
|
93
46
|
export interface BeforeAfterItem {
|
|
94
47
|
id: string;
|
|
95
48
|
beforeImage: string;
|
|
@@ -1 +1,50 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 🛑 DELETED 2026-10-19 — a second, incompatible section vocabulary, attached
|
|
3
|
+
* to LIVE, MOUNTED, publicly-reachable code.
|
|
4
|
+
*
|
|
5
|
+
* This file declared `HomepageSectionType` (9 values: `hero`,
|
|
6
|
+
* `featured_categories`, `featured_products`, `banner`, `testimonials`,
|
|
7
|
+
* `promotions`, `blog_posts`, `sellers`, `custom`), `HomepageSectionContent`,
|
|
8
|
+
* `HomepageSection` and `HomepageData`, against the live `SectionType` in
|
|
9
|
+
* `../schemas/firestore.ts`, which holds 25 values sharing exactly ONE
|
|
10
|
+
* (`banner`) with this union. A second, independently-declared copy of the
|
|
11
|
+
* same 9-value union lived in `seed/factories/homepage-section.factory.ts`
|
|
12
|
+
* too — THREE incompatible section vocabularies in one codebase, none of them
|
|
13
|
+
* the one the real renderer and repository use.
|
|
14
|
+
*
|
|
15
|
+
* This was not dead code sitting unused — `GET /api/homepage-sections` and
|
|
16
|
+
* `GET/POST /api/homepage-sections/[id]` were REAL, MOUNTED routes (stubs
|
|
17
|
+
* literally headed "feat-homepage — Pure stub", from a generic starter kit
|
|
18
|
+
* never adapted to this project) reading/writing the SAME `homepageSections`
|
|
19
|
+
* Firestore collection the real system owns, through a SECOND,
|
|
20
|
+
* identically-named `HomepageSectionsRepository` class (a generic
|
|
21
|
+
* `IRepository<HomepageSection>` wrapper in `repository/homepage.repository.ts`,
|
|
22
|
+
* distinct from the real `BaseRepository`-backed one in
|
|
23
|
+
* `homepage-sections.repository.ts`) — Root Cause #36's two-same-named-types
|
|
24
|
+
* defect, on a REPOSITORY CLASS this time, with a live route behind it.
|
|
25
|
+
*
|
|
26
|
+
* Concretely, before this deletion: the stub's GET filtered on `isVisible==true`,
|
|
27
|
+
* a field that does not exist on a real `HomepageSectionDocument` (the real
|
|
28
|
+
* field is `enabled`), so unauthenticated requests always got `[]`; its POST
|
|
29
|
+
* (admin-gated) would have written a document shaped `{ type: "hero", title,
|
|
30
|
+
* content: {...} }` into the collection the real renderer reads, where
|
|
31
|
+
* `SECTION_REGISTRY[section.type]` — see `../lib/section-renderer.tsx` — would
|
|
32
|
+
* resolve to `undefined` and render nothing, with no error anywhere: a
|
|
33
|
+
* corrupted, uneditable-through-the-real-admin-UI row, silently invisible.
|
|
34
|
+
*
|
|
35
|
+
* `useHomepage()` (the hook typed against `HomepageData`) fetched
|
|
36
|
+
* `HOMEPAGE_ENDPOINTS.GET = "/api/homepage"`, which was never mounted at all.
|
|
37
|
+
* `useHomepageSections()` called the stub above and had zero real callers —
|
|
38
|
+
* only a comment in `AdminSectionsView.tsx` mentioning it existed.
|
|
39
|
+
*
|
|
40
|
+
* All of it is deleted: the two hooks, the stub API routes (`api/route.ts`,
|
|
41
|
+
* `api/[id]/`, and a THIRD unused parallel stub at `api/sections/` for
|
|
42
|
+
* `/api/homepage/sections`), the stub repository class, `HeroSection.tsx`
|
|
43
|
+
* (zero real consumers), the seed factory, and the matching consumer-side
|
|
44
|
+
* `src/app/api/homepage-sections/{route.ts,[id]/route.ts}`.
|
|
45
|
+
*
|
|
46
|
+
* The live contract is `SectionType` / `SectionConfig` / `HomepageSectionDocument`
|
|
47
|
+
* in `../schemas/firestore.ts`, served by `GET /api/admin/sections` and read
|
|
48
|
+
* directly by `MarketplaceHomepageView` via `homepageSectionsRepository`.
|
|
49
|
+
*/
|
|
1
50
|
export {};
|
|
@@ -176,7 +176,7 @@ function SidebarContent({ sidebarItems, sidebarSections, sidebarPrimaryActions,
|
|
|
176
176
|
action.variant === "outline"
|
|
177
177
|
? "border hover:bg-surface-hover border-[var(--appkit-color-border)] text-[var(--appkit-color-text)]"
|
|
178
178
|
: "bg-primary text-white hover:bg-primary-600 dark:bg-primary dark:hover:bg-primary-600 btn-glow",
|
|
179
|
-
].join(" "), children: action.label }, `${action.href}-${action.label}`))) })), isAuthenticated && (_jsx(CollapsibleNavGroup, { title: labels.sectionTitle, hasActive: !!activeProfileLink, children: _jsxs(Ul, { spacing: "2xs", children: [_jsx(Li, { children: _jsx(TextLink, { href: profileHref, variant: "none", className: activeProfileLink?.href === profileHref ? navItemActiveClass : navItemClass, "aria-current": activeProfileLink?.href === profileHref ? "page" : undefined, children: labels.profile }) }), userOrdersHref && (_jsx(Li, { children: _jsx(TextLink, { href: userOrdersHref, variant: "none", className: activeProfileLink?.href === userOrdersHref ? navItemActiveClass : navItemClass, "aria-current": activeProfileLink?.href === userOrdersHref ? "page" : undefined, children: labels.orders }) })), userWishlistHref && (_jsx(Li, { children: _jsx(TextLink, { href: userWishlistHref, variant: "none", className: activeProfileLink?.href === userWishlistHref ? navItemActiveClass : navItemClass, "aria-current": activeProfileLink?.href === userWishlistHref ? "page" : undefined, children: labels.wishlist }) })), userSettingsHref && (_jsx(Li, { children: _jsx(TextLink, { href: userSettingsHref, variant: "none", className: activeProfileLink?.href === userSettingsHref ? navItemActiveClass : navItemClass, "aria-current": activeProfileLink?.href === userSettingsHref ? "page" : undefined, children: labels.settings }) }))] }) })), isAuthenticated && user?.stats && (_jsxs(Div, { layout: "grid", gap: "2", className: "grid-cols-2", children: [user.stats.totalOrders != null && (_jsxs(Div, { className: CLS_STAT_BOX, children: [_jsx(Text, { className: "leading-none", color: "primary", size: "lg", weight: "bold", children: user.stats.totalOrders }), _jsx(Text, { className: CLS_STAT_LABEL, children: "Orders" })] })), user.stats.reviewsCount != null && (_jsxs(Div, { className: CLS_STAT_BOX, children: [_jsx(Text, { className: "leading-none", color: "primary", size: "lg", weight: "bold", children: user.stats.reviewsCount }), _jsx(Text, { className: CLS_STAT_LABEL, children: "Reviews" })] })), user.stats.auctionsWon != null && (_jsxs(Div, { className: CLS_STAT_BOX, children: [_jsx(Text, { className: "leading-none", color: "primary", size: "lg", weight: "bold", children: user.stats.auctionsWon }), _jsx(Text, { className: CLS_STAT_LABEL, children: "Auctions Won" })] })), user.stats.itemsSold != null && (_jsxs(Div, { className: CLS_STAT_BOX, children: [_jsx(Text, { className: "leading-none", color: "primary", size: "lg", weight: "bold", children: user.stats.itemsSold }), _jsx(Text, { className: CLS_STAT_LABEL, children: "Items Sold" })] }))] })), isAuthenticated && isAdminOrSeller && (adminHref || resolvedStoreHref) && (_jsx(CollapsibleNavGroup, { title: labels.dashboardSectionTitle, hasActive: !!activeDashboardLink, children: _jsxs(Ul, { spacing: "2xs", children: [adminHref && role === "admin" && (_jsx(Li, { children: _jsx(TextLink, { href: adminHref, variant: "none", className: activeDashboardLink?.href === adminHref ? navItemActiveClass : navItemClass, "aria-current": activeDashboardLink?.href === adminHref ? "page" : undefined, children: labels.adminDashboard }) })), resolvedStoreHref && isAdminOrSeller && (_jsx(Li, { children: _jsx(TextLink, { href: resolvedStoreHref, variant: "none", className: activeDashboardLink?.href === resolvedStoreHref ? navItemActiveClass : navItemClass, "aria-current": activeDashboardLink?.href === resolvedStoreHref ? "page" : undefined, children: labels.storeDashboard }) }))] }) })), normalizedSections.map((section, sectionIndex) => (_jsx(CollapsibleSidebarSection, { section: section, navItemClass: navItemClass, navItemActiveClass: navItemActiveClass, activeHref: activeHref }, `sidebar-section-${sectionIndex}`))), (sidebarLocaleSlot || showThemeToggleInSidebar || (isAuthenticated && onLogout)) && (_jsxs(Stack, { border: "default", className: "border-t border-[var(--appkit-color-border-subtle)]", padding: "t-md", gap: "3", children: [sidebarLocaleSlot, showThemeToggleInSidebar && (_jsxs("button", { type: "button", onClick: toggleTheme, className: "flex w-full items-center justify-end gap-[var(--appkit-space-3)] rounded-lg px-[var(--appkit-space-3)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] text-[var(--appkit-color-text-muted)] transition-colors hover:bg-primary-surface hover:text-primary-800", children: [_jsx(Span, { "aria-hidden": "true", children: theme === "dark" ? "☀️" : "🌙" }), activeThemeName] })), isAuthenticated && onLogout && (_jsx("button", { type: "button", onClick: () => { onLogout(); onAfterLogout(); }, className: CLS_LOGOUT_BTN, children: labels.logout }))] }))] }));
|
|
179
|
+
].join(" "), children: action.label }, `${action.href}-${action.label}`))) })), isAuthenticated && (_jsx(CollapsibleNavGroup, { title: labels.sectionTitle, hasActive: !!activeProfileLink, children: _jsxs(Ul, { spacing: "2xs", children: [_jsx(Li, { children: _jsx(TextLink, { href: profileHref, variant: "none", className: activeProfileLink?.href === profileHref ? navItemActiveClass : navItemClass, "aria-current": activeProfileLink?.href === profileHref ? "page" : undefined, children: labels.profile }) }), userOrdersHref && (_jsx(Li, { children: _jsx(TextLink, { href: userOrdersHref, variant: "none", className: activeProfileLink?.href === userOrdersHref ? navItemActiveClass : navItemClass, "aria-current": activeProfileLink?.href === userOrdersHref ? "page" : undefined, children: labels.orders }) })), userWishlistHref && (_jsx(Li, { children: _jsx(TextLink, { href: userWishlistHref, variant: "none", className: activeProfileLink?.href === userWishlistHref ? navItemActiveClass : navItemClass, "aria-current": activeProfileLink?.href === userWishlistHref ? "page" : undefined, children: labels.wishlist }) })), userSettingsHref && (_jsx(Li, { children: _jsx(TextLink, { href: userSettingsHref, variant: "none", className: activeProfileLink?.href === userSettingsHref ? navItemActiveClass : navItemClass, "aria-current": activeProfileLink?.href === userSettingsHref ? "page" : undefined, children: labels.settings }) }))] }) })), isAuthenticated && user?.stats && (_jsxs(Div, { layout: "grid", gap: "2", className: "grid-cols-2", children: [user.stats.totalOrders != null && (_jsxs(Div, { className: CLS_STAT_BOX, children: [_jsx(Text, { className: "leading-none", color: "primary", size: "lg", weight: "bold", children: user.stats.totalOrders }), _jsx(Text, { className: CLS_STAT_LABEL, children: "Orders" })] })), user.stats.reviewsCount != null && (_jsxs(Div, { className: CLS_STAT_BOX, children: [_jsx(Text, { className: "leading-none", color: "primary", size: "lg", weight: "bold", children: user.stats.reviewsCount }), _jsx(Text, { className: CLS_STAT_LABEL, children: "Reviews" })] })), user.stats.auctionsWon != null && (_jsxs(Div, { className: CLS_STAT_BOX, children: [_jsx(Text, { className: "leading-none", color: "primary", size: "lg", weight: "bold", children: user.stats.auctionsWon }), _jsx(Text, { className: CLS_STAT_LABEL, children: "Auctions Won" })] })), user.stats.itemsSold != null && (_jsxs(Div, { className: CLS_STAT_BOX, children: [_jsx(Text, { className: "leading-none", color: "primary", size: "lg", weight: "bold", children: user.stats.itemsSold }), _jsx(Text, { className: CLS_STAT_LABEL, children: "Items Sold" })] }))] })), isAuthenticated && isAdminOrSeller && (adminHref || resolvedStoreHref) && (_jsx(CollapsibleNavGroup, { title: labels.dashboardSectionTitle, hasActive: !!activeDashboardLink, children: _jsxs(Ul, { spacing: "2xs", children: [adminHref && role === "admin" && (_jsx(Li, { children: _jsx(TextLink, { href: adminHref, variant: "none", className: activeDashboardLink?.href === adminHref ? navItemActiveClass : navItemClass, "aria-current": activeDashboardLink?.href === adminHref ? "page" : undefined, children: labels.adminDashboard }) })), resolvedStoreHref && isAdminOrSeller && (_jsx(Li, { children: _jsx(TextLink, { href: resolvedStoreHref, variant: "none", className: activeDashboardLink?.href === resolvedStoreHref ? navItemActiveClass : navItemClass, "aria-current": activeDashboardLink?.href === resolvedStoreHref ? "page" : undefined, children: labels.storeDashboard }) }))] }) })), normalizedSections.map((section, sectionIndex) => (_jsx(CollapsibleSidebarSection, { section: section, navItemClass: navItemClass, navItemActiveClass: navItemActiveClass, activeHref: activeHref }, `sidebar-section-${sectionIndex}`))), (sidebarLocaleSlot || showThemeToggleInSidebar || (isAuthenticated && onLogout)) && (_jsxs(Stack, { border: "default", className: "border-t border-[var(--appkit-color-border-subtle)]", padding: "t-md", gap: "3", children: [sidebarLocaleSlot, showThemeToggleInSidebar && (_jsxs("button", { type: "button", onClick: toggleTheme, className: "flex w-full items-center justify-end gap-[var(--appkit-space-3)] rounded-lg px-[var(--appkit-space-3)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] text-[var(--appkit-color-text-muted)] transition-colors hover:bg-primary-surface hover:text-primary-800 dark:hover:text-primary-200", children: [_jsx(Span, { "aria-hidden": "true", children: theme === "dark" ? "☀️" : "🌙" }), activeThemeName] })), isAuthenticated && onLogout && (_jsx("button", { type: "button", onClick: () => { onLogout(); onAfterLogout(); }, className: CLS_LOGOUT_BTN, children: labels.logout }))] }))] }));
|
|
180
180
|
}
|
|
181
181
|
// ─── Main component ────────────────────────────────────────────────────────────
|
|
182
182
|
export function AppLayoutShell({ children, navItems, sidebarItems = [], sidebarSections, sidebarPrimaryActions, sidebarTitle = "Navigation", hiddenNavItems, user, brandName, brandShortName, siteLogoUrl, logoHref, promotionsHref, cartHref, wishlistHref, messagesHref, unreadMessageCount, userId, profileHref, loginHref, registerHref, homeHref, shopHref, footer, searchSlot, searchSlotRenderer, titleBarNavSlot, titleBarNotificationSlot, titleBarDevSlot, titleBarPromoStripText, showThemeToggle = false, suppressDashboardNav = false, hideSidebarToggle = false, onLogout, adminHref, storeHref, sellerHref, userOrdersHref, userWishlistHref, userSettingsHref, sidebarLocaleSlot, showThemeToggleInSidebar = false, sidebarProfileLabels, eventBannerSlot, showBottomNav = true, contentClassName, lightBackground = DEFAULT_LIGHT_BG, darkBackground = DEFAULT_DARK_BG, }) {
|