@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
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: "Create your own bundle, with restrictions set by seller/admin" is the
|
|
3
|
+
* feature. The restrictions have TWO homes — a product group is identified
|
|
4
|
+
* by the parent product's slug, while a `groupedListing` is its own
|
|
5
|
+
* document — and the picker, the cart-add and the checkout re-validation
|
|
6
|
+
* all have to agree about them.
|
|
7
|
+
* WHAT: One shape, one resolver, one enforcer. Three readers, zero copies.
|
|
8
|
+
*
|
|
9
|
+
* 🛑 THE SAME RULES, FROM EITHER HOME. Resolving them at each call site is how
|
|
10
|
+
* a picker ends up permitting a selection the server then refuses (or worse,
|
|
11
|
+
* the reverse — a server-only rule reads as a broken button). `resolveGroupRules`
|
|
12
|
+
* is the only place the two homes are read, and `checkGroupRules` is the only
|
|
13
|
+
* place they are applied.
|
|
14
|
+
*
|
|
15
|
+
* 🛑 EVERY FIELD IS OPTIONAL AND ABSENT MEANS UNRESTRICTED. Every group that
|
|
16
|
+
* exists today has none of these, so a default that restricted anything would
|
|
17
|
+
* silently change what is buyable on live records.
|
|
18
|
+
*
|
|
19
|
+
* EXPORTS: GroupRules, GroupRuleSource, GroupRuleViolation, EMPTY_GROUP_RULES,
|
|
20
|
+
* readGroupRules, checkGroupRules, describeGroupRules
|
|
21
|
+
*
|
|
22
|
+
* @tag domain:products
|
|
23
|
+
* @tag layer:shared
|
|
24
|
+
* @tag pattern:none
|
|
25
|
+
* @tag access:isomorphic
|
|
26
|
+
* @tag consumers:GroupMemberPicker,cart-actions,checkout
|
|
27
|
+
* @tag sideEffects:none
|
|
28
|
+
*/
|
|
29
|
+
export const EMPTY_GROUP_RULES = {};
|
|
30
|
+
/**
|
|
31
|
+
* Read the rules off either home.
|
|
32
|
+
*
|
|
33
|
+
* Structurally typed on purpose: a product group's rules live on the PARENT
|
|
34
|
+
* product document and a grouped listing's on its own, and both are just
|
|
35
|
+
* objects carrying these optional keys. Taking `ProductDocument |
|
|
36
|
+
* GroupedListingDocument` here would drag two feature schemas into a shared
|
|
37
|
+
* module for no gain — and this module is imported by a client component.
|
|
38
|
+
*/
|
|
39
|
+
export function readGroupRules(doc) {
|
|
40
|
+
if (!doc)
|
|
41
|
+
return EMPTY_GROUP_RULES;
|
|
42
|
+
const out = {};
|
|
43
|
+
/*
|
|
44
|
+
* Copied field by field rather than spread. A spread of the whole parent
|
|
45
|
+
* PRODUCT document would carry ~90 unrelated fields into something named
|
|
46
|
+
* "rules", and the next reader would reasonably assume everything on it was
|
|
47
|
+
* a rule.
|
|
48
|
+
*/
|
|
49
|
+
if (typeof doc.groupMinMembers === "number")
|
|
50
|
+
out.groupMinMembers = doc.groupMinMembers;
|
|
51
|
+
if (typeof doc.groupMaxMembers === "number")
|
|
52
|
+
out.groupMaxMembers = doc.groupMaxMembers;
|
|
53
|
+
if (typeof doc.groupMaxUnitsPerMember === "number") {
|
|
54
|
+
out.groupMaxUnitsPerMember = doc.groupMaxUnitsPerMember;
|
|
55
|
+
}
|
|
56
|
+
if (Array.isArray(doc.groupRequiredMemberIds) && doc.groupRequiredMemberIds.length > 0) {
|
|
57
|
+
out.groupRequiredMemberIds = [...doc.groupRequiredMemberIds];
|
|
58
|
+
}
|
|
59
|
+
if (typeof doc.groupDiscountPercent === "number") {
|
|
60
|
+
out.groupDiscountPercent = doc.groupDiscountPercent;
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check a selection against the rules.
|
|
66
|
+
*
|
|
67
|
+
* Returns ALL violations rather than the first, because a picker shows them
|
|
68
|
+
* together and fixing one at a time is a worse experience than seeing the set.
|
|
69
|
+
* The server throws on the first; that is the caller's choice, not this
|
|
70
|
+
* function's.
|
|
71
|
+
*
|
|
72
|
+
* Entries at quantity 0 are ignored — the picker's stepper has `min={0}` and
|
|
73
|
+
* zero means "not chosen", so counting them would make an untouched member
|
|
74
|
+
* count toward `groupMinMembers`.
|
|
75
|
+
*/
|
|
76
|
+
export function checkGroupRules(rules, selection) {
|
|
77
|
+
const chosen = selection.filter((e) => e.quantity > 0);
|
|
78
|
+
const out = [];
|
|
79
|
+
if (rules.groupMinMembers !== undefined && chosen.length < rules.groupMinMembers) {
|
|
80
|
+
out.push({
|
|
81
|
+
code: "GROUP_TOO_FEW_MEMBERS",
|
|
82
|
+
message: `Pick at least ${rules.groupMinMembers} different item${rules.groupMinMembers === 1 ? "" : "s"} from this group — you have ${chosen.length}.`,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (rules.groupMaxMembers !== undefined && chosen.length > rules.groupMaxMembers) {
|
|
86
|
+
out.push({
|
|
87
|
+
code: "GROUP_TOO_MANY_MEMBERS",
|
|
88
|
+
message: `Pick at most ${rules.groupMaxMembers} different item${rules.groupMaxMembers === 1 ? "" : "s"} from this group — you have ${chosen.length}.`,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
if (rules.groupMaxUnitsPerMember !== undefined) {
|
|
92
|
+
for (const entry of chosen) {
|
|
93
|
+
if (entry.quantity > rules.groupMaxUnitsPerMember) {
|
|
94
|
+
out.push({
|
|
95
|
+
code: "GROUP_MEMBER_QTY_EXCEEDED",
|
|
96
|
+
message: `At most ${rules.groupMaxUnitsPerMember} of "${entry.title ?? entry.productId}" per order.`,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (rules.groupRequiredMemberIds) {
|
|
102
|
+
const present = new Set(chosen.map((e) => e.productId));
|
|
103
|
+
const missing = rules.groupRequiredMemberIds.filter((id) => !present.has(id));
|
|
104
|
+
if (missing.length > 0) {
|
|
105
|
+
/*
|
|
106
|
+
* Named by id when the caller has no title for it — which is the normal
|
|
107
|
+
* case, because a REQUIRED member the buyer has not chosen is not in
|
|
108
|
+
* their selection and so has no entry to read a title from. The picker
|
|
109
|
+
* passes titles it already has; the server does not have them and says
|
|
110
|
+
* so honestly rather than printing "undefined".
|
|
111
|
+
*/
|
|
112
|
+
const titles = missing.map((id) => selection.find((e) => e.productId === id)?.title ?? id);
|
|
113
|
+
out.push({
|
|
114
|
+
code: "GROUP_REQUIRED_MEMBER_MISSING",
|
|
115
|
+
message: `This group requires ${titles.join(", ")} to be included.`,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* The rules in words, for the picker's header.
|
|
123
|
+
*
|
|
124
|
+
* Returns an empty array when nothing is restricted, so the caller renders
|
|
125
|
+
* nothing rather than an empty box saying "Rules:".
|
|
126
|
+
*/
|
|
127
|
+
export function describeGroupRules(rules) {
|
|
128
|
+
const out = [];
|
|
129
|
+
if (rules.groupMinMembers !== undefined) {
|
|
130
|
+
out.push(`Pick at least ${rules.groupMinMembers}`);
|
|
131
|
+
}
|
|
132
|
+
if (rules.groupMaxMembers !== undefined) {
|
|
133
|
+
out.push(`Pick at most ${rules.groupMaxMembers}`);
|
|
134
|
+
}
|
|
135
|
+
if (rules.groupMaxUnitsPerMember !== undefined) {
|
|
136
|
+
out.push(`Max ${rules.groupMaxUnitsPerMember} of each`);
|
|
137
|
+
}
|
|
138
|
+
if (rules.groupDiscountPercent !== undefined && rules.groupDiscountPercent > 0) {
|
|
139
|
+
out.push(`${rules.groupDiscountPercent}% off the selection`);
|
|
140
|
+
}
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
@@ -108,6 +108,30 @@ export interface ListingTypePlugin {
|
|
|
108
108
|
* reachable only by typing the URL.
|
|
109
109
|
*/
|
|
110
110
|
inGeneralCatalogue: boolean;
|
|
111
|
+
/**
|
|
112
|
+
* May a listing of this type be a MEMBER of a product group?
|
|
113
|
+
*
|
|
114
|
+
* A product group is "a whole plus its parts, buy any mix" — a sticker sheet
|
|
115
|
+
* with its cut-out stickers, a complete Beyblade with its spares. The buyer
|
|
116
|
+
* picks quantities per member through `GroupMemberPicker`.
|
|
117
|
+
*
|
|
118
|
+
* 🛑 `findByGroupId` used to hard-code `["standard", "pre-order"]`, which
|
|
119
|
+
* made this field's answer invisible and wrong: a `stickers` or `art` member
|
|
120
|
+
* was silently dropped from the query, so `ShowGroupSection` saw one member
|
|
121
|
+
* and returned null — the picker was unreachable with nothing erroring. That
|
|
122
|
+
* is Root Cause #58's shape, a union member missing from the one allowlist
|
|
123
|
+
* that gates it.
|
|
124
|
+
*
|
|
125
|
+
* Required, not optional, for the same reason as `inGeneralCatalogue`: a
|
|
126
|
+
* tenth type must not compile until someone decides.
|
|
127
|
+
*
|
|
128
|
+
* False where the type's own pricing or lifecycle makes "pick N of these"
|
|
129
|
+
* meaningless — an auction is one unique lot, a pre-order is a deposit
|
|
130
|
+
* against a future release, a prize-draw sells entries, a classified has no
|
|
131
|
+
* cart, a digital-code is a fungible pool, and a live item is
|
|
132
|
+
* jurisdiction-gated per buyer.
|
|
133
|
+
*/
|
|
134
|
+
canJoinProductGroup: boolean;
|
|
111
135
|
/**
|
|
112
136
|
* Leading glyph for this type's chip, tab and dropdown row.
|
|
113
137
|
*
|
|
@@ -32,6 +32,8 @@ import * as live from "./live/config.js";
|
|
|
32
32
|
// EMI/art-stickers session — printed-only physical-goods types.
|
|
33
33
|
import * as art from "./art/config.js";
|
|
34
34
|
import * as stickers from "./stickers/config.js";
|
|
35
|
+
// Part Two 2026-10-19 — one component off a disassembled item, sold alone.
|
|
36
|
+
import * as spares from "./spares/config.js";
|
|
35
37
|
import { LISTING_TYPE_CAPABILITIES } from "./capabilities.js";
|
|
36
38
|
import { baseAvailable, } from "./availability.js";
|
|
37
39
|
import { AVAILABILITY_VALUES, } from "../../../constants/field-names.js";
|
|
@@ -48,9 +50,45 @@ export const LISTING_TYPE_REGISTRY = {
|
|
|
48
50
|
live: live.config,
|
|
49
51
|
art: art.config,
|
|
50
52
|
stickers: stickers.config,
|
|
53
|
+
spares: spares.config,
|
|
51
54
|
};
|
|
55
|
+
/*
|
|
56
|
+
* 🛑 TOTAL BY CONSTRUCTION — this was a bare index lookup and it crashed pages.
|
|
57
|
+
*
|
|
58
|
+
* The signature says `(type: ListingType) => ListingTypePlugin`, and for a
|
|
59
|
+
* value the compiler has actually checked that is true. But most callers get
|
|
60
|
+
* their `listingType` from a Firestore document, which crosses into the app
|
|
61
|
+
* as untyped data: a row written before a type existed, a row whose field was
|
|
62
|
+
* stripped by a `z.object()` schema, or a mapper that forgot to copy the
|
|
63
|
+
* field (Root Cause #48) all arrive as `undefined`. The lookup then returned
|
|
64
|
+
* `undefined` while TypeScript still believed it held a plugin, so the very
|
|
65
|
+
* next property access threw.
|
|
66
|
+
*
|
|
67
|
+
* Measured in production over 24h: 18 server-side crashes reading
|
|
68
|
+
* `.detailRoute` of undefined, across FIVE route families
|
|
69
|
+
* (`products/[slug]`, `classified/[slug]`, `pre-orders/[id]`,
|
|
70
|
+
* `digital-codes/[slug]`, `prize-draws/[slug]`), plus client-side copies of
|
|
71
|
+
* the same throw and one on `.badge` from `franchise/[slug]`. Each one is a
|
|
72
|
+
* whole detail page replaced by an error boundary.
|
|
73
|
+
*
|
|
74
|
+
* Falling back to `standard` is right because it is what the rest of the
|
|
75
|
+
* codebase ALREADY assumes: `normalizeListingType` is defined as
|
|
76
|
+
* `p.listingType ?? "standard"`, so a missing field is a standard listing
|
|
77
|
+
* everywhere else. Callers that pass through it were always safe; this makes
|
|
78
|
+
* the ones that do not safe as well.
|
|
79
|
+
*
|
|
80
|
+
* 🛑 It WARNS rather than falling back silently. A silent default is how a
|
|
81
|
+
* tenth listing type goes missing from the catalogue for weeks (Root Cause
|
|
82
|
+
* #58, where an unmapped alias returned "" and the filter simply vanished).
|
|
83
|
+
* The page renders; the gap is still reported.
|
|
84
|
+
*/
|
|
52
85
|
export function pluginFor(type) {
|
|
53
|
-
|
|
86
|
+
const plugin = LISTING_TYPE_REGISTRY[type];
|
|
87
|
+
if (plugin)
|
|
88
|
+
return plugin;
|
|
89
|
+
console.warn(`[listing-types] no plugin for listingType ${JSON.stringify(type)} — ` +
|
|
90
|
+
`falling back to "standard". Expected one of: ${Object.keys(LISTING_TYPE_REGISTRY).join(", ")}.`);
|
|
91
|
+
return LISTING_TYPE_REGISTRY.standard;
|
|
54
92
|
}
|
|
55
93
|
/**
|
|
56
94
|
* Infer a listing type from a product slug/id by matching its registered
|
|
@@ -22,6 +22,8 @@ export const config = {
|
|
|
22
22
|
browseRoute: String(ROUTES.PUBLIC.ART),
|
|
23
23
|
// /art ("Art & Stickers") is in MAIN_NAV_ITEMS and spans art + stickers.
|
|
24
24
|
inGeneralCatalogue: false,
|
|
25
|
+
// a print can be one of a set, and a sheet of art can be split
|
|
26
|
+
canJoinProductGroup: true,
|
|
25
27
|
iconKey: "art",
|
|
26
28
|
hideDefault: "sold",
|
|
27
29
|
// Runs out rather than ending — no time dimension, so the shared
|
|
@@ -22,6 +22,8 @@ export const config = {
|
|
|
22
22
|
// /auctions is in MAIN_NAV_ITEMS. An auction card in the general grid renders
|
|
23
23
|
// Buy-Now chrome rather than bid affordances, so it belongs on its own page.
|
|
24
24
|
inGeneralCatalogue: false,
|
|
25
|
+
// one unique lot, won by one bidder — there is no "pick 3 of these"
|
|
26
|
+
canJoinProductGroup: false,
|
|
25
27
|
iconKey: "bid",
|
|
26
28
|
// An auction is never "sold out" — it ends. Hiding by stock would hide
|
|
27
29
|
// every live auction, since auctions don't carry meaningful stock.
|
|
@@ -67,8 +67,32 @@ export function num(value) {
|
|
|
67
67
|
* and must not vanish from the default scope.
|
|
68
68
|
*/
|
|
69
69
|
export function baseAvailable(row) {
|
|
70
|
+
/*
|
|
71
|
+
* `isSold` stays the kill switch and is tested FIRST, ahead of the
|
|
72
|
+
* made-to-order bypass. A seller who marks a listing sold has made a
|
|
73
|
+
* statement about the listing, not about its stock level, and it must hold
|
|
74
|
+
* whatever the production model is — otherwise a made-to-order row could
|
|
75
|
+
* never be retired at all.
|
|
76
|
+
*/
|
|
70
77
|
if (row[PRODUCT_FIELDS.IS_SOLD] === true)
|
|
71
78
|
return false;
|
|
79
|
+
/*
|
|
80
|
+
* 🛑 Made to order: stock does not gate availability, so return before the
|
|
81
|
+
* two quantity checks.
|
|
82
|
+
*
|
|
83
|
+
* This ONE branch fixes `isListingRowAvailable`, the dense `available`
|
|
84
|
+
* scope, all three homepage `getFeatured*` helpers and related-items at
|
|
85
|
+
* once, because every one of them resolves to this function — which is the
|
|
86
|
+
* entire reason the four disagreeing copies were collapsed into it (Root
|
|
87
|
+
* Cause #73). It also correctly keeps a made-to-order row OUT of "Sold &
|
|
88
|
+
* Ended": that scope is the complement of this predicate.
|
|
89
|
+
*
|
|
90
|
+
* The counter-case is the point of the flag being per-listing: a finite
|
|
91
|
+
* spare at quantity 0 is genuinely gone and still falls through to the
|
|
92
|
+
* checks below.
|
|
93
|
+
*/
|
|
94
|
+
if (row[PRODUCT_FIELDS.MADE_TO_ORDER] === true)
|
|
95
|
+
return true;
|
|
72
96
|
const available = num(row[PRODUCT_FIELDS.AVAILABLE_QUANTITY]);
|
|
73
97
|
if (available !== null && available <= 0)
|
|
74
98
|
return false;
|
|
@@ -94,6 +118,30 @@ export const STOCK_ONLY_UNAVAILABLE_CLAUSES = [
|
|
|
94
118
|
{ field: PRODUCT_FIELDS.AVAILABLE_QUANTITY, op: "eq", value: 0 },
|
|
95
119
|
{ field: PRODUCT_FIELDS.IS_SOLD, op: "eq", value: true },
|
|
96
120
|
];
|
|
121
|
+
/*
|
|
122
|
+
* 🛑 WHY `madeToOrder` IS NOT A CLAUSE HERE, written down so nobody
|
|
123
|
+
* "optimises" it into a FAILED_PRECONDITION.
|
|
124
|
+
*
|
|
125
|
+
* A made-to-order row at quantity 0 still matches the first clause above, so it
|
|
126
|
+
* is fetched by the "Sold & Ended" query and then dropped in memory by
|
|
127
|
+
* `baseAvailable`. That is wasteful and it is CORRECT.
|
|
128
|
+
*
|
|
129
|
+
* The apparent fix — adding `madeToOrder != true` to narrow the query — cannot
|
|
130
|
+
* be expressed: `!=` is an INEQUALITY, so `UnavailableClause` would require it
|
|
131
|
+
* to name its own `sortField`, and Firestore implicitly appends an
|
|
132
|
+
* inequality's field to the `orderBy`. Pairing it with the scope's real sort
|
|
133
|
+
* demands a composite index in an order nobody declares (Root Cause #59), and
|
|
134
|
+
* every caller wraps the query in a guard that turns the failure into an empty
|
|
135
|
+
* page rather than an error.
|
|
136
|
+
*
|
|
137
|
+
* Worse, a Firestore inequality EXCLUDES every document that lacks the field —
|
|
138
|
+
* which is every product written before this flag existed, i.e. all of them.
|
|
139
|
+
* `madeToOrder != true` would return almost nothing. Same trap as the
|
|
140
|
+
* `isTestData` one CLAUDE.md documents.
|
|
141
|
+
*
|
|
142
|
+
* The in-memory drop is bounded by the page size, so the cost is a few rows
|
|
143
|
+
* read and discarded. Leave it.
|
|
144
|
+
*/
|
|
97
145
|
/**
|
|
98
146
|
* `isAvailable` for a type with no rule beyond `baseAvailable`. Named rather
|
|
99
147
|
* than an inline `() => true` so the five configs that use it read as
|
|
@@ -11,6 +11,25 @@
|
|
|
11
11
|
* inside the per-type folder (X2 plugin layout).
|
|
12
12
|
*/
|
|
13
13
|
export const LISTING_TYPE_CAPABILITIES = {
|
|
14
|
+
/*
|
|
15
|
+
* Standard physical-goods behaviour, with ONE deliberate difference:
|
|
16
|
+
* `canMakeOffer` is true.
|
|
17
|
+
*
|
|
18
|
+
* A loose part has no catalogue price — what a spare attack ring is worth
|
|
19
|
+
* depends on the colour, the wear and how badly the buyer needs that exact
|
|
20
|
+
* one. It is the archetypal haggled item here, which is the whole reason the
|
|
21
|
+
* seller is listing it instead of leaving it in a drawer, so the type that
|
|
22
|
+
* most needs Make-an-Offer is this one.
|
|
23
|
+
*/
|
|
24
|
+
spares: {
|
|
25
|
+
canAddToCart: true,
|
|
26
|
+
canBid: false,
|
|
27
|
+
supportsShipping: true,
|
|
28
|
+
requiresVendorVerified: false,
|
|
29
|
+
requiresJurisdictionCheck: false,
|
|
30
|
+
hasInstantFulfillment: false,
|
|
31
|
+
canMakeOffer: true,
|
|
32
|
+
},
|
|
14
33
|
standard: {
|
|
15
34
|
canAddToCart: true,
|
|
16
35
|
canBid: false,
|
|
@@ -21,6 +21,8 @@ export const config = {
|
|
|
21
21
|
// Has a dedicated page but NO MAIN_NAV_ITEMS entry, so /products is its only
|
|
22
22
|
// discovery path. Dropping it here would orphan the type (Root Cause #61).
|
|
23
23
|
inGeneralCatalogue: true,
|
|
24
|
+
// no cart at all (cartLine "blocked") — the purchase path is contact-seller
|
|
25
|
+
canJoinProductGroup: false,
|
|
24
26
|
iconKey: "deals",
|
|
25
27
|
hideDefault: "sold",
|
|
26
28
|
// Runs out rather than ending — no time dimension, so the shared
|
|
@@ -34,6 +34,8 @@ export const config = {
|
|
|
34
34
|
// Has a dedicated page but NO MAIN_NAV_ITEMS entry, so /products is its only
|
|
35
35
|
// discovery path. Dropping it here would orphan the type (Root Cause #61).
|
|
36
36
|
inGeneralCatalogue: true,
|
|
37
|
+
// a fungible pool item; "which 3 of these codes" is not a question a buyer has
|
|
38
|
+
canJoinProductGroup: false,
|
|
37
39
|
iconKey: "digitalCode",
|
|
38
40
|
// "Sold out" for a code pool means codesAvailable hit 0. That was ASSUMED to
|
|
39
41
|
// be mirrored by stockQuantity, and it isn't — seed and production rows exist
|
|
@@ -21,6 +21,8 @@ export const config = {
|
|
|
21
21
|
// Has a dedicated page but NO MAIN_NAV_ITEMS entry, so /products is its only
|
|
22
22
|
// discovery path. Dropping it here would orphan the type (Root Cause #61).
|
|
23
23
|
inGeneralCatalogue: true,
|
|
24
|
+
// jurisdiction-gated per buyer and vendor-verified — not mixable into a group line
|
|
25
|
+
canJoinProductGroup: false,
|
|
24
26
|
iconKey: "live",
|
|
25
27
|
hideDefault: "sold",
|
|
26
28
|
// Runs out rather than ending — no time dimension, so the shared
|
|
@@ -21,6 +21,8 @@ export const config = {
|
|
|
21
21
|
browseRoute: String(ROUTES.PUBLIC.PRE_ORDERS),
|
|
22
22
|
// /pre-orders is in MAIN_NAV_ITEMS.
|
|
23
23
|
inGeneralCatalogue: false,
|
|
24
|
+
// a deposit against a future release; members would ship at different times
|
|
25
|
+
canJoinProductGroup: false,
|
|
24
26
|
iconKey: "preOrder",
|
|
25
27
|
hideDefault: "closed",
|
|
26
28
|
// A pre-order closes when its allocation fills, NOT when its delivery date
|
|
@@ -21,6 +21,8 @@ export const config = {
|
|
|
21
21
|
// /prize-draws is in MAIN_NAV_ITEMS. Entry-based pricing reads wrong beside
|
|
22
22
|
// ordinary unit prices in the general grid.
|
|
23
23
|
inGeneralCatalogue: false,
|
|
24
|
+
// sells ENTRIES at a fixed price; a group line would blur what was entered
|
|
25
|
+
canJoinProductGroup: false,
|
|
24
26
|
iconKey: "prizeDraw",
|
|
25
27
|
hideDefault: "closed",
|
|
26
28
|
// `prizeRevealStatus`, NOT remaining entries: a draw can close with slots
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { alwaysAvailable } from "../availability";
|
|
2
|
+
export declare const LISTING_TYPE: "spares";
|
|
3
|
+
export declare const capability: import("../capabilities").ListingTypeCapability;
|
|
4
|
+
export declare const config: {
|
|
5
|
+
listingType: "spares";
|
|
6
|
+
slugPrefix: string;
|
|
7
|
+
cartLine: "single-product";
|
|
8
|
+
detailRoute: (idOrSlug: string) => string;
|
|
9
|
+
badge: {
|
|
10
|
+
label: string;
|
|
11
|
+
className: string;
|
|
12
|
+
};
|
|
13
|
+
priceLabel: string;
|
|
14
|
+
typeLabel: string;
|
|
15
|
+
showsStockQuantity: boolean;
|
|
16
|
+
tabSlug: string;
|
|
17
|
+
pluralLabel: string;
|
|
18
|
+
chipLabel: string;
|
|
19
|
+
browseRoute: string;
|
|
20
|
+
inGeneralCatalogue: boolean;
|
|
21
|
+
canJoinProductGroup: boolean;
|
|
22
|
+
iconKey: "spares";
|
|
23
|
+
hideDefault: "sold";
|
|
24
|
+
isAvailable: typeof alwaysAvailable;
|
|
25
|
+
unavailableClauses: readonly import("../availability").UnavailableClause[];
|
|
26
|
+
sortOptions: readonly [{
|
|
27
|
+
readonly value: string;
|
|
28
|
+
readonly label: "Newest First";
|
|
29
|
+
}, {
|
|
30
|
+
readonly value: string;
|
|
31
|
+
readonly label: "Oldest First";
|
|
32
|
+
}, {
|
|
33
|
+
readonly value: string;
|
|
34
|
+
readonly label: "Price: Low to High";
|
|
35
|
+
}, {
|
|
36
|
+
readonly value: string;
|
|
37
|
+
readonly label: "Price: High to Low";
|
|
38
|
+
}, {
|
|
39
|
+
readonly value: string;
|
|
40
|
+
readonly label: "Name: A–Z";
|
|
41
|
+
}, {
|
|
42
|
+
readonly value: string;
|
|
43
|
+
readonly label: "Name: Z–A";
|
|
44
|
+
}, {
|
|
45
|
+
readonly value: string;
|
|
46
|
+
readonly label: "Featured First";
|
|
47
|
+
}, {
|
|
48
|
+
readonly value: string;
|
|
49
|
+
readonly label: "Promoted First";
|
|
50
|
+
}, {
|
|
51
|
+
readonly value: string;
|
|
52
|
+
readonly label: "Recently Updated";
|
|
53
|
+
}];
|
|
54
|
+
publicSortOptions: readonly [{
|
|
55
|
+
readonly value: string;
|
|
56
|
+
readonly label: "Newest First";
|
|
57
|
+
}, {
|
|
58
|
+
readonly value: string;
|
|
59
|
+
readonly label: "Oldest First";
|
|
60
|
+
}, {
|
|
61
|
+
readonly value: string;
|
|
62
|
+
readonly label: "Price: Low to High";
|
|
63
|
+
}, {
|
|
64
|
+
readonly value: string;
|
|
65
|
+
readonly label: "Price: High to Low";
|
|
66
|
+
}, {
|
|
67
|
+
readonly value: string;
|
|
68
|
+
readonly label: "Name: A–Z";
|
|
69
|
+
}, {
|
|
70
|
+
readonly value: string;
|
|
71
|
+
readonly label: "Name: Z–A";
|
|
72
|
+
}];
|
|
73
|
+
extraFacetKeys: readonly string[];
|
|
74
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { LISTING_TYPE_CAPABILITIES } from "../capabilities.js";
|
|
2
|
+
import { alwaysAvailable, STOCK_ONLY_UNAVAILABLE_CLAUSES, } from "../availability.js";
|
|
3
|
+
import { ROUTES } from "../../../../next/routing/route-map.js";
|
|
4
|
+
import { STANDARD_SORT_OPTIONS, STANDARD_PUBLIC_SORT_OPTIONS, } from "../../../../features/products/constants/sieve.js";
|
|
5
|
+
export const LISTING_TYPE = "spares";
|
|
6
|
+
export const capability = LISTING_TYPE_CAPABILITIES.spares;
|
|
7
|
+
export const config = {
|
|
8
|
+
listingType: LISTING_TYPE,
|
|
9
|
+
/*
|
|
10
|
+
* Singular, matching `sticker-` rather than the plural type name.
|
|
11
|
+
*
|
|
12
|
+
* 🛑 Matched by `startsWith`, so this exact string must open every seeded id
|
|
13
|
+
* or `audit-seed-listing-type`'s R3 fails on every row — that audit calls the
|
|
14
|
+
* shipped `detectListingTypeFromSlug` rather than re-deriving the map, which
|
|
15
|
+
* is how it caught five `stickers-` ids against a registered `sticker-`.
|
|
16
|
+
*/
|
|
17
|
+
slugPrefix: "spare-",
|
|
18
|
+
cartLine: "single-product",
|
|
19
|
+
detailRoute: (idOrSlug) => String(ROUTES.PUBLIC.PRODUCT_DETAIL(idOrSlug)),
|
|
20
|
+
badge: { label: "Spare Part", className: "bg-primary-700 text-white" },
|
|
21
|
+
priceLabel: "Price (₹)",
|
|
22
|
+
typeLabel: "Spares",
|
|
23
|
+
showsStockQuantity: true,
|
|
24
|
+
tabSlug: "spares",
|
|
25
|
+
pluralLabel: "Spares",
|
|
26
|
+
chipLabel: "Spares",
|
|
27
|
+
browseRoute: String(ROUTES.PUBLIC.SPARES),
|
|
28
|
+
/*
|
|
29
|
+
* 🛑 `false`, and it obliges the nav entry that lands in the same change.
|
|
30
|
+
*
|
|
31
|
+
* The rule for this flag is nav reachability, not taste: a type kept out of
|
|
32
|
+
* the general catalogue must own a page that `MAIN_NAV_ITEMS` links, or it is
|
|
33
|
+
* reachable from nowhere (Root Cause #61). `/spares` is that page.
|
|
34
|
+
*
|
|
35
|
+
* The reason to keep it out is the catalogue itself. A seller who strips one
|
|
36
|
+
* Beyblade lists eight parts, so a few disassembled items would outnumber
|
|
37
|
+
* every complete listing on `/products` — and a buyer looking for a loose
|
|
38
|
+
* attack ring wants a page where everything is a loose part, not one where
|
|
39
|
+
* they are scattered among bundles and sealed boxes.
|
|
40
|
+
*/
|
|
41
|
+
inGeneralCatalogue: false,
|
|
42
|
+
/*
|
|
43
|
+
* A sheet-plus-parts group is the shape this exists for on the sticker side,
|
|
44
|
+
* and the same shape sells a stripped bey: the whole item as the parent, each
|
|
45
|
+
* salvaged part as a child, buyer takes any mix.
|
|
46
|
+
*/
|
|
47
|
+
canJoinProductGroup: true,
|
|
48
|
+
iconKey: "spares",
|
|
49
|
+
hideDefault: "sold",
|
|
50
|
+
/*
|
|
51
|
+
* A spare runs out rather than ending — there is no time dimension at all, so
|
|
52
|
+
* the shared stock-only rules are the whole story. Usually quantity 1: it is
|
|
53
|
+
* one physical object the seller happens to have.
|
|
54
|
+
*/
|
|
55
|
+
isAvailable: alwaysAvailable,
|
|
56
|
+
unavailableClauses: STOCK_ONLY_UNAVAILABLE_CLAUSES,
|
|
57
|
+
sortOptions: STANDARD_SORT_OPTIONS,
|
|
58
|
+
publicSortOptions: STANDARD_PUBLIC_SORT_OPTIONS,
|
|
59
|
+
extraFacetKeys: [],
|
|
60
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ctas: readonly string[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -19,6 +19,8 @@ export const config = {
|
|
|
19
19
|
browseRoute: String(ROUTES.PUBLIC.PRODUCTS),
|
|
20
20
|
// The general catalogue IS this type's page.
|
|
21
21
|
inGeneralCatalogue: true,
|
|
22
|
+
// the ordinary case — a complete item whose parts can be sold beside it
|
|
23
|
+
canJoinProductGroup: true,
|
|
22
24
|
iconKey: "order",
|
|
23
25
|
hideDefault: "sold",
|
|
24
26
|
// Runs out rather than ending — no time dimension, so the shared
|