@mohasinac/appkit 4.13.0 → 4.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_internal/client/features/layout/DashboardLayoutClient.js +14 -5
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.d.ts +3 -0
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +6 -0
- package/dist/_internal/client/features/lottery/LotteryDetailView.d.ts +8 -0
- package/dist/_internal/client/features/lottery/LotteryDetailView.js +4 -1
- package/dist/_internal/client/features/lottery/LotteryListView.d.ts +7 -0
- package/dist/_internal/client/features/lottery/LotteryListView.js +1 -1
- package/dist/_internal/client/features/lottery/PrizeDrawLotteryDetailView.js +4 -1
- package/dist/_internal/client/features/lottery/slot-collage-items.d.ts +15 -0
- package/dist/_internal/client/features/lottery/slot-collage-items.js +13 -0
- package/dist/_internal/server/features/auctions/actions.js +6 -0
- package/dist/_internal/server/features/bundles/data.d.ts +16 -0
- package/dist/_internal/server/features/bundles/data.js +26 -0
- package/dist/_internal/server/features/bundles/index.d.ts +1 -1
- package/dist/_internal/server/features/bundles/index.js +1 -1
- package/dist/_internal/server/features/checkout/actions.js +6 -0
- package/dist/_internal/server/features/checkout/locked-lines.d.ts +38 -0
- package/dist/_internal/server/features/checkout/locked-lines.js +171 -0
- package/dist/_internal/server/features/homepage/index.d.ts +0 -1
- package/dist/_internal/server/features/homepage/index.js +7 -1
- package/dist/_internal/server/features/lottery/adapters.js +4 -0
- package/dist/_internal/server/features/products/data.js +15 -37
- package/dist/_internal/server/features/products/index.d.ts +1 -1
- package/dist/_internal/server/features/products/index.js +1 -1
- package/dist/_internal/server/features/products/list-public.d.ts +46 -20
- package/dist/_internal/server/features/products/list-public.js +266 -90
- package/dist/_internal/server/features/products/listing-tab-counts.d.ts +44 -0
- package/dist/_internal/server/features/products/listing-tab-counts.js +97 -0
- package/dist/_internal/server/features/site-settings/adapters.d.ts +51 -0
- package/dist/_internal/server/features/site-settings/adapters.js +75 -0
- package/dist/_internal/server/features/site-settings/index.d.ts +1 -0
- package/dist/_internal/server/features/site-settings/index.js +1 -0
- package/dist/_internal/server/features/stores/adapters.d.ts +56 -0
- package/dist/_internal/server/features/stores/adapters.js +91 -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/jobs/core/auctionSettlement.js +56 -2
- package/dist/_internal/server/jobs/core/offerExpiry.js +45 -9
- package/dist/_internal/server/jobs/core/paymentReviewAutoApprove.d.ts +5 -0
- package/dist/_internal/server/jobs/core/paymentReviewAutoApprove.js +33 -1
- package/dist/_internal/server/jobs/handlers/messages.d.ts +7 -0
- package/dist/_internal/server/jobs/handlers/messages.js +10 -0
- package/dist/_internal/shared/actions/action-registry.js +15 -1
- package/dist/_internal/shared/checkout/lanes.d.ts +25 -0
- package/dist/_internal/shared/checkout/lanes.js +26 -0
- package/dist/_internal/shared/features/auctions/config.d.ts +27 -0
- package/dist/_internal/shared/features/auctions/config.js +27 -0
- package/dist/_internal/shared/features/blog/schema.d.ts +2 -2
- package/dist/_internal/shared/features/cart/schema.d.ts +12 -12
- package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +32 -32
- package/dist/_internal/shared/features/emi/schedule.d.ts +24 -3
- package/dist/_internal/shared/features/emi/schedule.js +20 -5
- package/dist/_internal/shared/features/events/schema.d.ts +2 -2
- package/dist/_internal/shared/features/homepage/section-gate.d.ts +14 -0
- package/dist/_internal/shared/features/homepage/section-gate.js +51 -0
- package/dist/_internal/shared/features/offers/config.d.ts +30 -0
- package/dist/_internal/shared/features/offers/config.js +59 -0
- package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
- package/dist/_internal/shared/features/products/schema.d.ts +32 -32
- package/dist/_internal/shared/features/products/to-product-item.js +6 -0
- package/dist/_internal/shared/features/reviews/schema.d.ts +2 -2
- package/dist/_internal/shared/features/site-settings/fees.d.ts +60 -0
- package/dist/_internal/shared/features/site-settings/fees.js +39 -0
- package/dist/_internal/shared/features/site-settings/types.d.ts +40 -0
- package/dist/_internal/shared/features/site-settings/types.js +1 -0
- package/dist/_internal/shared/history/history.d.ts +66 -0
- package/dist/_internal/shared/history/history.js +158 -0
- package/dist/_internal/shared/history/index.d.ts +4 -0
- package/dist/_internal/shared/history/index.js +2 -0
- package/dist/_internal/shared/history/types.d.ts +61 -0
- package/dist/_internal/shared/history/types.js +6 -0
- package/dist/_internal/shared/listing-types/_registry.d.ts +54 -1
- package/dist/_internal/shared/listing-types/_registry.js +67 -0
- package/dist/_internal/shared/listing-types/art/config.d.ts +3 -0
- package/dist/_internal/shared/listing-types/art/config.js +5 -0
- package/dist/_internal/shared/listing-types/auction/config.d.ts +13 -0
- package/dist/_internal/shared/listing-types/auction/config.js +21 -0
- package/dist/_internal/shared/listing-types/availability.d.ts +79 -0
- package/dist/_internal/shared/listing-types/availability.js +104 -0
- package/dist/_internal/shared/listing-types/capabilities.d.ts +15 -0
- package/dist/_internal/shared/listing-types/capabilities.js +12 -0
- package/dist/_internal/shared/listing-types/classified/config.d.ts +3 -0
- package/dist/_internal/shared/listing-types/classified/config.js +5 -0
- package/dist/_internal/shared/listing-types/digital-code/config.d.ts +11 -0
- package/dist/_internal/shared/listing-types/digital-code/config.js +22 -2
- package/dist/_internal/shared/listing-types/live/config.d.ts +3 -0
- package/dist/_internal/shared/listing-types/live/config.js +5 -0
- package/dist/_internal/shared/listing-types/pre-order/config.d.ts +3 -0
- package/dist/_internal/shared/listing-types/pre-order/config.js +19 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +11 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.js +15 -0
- package/dist/_internal/shared/listing-types/standard/config.d.ts +3 -0
- package/dist/_internal/shared/listing-types/standard/config.js +5 -0
- package/dist/_internal/shared/listing-types/stickers/config.d.ts +3 -0
- package/dist/_internal/shared/listing-types/stickers/config.js +5 -0
- package/dist/client.d.ts +7 -5
- package/dist/client.js +2 -2
- package/dist/constants/api-endpoints.d.ts +6 -0
- package/dist/constants/api-endpoints.js +2 -0
- package/dist/constants/field-names.d.ts +49 -2
- package/dist/constants/field-names.js +53 -2
- package/dist/constants/table-keys.d.ts +17 -0
- package/dist/constants/table-keys.js +17 -0
- package/dist/errors/error-codes.d.ts +13 -1
- package/dist/errors/error-codes.js +13 -1
- package/dist/errors/error-display-map.js +12 -3
- package/dist/errors/messages.d.ts +10 -2
- package/dist/errors/messages.js +10 -2
- package/dist/features/about/components/AboutView.d.ts +3 -0
- package/dist/features/about/components/AboutView.js +3 -2
- package/dist/features/about/components/PolicyPageView.d.ts +2 -1
- package/dist/features/about/components/PolicyPageView.js +61 -23
- package/dist/features/about/components/PublicProfileView.js +5 -0
- package/dist/features/about/schemas/firestore.d.ts +3 -0
- package/dist/features/account/components/UserOrdersView.js +7 -0
- package/dist/features/account/components/index.d.ts +0 -2
- package/dist/features/account/components/index.js +0 -1
- package/dist/features/account/schemas/index.d.ts +2 -2
- package/dist/features/account/types/index.d.ts +21 -2
- package/dist/features/addresses/schemas/index.d.ts +4 -4
- package/dist/features/admin/components/AdminArtView.js +8 -3
- package/dist/features/admin/components/AdminClassifiedView.js +8 -3
- package/dist/features/admin/components/AdminDigitalCodesView.js +8 -3
- package/dist/features/admin/components/AdminFeatureFlagsView.js +1 -0
- package/dist/features/admin/components/AdminLiveView.js +8 -3
- package/dist/features/admin/components/AdminOffersView.d.ts +4 -0
- package/dist/features/admin/components/AdminOffersView.js +186 -0
- package/dist/features/admin/components/AdminOrdersView.js +10 -1
- package/dist/features/admin/components/AdminPrizeDrawsView.js +5 -0
- package/dist/features/admin/components/AdminProductsView.js +16 -29
- package/dist/features/admin/components/AdminSiteSettingsView.js +31 -13
- package/dist/features/admin/components/AdminSiteView.js +6 -2
- package/dist/features/admin/components/AdminStickersView.js +8 -3
- package/dist/features/admin/components/index.d.ts +2 -0
- package/dist/features/admin/components/index.js +1 -0
- package/dist/features/admin/constants/filter-tabs.d.ts +86 -0
- package/dist/features/admin/constants/filter-tabs.js +55 -0
- package/dist/features/admin/schemas/firestore.d.ts +122 -3
- package/dist/features/admin/schemas/firestore.js +1 -0
- package/dist/features/auctions/actions/bid-actions.d.ts +20 -5
- package/dist/features/auctions/actions/bid-actions.js +93 -20
- package/dist/features/auctions/components/AuctionDetailPageView.js +11 -6
- package/dist/features/auctions/components/AuctionsListView.js +5 -6
- package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +7 -0
- package/dist/features/auctions/components/MarketplaceAuctionCard.js +19 -2
- package/dist/features/auctions/components/PlaceBidFormClient.d.ts +1 -2
- package/dist/features/auctions/components/PlaceBidFormClient.js +8 -4
- package/dist/features/auctions/repository/bid.repository.d.ts +13 -0
- package/dist/features/auctions/repository/bid.repository.js +23 -0
- package/dist/features/auctions/schemas/firestore.d.ts +17 -0
- package/dist/features/auctions/schemas/index.d.ts +12 -12
- package/dist/features/auth/permissions/constants.d.ts +1 -1
- package/dist/features/auth/permissions/constants.js +10 -1
- package/dist/features/blog/actions/blog-actions.d.ts +7 -7
- package/dist/features/blog/schemas/index.d.ts +6 -6
- package/dist/features/cart/repository/cart.repository.js +1 -0
- package/dist/features/cart/schemas/firestore.d.ts +15 -0
- package/dist/features/catalogue/schemas/validation.d.ts +4 -4
- package/dist/features/categories/components/BrandDetailPageView.js +23 -40
- package/dist/features/categories/components/BrandDetailTabs.d.ts +7 -7
- package/dist/features/categories/components/BrandDetailTabs.js +8 -12
- package/dist/features/categories/components/BundleCollage.js +1 -1
- package/dist/features/categories/components/CategoryDetailPageView.js +53 -57
- package/dist/features/categories/components/CategoryDetailTabs.d.ts +10 -8
- package/dist/features/categories/components/CategoryDetailTabs.js +11 -16
- package/dist/features/categories/components/CategoryProductsListing.js +11 -1
- package/dist/features/categories/components/ConcernCard.js +7 -1
- package/dist/features/categories/schemas/firestore.d.ts +13 -0
- package/dist/features/categories/schemas/index.d.ts +26 -26
- package/dist/features/classified/components/ClassifiedDetailPageView.d.ts +16 -1
- package/dist/features/classified/components/ClassifiedDetailPageView.js +23 -3
- package/dist/features/events/components/AdminEventsView.js +15 -11
- package/dist/features/events/components/EventFilters.d.ts +9 -1
- package/dist/features/events/components/EventFilters.js +45 -21
- package/dist/features/events/components/EventsIndexListing.d.ts +6 -1
- package/dist/features/events/components/EventsIndexListing.js +2 -2
- package/dist/features/events/components/EventsListPageView.js +13 -4
- package/dist/features/events/repository/events.repository.d.ts +17 -0
- package/dist/features/events/repository/events.repository.js +27 -0
- package/dist/features/events/schemas/firestore.d.ts +12 -0
- package/dist/features/events/schemas/firestore.js +12 -0
- package/dist/features/events/schemas/index.d.ts +50 -50
- package/dist/features/events/types/index.d.ts +11 -0
- package/dist/features/events/types/index.js +57 -1
- package/dist/features/faq/actions/faq-actions.d.ts +12 -12
- package/dist/features/faq/schemas/index.d.ts +8 -8
- package/dist/features/filters/FilterFacetSection.d.ts +7 -1
- package/dist/features/filters/FilterFacetSection.js +11 -3
- package/dist/features/grouped/schemas/index.d.ts +4 -4
- package/dist/features/homepage/components/AnnouncementBar.d.ts +7 -1
- package/dist/features/homepage/components/AnnouncementBar.js +3 -3
- package/dist/features/homepage/components/MarketplaceHomepageView.js +20 -6
- package/dist/features/homepage/hooks/homepage-query.d.ts +16 -0
- package/dist/features/homepage/hooks/homepage-query.js +45 -0
- package/dist/features/homepage/hooks/useFeaturedAuctions.d.ts +10 -0
- package/dist/features/homepage/hooks/useFeaturedAuctions.js +28 -8
- package/dist/features/homepage/hooks/useFeaturedPreOrders.js +17 -8
- package/dist/features/homepage/hooks/useFeaturedProducts.js +15 -8
- package/dist/features/homepage/schemas/index.d.ts +2 -2
- package/dist/features/layout/AppLayoutShell.d.ts +11 -1
- package/dist/features/layout/AppLayoutShell.js +15 -14
- package/dist/features/layout/BackToTop.d.ts +9 -0
- package/dist/features/layout/BackToTop.js +10 -1
- package/dist/features/layout/BottomActions.js +28 -25
- package/dist/features/layout/BottomChrome.d.ts +34 -0
- package/dist/features/layout/BottomChrome.js +55 -0
- package/dist/features/layout/BottomNavLayout.d.ts +6 -0
- package/dist/features/layout/BottomNavLayout.js +7 -1
- package/dist/features/layout/BottomNavbar.js +15 -2
- package/dist/features/layout/FooterLayout.js +11 -1
- package/dist/features/layout/NavbarLayout.js +1 -1
- package/dist/features/layout/TitleBarLayout.d.ts +7 -0
- package/dist/features/layout/TitleBarLayout.js +28 -5
- package/dist/features/layout/index.d.ts +2 -0
- package/dist/features/layout/index.js +1 -0
- package/dist/features/lottery/types/index.d.ts +3 -0
- package/dist/features/media/MediaPickerModal.js +5 -1
- package/dist/features/messages/schemas/index.d.ts +2 -2
- package/dist/features/orders/components/OrderScopeTabs.d.ts +20 -0
- package/dist/features/orders/components/OrderScopeTabs.js +31 -0
- package/dist/features/orders/constants/order-scope.d.ts +48 -0
- package/dist/features/orders/constants/order-scope.js +111 -0
- package/dist/features/orders/repository/orders.repository.d.ts +54 -7
- package/dist/features/orders/repository/orders.repository.js +116 -22
- package/dist/features/orders/schemas/firestore.d.ts +117 -0
- package/dist/features/orders/schemas/firestore.js +30 -0
- package/dist/features/orders/schemas/index.d.ts +18 -18
- package/dist/features/pre-orders/components/PreOrdersIndexListing.js +14 -9
- package/dist/features/pre-orders/components/PreOrdersListView.js +6 -5
- package/dist/features/pre-orders/schemas/index.d.ts +1 -1
- package/dist/features/products/actions/product-actions.d.ts +14 -0
- package/dist/features/products/actions/product-actions.js +49 -11
- package/dist/features/products/api/route.d.ts +12 -0
- package/dist/features/products/api/route.js +42 -100
- package/dist/features/products/components/ArtStickersListView.js +2 -2
- package/dist/features/products/components/AuctionsIndexListing.js +13 -11
- package/dist/features/products/components/AvailabilityTabs.d.ts +11 -0
- package/dist/features/products/components/AvailabilityTabs.js +47 -0
- package/dist/features/products/components/MakeOfferButton.js +48 -49
- package/dist/features/products/components/PrizeDrawCollage.d.ts +20 -4
- package/dist/features/products/components/PrizeDrawCollage.js +9 -1
- package/dist/features/products/components/PrizeDrawsIndexListing.js +14 -12
- package/dist/features/products/components/PrizeDrawsListingView.js +2 -2
- package/dist/features/products/components/PrizeDrawsSection.d.ts +7 -1
- package/dist/features/products/components/PrizeDrawsSection.js +23 -18
- package/dist/features/products/components/ProductDetailPageView.d.ts +4 -1
- package/dist/features/products/components/ProductDetailPageView.js +18 -4
- package/dist/features/products/components/ProductForm.js +5 -2
- package/dist/features/products/components/ProductGrid.js +6 -1
- package/dist/features/products/components/ProductsIndexListing.js +22 -32
- package/dist/features/products/components/ProductsIndexPageView.js +6 -9
- package/dist/features/products/components/index.d.ts +2 -2
- package/dist/features/products/components/index.js +1 -1
- package/dist/features/products/config/listing-type-listing-config.d.ts +20 -0
- package/dist/features/products/config/listing-type-listing-config.js +22 -10
- package/dist/features/products/constants/action-defs.d.ts +2 -0
- package/dist/features/products/constants/action-defs.js +6 -0
- package/dist/features/products/hooks/useAvailabilityScope.d.ts +13 -0
- package/dist/features/products/hooks/useAvailabilityScope.js +19 -0
- package/dist/features/products/hooks/useProducts.d.ts +5 -0
- package/dist/features/products/hooks/useProducts.js +13 -2
- package/dist/features/products/repository/products.repository.d.ts +31 -2
- package/dist/features/products/repository/products.repository.js +53 -21
- package/dist/features/products/schemas/firestore.d.ts +17 -3
- package/dist/features/products/schemas/firestore.js +7 -2
- package/dist/features/products/schemas/index.d.ts +66 -66
- package/dist/features/products/schemas/product-features.validators.d.ts +6 -6
- package/dist/features/products/types/index.d.ts +16 -1
- package/dist/features/promotions/schemas/index.d.ts +2 -2
- package/dist/features/reviews/schemas/index.d.ts +16 -16
- package/dist/features/search/schemas/index.d.ts +4 -4
- package/dist/features/seller/actions/offer-actions.js +25 -2
- package/dist/features/seller/components/SellerArtView.js +5 -0
- package/dist/features/seller/components/SellerAuctionsView.js +13 -15
- package/dist/features/seller/components/SellerClassifiedView.js +5 -0
- package/dist/features/seller/components/SellerDigitalCodesView.js +5 -0
- package/dist/features/seller/components/SellerLiveView.js +5 -0
- package/dist/features/seller/components/SellerOrdersView.js +31 -9
- package/dist/features/seller/components/SellerPayoutSettingsView.js +19 -18
- package/dist/features/seller/components/SellerPreOrdersView.js +5 -0
- package/dist/features/seller/components/SellerPrizeDrawsView.js +14 -16
- package/dist/features/seller/components/SellerProductShell.js +7 -1
- package/dist/features/seller/components/SellerProductsView.js +11 -8
- package/dist/features/seller/components/SellerStickersView.js +5 -0
- package/dist/features/seller/components/index.d.ts +0 -2
- package/dist/features/seller/components/index.js +0 -1
- package/dist/features/seller/repository/offer.repository.d.ts +73 -16
- package/dist/features/seller/repository/offer.repository.js +38 -3
- package/dist/features/seller/schemas/index.d.ts +2 -2
- package/dist/features/seller/schemas/offer-forms.d.ts +25 -0
- package/dist/features/seller/schemas/offer-forms.js +21 -0
- package/dist/features/seller/server.d.ts +0 -1
- package/dist/features/seller/server.js +0 -1
- package/dist/features/shell/SectionForm.d.ts +99 -0
- package/dist/features/shell/SectionForm.js +128 -0
- package/dist/features/shell/entity-form.d.ts +109 -0
- package/dist/features/shell/entity-form.js +96 -0
- package/dist/features/shell/index.d.ts +4 -0
- package/dist/features/shell/index.js +2 -0
- package/dist/features/stores/api/[storeSlug]/route.js +2 -25
- package/dist/features/stores/components/StoreAuctionsListing.js +15 -1
- package/dist/features/stores/components/StoreClassifiedsListing.js +12 -2
- package/dist/features/stores/components/StoreDetailLayoutView.js +24 -71
- package/dist/features/stores/components/StoreDigitalCodesListing.js +12 -2
- package/dist/features/stores/components/StoreLiveItemsListing.js +12 -2
- package/dist/features/stores/components/StorePreOrdersListing.js +12 -1
- package/dist/features/stores/components/StoreProductsListing.js +11 -1
- package/dist/features/stores/repository/store.repository.js +6 -0
- package/dist/features/stores/schemas/index.d.ts +6 -6
- package/dist/features/support/schemas/index.d.ts +4 -4
- package/dist/features/tester/actions/checklist-item-actions.d.ts +4 -4
- package/dist/features/tester/seed-data/offers-tester-seed-data.js +119 -3
- package/dist/features/tester/seed-data/products-tester-seed-data.js +131 -1
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +105 -1
- package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
- package/dist/index.d.ts +13 -10
- package/dist/index.js +14 -9
- package/dist/next/routing/route-map.d.ts +7 -1
- package/dist/next/routing/route-map.js +5 -0
- package/dist/providers/db-firebase/base.repository.d.ts +30 -0
- package/dist/providers/db-firebase/base.repository.js +50 -1
- package/dist/providers/db-firebase/index.d.ts +1 -1
- package/dist/providers/db-firebase/index.js +1 -1
- package/dist/providers/db-firebase/sieve.d.ts +25 -0
- package/dist/providers/db-firebase/sieve.js +52 -18
- package/dist/react/hooks/useUrlTable.js +10 -1
- package/dist/schemas/registry.d.ts +68 -68
- package/dist/seed/_helpers/category-forest.d.ts +2 -0
- package/dist/seed/_helpers/category-forest.js +309 -0
- package/dist/seed/_helpers/category-tree.d.ts +27 -0
- package/dist/seed/_helpers/category-tree.js +103 -0
- package/dist/seed/catalogue-seed-data.js +12 -12
- package/dist/seed/categories-seed-data.js +177 -162
- package/dist/seed/events-seed-data.js +61 -10
- package/dist/seed/homepage-sections-seed-data.js +5 -1
- package/dist/seed/offers-seed-data.js +32 -27
- package/dist/seed/products-art-seed-data.js +50 -12
- package/dist/seed/products-auctions-seed-data.js +97 -18
- package/dist/seed/products-classifieds-seed-data.js +80 -16
- package/dist/seed/products-digital-codes-seed-data.js +66 -18
- package/dist/seed/products-live-items-seed-data.js +64 -13
- package/dist/seed/products-preorders-seed-data.d.ts +0 -1
- package/dist/seed/products-preorders-seed-data.js +52 -13
- package/dist/seed/products-prize-draws-seed-data.js +63 -14
- package/dist/seed/products-standard-seed-data.js +99 -26
- package/dist/seed/products-stickers-seed-data.js +47 -12
- package/dist/seed/reviews-seed-data.js +6 -1
- package/dist/seed/site-settings-seed-data.d.ts +1 -38
- package/dist/seed/site-settings-seed-data.js +38 -76
- package/dist/seed/stores-seed-data.js +71 -1
- package/dist/seed/users-seed-data.js +15 -5
- package/dist/server-entry.d.ts +1 -2
- package/dist/server-entry.js +4 -3
- package/dist/server.d.ts +4 -3
- package/dist/server.js +8 -4
- package/dist/styles.css +78 -12
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/Button.style.css +19 -4
- package/dist/ui/components/CollapsibleSection.d.ts +17 -1
- package/dist/ui/components/CollapsibleSection.js +6 -2
- package/dist/ui/components/FilterChipGroup.d.ts +25 -1
- package/dist/ui/components/FilterChipGroup.js +21 -4
- package/dist/ui/components/HandMode.style.css +47 -0
- package/dist/ui/components/Layout.d.ts +9 -2
- package/dist/ui/components/Layout.js +1 -1
- package/dist/ui/components/ListingLayout.js +8 -8
- package/dist/ui/components/ListingLayout.style.css +8 -7
- package/dist/ui/components/StickyToolbar.d.ts +3 -1
- package/dist/ui/components/StickyToolbar.js +62 -20
- package/dist/ui/components/bottom-chrome-slot.d.ts +21 -0
- package/dist/ui/components/bottom-chrome-slot.js +29 -0
- package/dist/ui/components/index.style.css +3 -0
- package/dist/ui/forms/FormShell.d.ts +43 -13
- package/dist/ui/forms/FormShell.js +22 -11
- package/dist/ui/forms/index.d.ts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/** `"storeName"` / `"store_name"` / `"store.name"` -> `"Store name"`. */
|
|
2
|
+
export function humaniseFieldName(name) {
|
|
3
|
+
const leaf = name.includes(".") ? name.slice(name.lastIndexOf(".") + 1) : name;
|
|
4
|
+
const spaced = leaf
|
|
5
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
6
|
+
.replace(/[_-]+/g, " ")
|
|
7
|
+
.trim();
|
|
8
|
+
return spaced.charAt(0).toUpperCase() + spaced.slice(1);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The quick-mode field set: every field owned by a `quick: true` section,
|
|
12
|
+
* minus anything `derive()` produces.
|
|
13
|
+
*
|
|
14
|
+
* Derived, never declared — so quick and full modes cannot drift apart.
|
|
15
|
+
*/
|
|
16
|
+
export function deriveQuickFieldNames(def) {
|
|
17
|
+
const derived = new Set(def.derivedFields ?? []);
|
|
18
|
+
const seen = new Set();
|
|
19
|
+
const out = [];
|
|
20
|
+
for (const section of def.sections) {
|
|
21
|
+
if (!section.quick)
|
|
22
|
+
continue;
|
|
23
|
+
for (const field of section.fields ?? []) {
|
|
24
|
+
if (derived.has(field) || seen.has(field))
|
|
25
|
+
continue;
|
|
26
|
+
seen.add(field);
|
|
27
|
+
out.push(field);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return out;
|
|
31
|
+
}
|
|
32
|
+
/** Quick-mode field descriptors — feed straight into QuickFormDrawer's `fields` prop. */
|
|
33
|
+
export function deriveQuickFields(def) {
|
|
34
|
+
const required = new Set(def.requiredFields ?? []);
|
|
35
|
+
return deriveQuickFieldNames(def).map((name) => ({
|
|
36
|
+
name,
|
|
37
|
+
label: def.quickFieldLabels?.[name] ?? humaniseFieldName(name),
|
|
38
|
+
type: def.quickFieldTypes?.[name] ?? "text",
|
|
39
|
+
required: required.has(name),
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Throws when a `derive()` output is also offered as a quick field.
|
|
44
|
+
*
|
|
45
|
+
* That combination means the form asks the user to type something the
|
|
46
|
+
* definition computes for them, and whichever runs last silently wins. Call
|
|
47
|
+
* this once per definition — it is cheap and catches the mistake at the point
|
|
48
|
+
* the definition is written rather than at the point data is lost.
|
|
49
|
+
*/
|
|
50
|
+
export function assertNoDeriveCollision(def) {
|
|
51
|
+
const derived = new Set(def.derivedFields ?? []);
|
|
52
|
+
if (derived.size === 0)
|
|
53
|
+
return;
|
|
54
|
+
const collisions = [];
|
|
55
|
+
for (const section of def.sections) {
|
|
56
|
+
if (!section.quick)
|
|
57
|
+
continue;
|
|
58
|
+
for (const field of section.fields ?? []) {
|
|
59
|
+
if (derived.has(field))
|
|
60
|
+
collisions.push(field);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (collisions.length > 0) {
|
|
64
|
+
throw new Error(`EntityFormDefinition("${def.entity}"): ${collisions.join(", ")} ` +
|
|
65
|
+
`${collisions.length === 1 ? "is" : "are"} produced by derive() and also ` +
|
|
66
|
+
`marked as quick field(s). A derived field must not be asked of the user — ` +
|
|
67
|
+
`drop it from the quick section's \`fields\`, or stop deriving it.`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Every field name the definition can reach — the union of all section fields
|
|
72
|
+
* plus everything `derive()` produces.
|
|
73
|
+
*
|
|
74
|
+
* This is what a schema must be a superset of. A document field missing from
|
|
75
|
+
* this set is unreachable in the UI; a schema field missing from it can never
|
|
76
|
+
* be populated. `audit-form-field-roundtrip` checks both directions.
|
|
77
|
+
*/
|
|
78
|
+
export function allDefinitionFields(def) {
|
|
79
|
+
const out = new Set(def.derivedFields ?? []);
|
|
80
|
+
for (const section of def.sections) {
|
|
81
|
+
for (const field of section.fields ?? [])
|
|
82
|
+
out.add(field);
|
|
83
|
+
}
|
|
84
|
+
return [...out];
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Apply `derive()` to a pending change, without clobbering user input.
|
|
88
|
+
*
|
|
89
|
+
* Returns the partial to merge: the caller's own change plus whatever the
|
|
90
|
+
* definition computed from it.
|
|
91
|
+
*/
|
|
92
|
+
export function applyDerive(def, partial, prev, mode) {
|
|
93
|
+
if (!def.derive)
|
|
94
|
+
return partial;
|
|
95
|
+
return { ...partial, ...def.derive(partial, prev, { mode }) };
|
|
96
|
+
}
|
|
@@ -6,5 +6,9 @@ export type { QuickFieldType, QuickFieldDef, QuickFormDrawerProps } from "./Quic
|
|
|
6
6
|
export { QuickFormDrawer } from "./QuickFormDrawer";
|
|
7
7
|
export type { StepDef, StepFormProps, StepFormActionsProps } from "./StepForm";
|
|
8
8
|
export { StepForm, StepFormActions, StepIndicator } from "./StepForm";
|
|
9
|
+
export type { SectionDef, SectionFormProps, UseSectionFormNavResult, } from "./SectionForm";
|
|
10
|
+
export { SectionForm, useSectionFormNav, orderSections, buildFieldToSectionIndex, sectionAnchorId, } from "./SectionForm";
|
|
11
|
+
export type { EntityFormDefinition } from "./entity-form";
|
|
12
|
+
export { deriveQuickFields, deriveQuickFieldNames, allDefinitionFields, applyDerive, assertNoDeriveCollision, humaniseFieldName, } from "./entity-form";
|
|
9
13
|
export type { TitleDescriptionGroupProps, ImageFieldGroupProps, SeoFieldGroupProps, StatusFieldGroupProps, StatusFieldGroupOption, } from "./field-groups";
|
|
10
14
|
export { TitleDescriptionGroup, ImageFieldGroup, SeoFieldGroup, StatusFieldGroup, } from "./field-groups";
|
|
@@ -2,4 +2,6 @@ export { FormShell, useFormShell, FormSchemaContext } from "./FormShell";
|
|
|
2
2
|
export { CommandPalette, useCommandPaletteHotkey } from "./CommandPalette";
|
|
3
3
|
export { QuickFormDrawer } from "./QuickFormDrawer";
|
|
4
4
|
export { StepForm, StepFormActions, StepIndicator } from "./StepForm";
|
|
5
|
+
export { SectionForm, useSectionFormNav, orderSections, buildFieldToSectionIndex, sectionAnchorId, } from "./SectionForm";
|
|
6
|
+
export { deriveQuickFields, deriveQuickFieldNames, allDefinitionFields, applyDerive, assertNoDeriveCollision, humaniseFieldName, } from "./entity-form";
|
|
5
7
|
export { TitleDescriptionGroup, ImageFieldGroup, SeoFieldGroup, StatusFieldGroup, } from "./field-groups";
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { NextResponse } from "next/server.js";
|
|
15
15
|
import { getProviders } from "../../../../contracts";
|
|
16
|
+
import { toStoreDetail } from "../../../../_internal/server/features/stores/adapters";
|
|
16
17
|
import { normalizeError } from "../../../../errors/normalize";
|
|
17
18
|
// --- GET /api/stores/[storeSlug] ---------------------------------------------
|
|
18
19
|
export async function GET(_request, context) {
|
|
@@ -33,31 +34,7 @@ export async function GET(_request, context) {
|
|
|
33
34
|
return NextResponse.json({ success: false, error: "Store not found" }, { status: 404 });
|
|
34
35
|
}
|
|
35
36
|
// Map to public-safe StoreDetail shape (strip internal/sensitive fields)
|
|
36
|
-
const store =
|
|
37
|
-
id: raw.id,
|
|
38
|
-
storeSlug: raw.storeSlug,
|
|
39
|
-
ownerId: raw.ownerId,
|
|
40
|
-
storeName: raw.storeName,
|
|
41
|
-
storeDescription: raw.storeDescription,
|
|
42
|
-
storeCategory: raw.storeCategory,
|
|
43
|
-
storeLogoURL: raw.storeLogoURL,
|
|
44
|
-
storeBannerURL: raw.storeBannerURL,
|
|
45
|
-
status: raw.status,
|
|
46
|
-
isPublic: raw.isPublic,
|
|
47
|
-
totalProducts: raw.stats?.totalProducts ?? raw.totalProducts ?? undefined,
|
|
48
|
-
itemsSold: raw.stats?.itemsSold ?? raw.itemsSold ?? undefined,
|
|
49
|
-
totalReviews: raw.stats?.totalReviews ?? raw.totalReviews ?? undefined,
|
|
50
|
-
averageRating: raw.stats?.averageRating ?? raw.averageRating,
|
|
51
|
-
bio: raw.bio,
|
|
52
|
-
location: raw.location,
|
|
53
|
-
website: raw.website,
|
|
54
|
-
socialLinks: raw.socialLinks,
|
|
55
|
-
returnPolicy: raw.returnPolicy,
|
|
56
|
-
shippingPolicy: raw.shippingPolicy,
|
|
57
|
-
isVacationMode: raw.isVacationMode,
|
|
58
|
-
vacationMessage: raw.vacationMessage,
|
|
59
|
-
createdAt: raw.createdAt,
|
|
60
|
-
};
|
|
37
|
+
const store = toStoreDetail(raw);
|
|
61
38
|
return NextResponse.json({ success: true, data: store });
|
|
62
39
|
}
|
|
63
40
|
catch (error) {
|
|
@@ -13,6 +13,10 @@ import { getDefaultCurrency } from "../../../core/baseline-resolver";
|
|
|
13
13
|
import { useGuestWishlist } from "../../wishlist/hooks/useGuestWishlist";
|
|
14
14
|
import { pushWishlistOp } from "../../cart/utils/pending-ops";
|
|
15
15
|
import { AUCTION_PUBLIC_SORT_OPTIONS } from "../../products/constants/sieve";
|
|
16
|
+
import { AvailabilityTabs } from "../../products/components/AvailabilityTabs";
|
|
17
|
+
import { AVAILABILITY_VALUES } from "../../../constants/field-names";
|
|
18
|
+
import { TABLE_KEYS } from "../../../constants/table-keys";
|
|
19
|
+
const STORE_AUCTION_TYPES = ["auction"];
|
|
16
20
|
const __P = {
|
|
17
21
|
p3: "p-[var(--appkit-space-3)]",
|
|
18
22
|
};
|
|
@@ -45,6 +49,12 @@ export function StoreAuctionsListing({ storeId, initialData }) {
|
|
|
45
49
|
const hasActiveState = !!table.get("q") ||
|
|
46
50
|
table.get("sort") !== DEFAULT_SORT ||
|
|
47
51
|
filterActiveCount > 0;
|
|
52
|
+
// Absent means "available" — the same default `listStoreProducts`
|
|
53
|
+
// resolves server-side. These six store tabs sent NO availability
|
|
54
|
+
// param at all until 2026-08-24, while their SSR fetch did apply one,
|
|
55
|
+
// so any client refetch silently widened the list (Root Cause #30).
|
|
56
|
+
const availability = table.get(TABLE_KEYS.AVAILABILITY) ||
|
|
57
|
+
AVAILABILITY_VALUES.AVAILABLE;
|
|
48
58
|
const params = {
|
|
49
59
|
q: table.get("q") || undefined,
|
|
50
60
|
minBid: table.get("minBid") ? Number(table.get("minBid")) : undefined,
|
|
@@ -56,6 +66,7 @@ export function StoreAuctionsListing({ storeId, initialData }) {
|
|
|
56
66
|
perPage: table.getNumber("pageSize", 24),
|
|
57
67
|
storeId: storeId || undefined,
|
|
58
68
|
listingType: "auction",
|
|
69
|
+
availability,
|
|
59
70
|
};
|
|
60
71
|
const { products: rawAuctions, totalPages, page, isLoading } = useProducts(params, { initialData });
|
|
61
72
|
const auctions = rawAuctions.map((p) => ({
|
|
@@ -75,6 +86,9 @@ export function StoreAuctionsListing({ storeId, initialData }) {
|
|
|
75
86
|
status: p.status,
|
|
76
87
|
slug: p.slug,
|
|
77
88
|
buyNowPrice: p.buyNowPrice,
|
|
89
|
+
// Read by isBuyNowAvailable() on the card — without it a sold auction still
|
|
90
|
+
// offers a Buyout chip.
|
|
91
|
+
isSold: p.isSold,
|
|
78
92
|
}));
|
|
79
93
|
const commitSearch = useCallback(() => {
|
|
80
94
|
// table.set("q", v) already resets page to 1 — see root-cause #13.
|
|
@@ -107,7 +121,7 @@ export function StoreAuctionsListing({ storeId, initialData }) {
|
|
|
107
121
|
return;
|
|
108
122
|
setView(v);
|
|
109
123
|
table.set("view", v);
|
|
110
|
-
}, onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), _jsx(Div, { padding: "y-lg", children: isLoading ? (_jsx(Div, { className: gridClass, children: Array.from({ length: 8 }).map((_, i) => (_jsxs(Div, { className: "overflow-hidden animate-pulse", border: "subtle", rounded: "xl", children: [_jsx(Div, { className: "aspect-square", surface: "subtle" }), _jsxs(Stack, { className: `${__P.p3}`, gap: "sm", children: [_jsx(Div, { className: "h-3 w-3/4", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-4 w-1/2", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-8", surface: "subtle", rounded: "default" })] })] }, i))) })) : (_jsx(MarketplaceAuctionGrid, { auctions: auctions, variant: view === "list" ? "list" : "grid", gridClassName: view === "list" ? "flex flex-col gap-[var(--appkit-space-4)]" : gridClass, wishlistActions: wishlistActions, labels: {
|
|
124
|
+
}, onResetAll: resetAll, hasActiveState: hasActiveState }), _jsx(Div, { padding: "y-sm", children: _jsx(AvailabilityTabs, { types: STORE_AUCTION_TYPES }) }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), _jsx(Div, { padding: "y-lg", children: isLoading ? (_jsx(Div, { className: gridClass, children: Array.from({ length: 8 }).map((_, i) => (_jsxs(Div, { className: "overflow-hidden animate-pulse", border: "subtle", rounded: "xl", children: [_jsx(Div, { className: "aspect-square", surface: "subtle" }), _jsxs(Stack, { className: `${__P.p3}`, gap: "sm", children: [_jsx(Div, { className: "h-3 w-3/4", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-4 w-1/2", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-8", surface: "subtle", rounded: "default" })] })] }, i))) })) : (_jsx(MarketplaceAuctionGrid, { auctions: auctions, variant: view === "list" ? "list" : "grid", gridClassName: view === "list" ? "flex flex-col gap-[var(--appkit-space-4)]" : gridClass, wishlistActions: wishlistActions, labels: {
|
|
111
125
|
emptyTitle: "No auctions yet",
|
|
112
126
|
emptyDescription: "This store has no active auctions.",
|
|
113
127
|
} })) }), _jsx(FilterDrawer, { open: filterOpen, onOpen: openFilters, onClose: () => setFilterOpen(false), onApply: applyFilters, onReset: onFilterClear, activeCount: filterActiveCount, hideTrigger: true, children: _jsx(AuctionFilters, { table: pendingTable, currencyPrefix: "\u20B9" }) }), _jsx(LoginRequiredModal, { isOpen: modalOpen, onClose: closeModal, message: modalMessage })] }));
|
|
@@ -8,9 +8,12 @@ import { Div, FilterDrawer, ListingToolbar, Pagination, Row, Text, StickyToolbar
|
|
|
8
8
|
import { ClassifiedFilters } from "../../classified/components/ClassifiedFilters";
|
|
9
9
|
import { InteractiveProductCard } from "../../products/components/InteractiveProductCard";
|
|
10
10
|
import { PRODUCT_FIELDS } from "../../../constants/field-names";
|
|
11
|
-
import { TABLE_KEYS } from "../../../constants/table-keys";
|
|
12
11
|
import { sortBy } from "../../../constants/sort";
|
|
13
12
|
import { ROUTES } from "../../../next";
|
|
13
|
+
import { AvailabilityTabs } from "../../products/components/AvailabilityTabs";
|
|
14
|
+
import { AVAILABILITY_VALUES } from "../../../constants/field-names";
|
|
15
|
+
import { TABLE_KEYS } from "../../../constants/table-keys";
|
|
16
|
+
const STORE_CLASSIFIED_TYPES = ["classified"];
|
|
14
17
|
const DEFAULT_SORT = sortBy(PRODUCT_FIELDS.CREATED_AT);
|
|
15
18
|
const SORT_OPTIONS = [
|
|
16
19
|
{ value: sortBy(PRODUCT_FIELDS.CREATED_AT), label: "Newest First" },
|
|
@@ -28,6 +31,12 @@ export function StoreClassifiedsListing({ storeId, initialData }) {
|
|
|
28
31
|
const applyFilters = useCallback(() => { onFilterApply(); setFilterOpen(false); }, [onFilterApply]);
|
|
29
32
|
const resetAll = useCallback(() => { onResetAll({ q: "", sort: "" }); setSearchInput(""); }, [onResetAll]);
|
|
30
33
|
const hasActiveState = !!table.get("q") || table.get("sort") !== DEFAULT_SORT || filterActiveCount > 0;
|
|
34
|
+
// Absent means "available" — the same default `listStoreProducts`
|
|
35
|
+
// resolves server-side. These six store tabs sent NO availability
|
|
36
|
+
// param at all until 2026-08-24, while their SSR fetch did apply one,
|
|
37
|
+
// so any client refetch silently widened the list (Root Cause #30).
|
|
38
|
+
const availability = table.get(TABLE_KEYS.AVAILABILITY) ||
|
|
39
|
+
AVAILABILITY_VALUES.AVAILABLE;
|
|
31
40
|
const params = {
|
|
32
41
|
q: table.get("q") || undefined,
|
|
33
42
|
minPrice: table.get(TABLE_KEYS.MIN_PRICE) ? Number(table.get(TABLE_KEYS.MIN_PRICE)) : undefined,
|
|
@@ -44,10 +53,11 @@ export function StoreClassifiedsListing({ storeId, initialData }) {
|
|
|
44
53
|
[TABLE_KEYS.NEGOTIABLE]: table.get(TABLE_KEYS.NEGOTIABLE),
|
|
45
54
|
[TABLE_KEYS.ACCEPTS_SHIPPING]: table.get(TABLE_KEYS.ACCEPTS_SHIPPING),
|
|
46
55
|
},
|
|
56
|
+
availability,
|
|
47
57
|
};
|
|
48
58
|
const { products, totalPages, page, isLoading } = useProducts(params, { initialData });
|
|
49
59
|
const gridClass = "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-[var(--appkit-space-4)]";
|
|
50
|
-
return (_jsxs(Div, { className: "min-h-[200px]", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search store classifieds\u2026", onSearchChange: setSearchInput, onSearchCommit: () => table.set("q", searchInput.trim()), sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => table.set("sort", v), onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), _jsx(Div, { padding: "y-lg", children: _jsx(Div, { className: gridClass, children: isLoading
|
|
60
|
+
return (_jsxs(Div, { className: "min-h-[200px]", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search store classifieds\u2026", onSearchChange: setSearchInput, onSearchCommit: () => table.set("q", searchInput.trim()), sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => table.set("sort", v), onResetAll: resetAll, hasActiveState: hasActiveState }), _jsx(Div, { padding: "y-sm", children: _jsx(AvailabilityTabs, { types: STORE_CLASSIFIED_TYPES }) }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), _jsx(Div, { padding: "y-lg", children: _jsx(Div, { className: gridClass, children: isLoading
|
|
51
61
|
? Array.from({ length: 8 }).map((_, i) => _jsx(Div, { surface: "muted", rounded: "xl", className: "aspect-square animate-pulse" }, i))
|
|
52
62
|
: products.length === 0
|
|
53
63
|
? _jsx(Div, { paddingY: "y-4xl", className: "col-span-full text-left", children: _jsx(Text, { color: "muted", children: "No classified listings in this store yet." }) })
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { sieveFilter, sieveAnd, SIEVE_OP } from "@mohasinac/appkit";
|
|
3
3
|
import { cache } from "react";
|
|
4
|
-
import { storeRepository,
|
|
4
|
+
import { storeRepository, siteSettingsRepository, reviewRepository, couponsRepository } from "../../../repositories";
|
|
5
5
|
import { ROUTES } from "../../../next";
|
|
6
6
|
import { Container, Main, Section, Text } from "../../../ui";
|
|
7
7
|
import { STORE_PAGE_TABS } from "../../products/constants/listing-tabs";
|
|
8
8
|
import { isListingTypeEnabled, isCategoryTypeEnabled } from "../../../_internal/shared/listing-types/feature-flags";
|
|
9
|
+
import { pluginFor } from "../../../_internal/shared/listing-types/_registry";
|
|
10
|
+
import { listingTabCounts, } from "../../../_internal/server/features/products/listing-tab-counts";
|
|
9
11
|
import { getSellerTrustStatus } from "../../scams/actions/scam-actions";
|
|
10
12
|
import { StoreHeader } from "./StoreHeader";
|
|
11
13
|
import { StoreNavTabs } from "./StoreNavTabs";
|
|
14
|
+
import { toStoreDetail } from "../../../_internal/server/features/stores/adapters";
|
|
12
15
|
const STORE_LISTING_HREF = {
|
|
13
16
|
products: (slug) => String(ROUTES.PUBLIC.STORE_PRODUCTS(slug)),
|
|
14
17
|
auctions: (slug) => String(ROUTES.PUBLIC.STORE_AUCTIONS(slug)),
|
|
@@ -41,46 +44,14 @@ export async function StoreDetailLayoutView({ storeSlug, activeTab, children, sc
|
|
|
41
44
|
? getSellerTrustStatus(storeId).catch(() => undefined)
|
|
42
45
|
: Promise.resolve(undefined),
|
|
43
46
|
]);
|
|
44
|
-
|
|
47
|
+
// One derived batch instead of nine copy-pasted per-type queries. The tabs
|
|
48
|
+
// themselves say which listing types to count (including the combined
|
|
49
|
+
// `art|stickers` OR-group), so a tenth type is counted automatically — the
|
|
50
|
+
// hand-written `TAB_LISTING_TYPE` map this replaces was unguarded by any
|
|
51
|
+
// audit and already omitted art/stickers (Root Cause #61).
|
|
52
|
+
const [listingCounts, couponsCount, reviewsCount] = storeId
|
|
45
53
|
? await Promise.all([
|
|
46
|
-
|
|
47
|
-
.list({ filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("listingType", SIEVE_OP.EQ, "standard")), page: 1, pageSize: 1 })
|
|
48
|
-
.then((r) => r.total)
|
|
49
|
-
.catch(() => 0),
|
|
50
|
-
productRepository
|
|
51
|
-
.list({ filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("listingType", SIEVE_OP.EQ, "auction")), page: 1, pageSize: 1 })
|
|
52
|
-
.then((r) => r.total)
|
|
53
|
-
.catch(() => 0),
|
|
54
|
-
productRepository
|
|
55
|
-
.list({ filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("listingType", SIEVE_OP.EQ, "pre-order")), page: 1, pageSize: 1 })
|
|
56
|
-
.then((r) => r.total)
|
|
57
|
-
.catch(() => 0),
|
|
58
|
-
productRepository
|
|
59
|
-
.list({ filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("listingType", SIEVE_OP.EQ, "prize-draw")), page: 1, pageSize: 1 })
|
|
60
|
-
.then((r) => r.total)
|
|
61
|
-
.catch(() => 0),
|
|
62
|
-
// SB-UNI-D — bundles live on categories with categoryType:"bundle"
|
|
63
|
-
// + createdByStoreId scoping.
|
|
64
|
-
categoriesRepository
|
|
65
|
-
.listByType("bundle", { activeOnly: true, limit: 100 })
|
|
66
|
-
.then((rows) => rows.filter((c) => c.createdByStoreId === storeId).length)
|
|
67
|
-
.catch(() => 0),
|
|
68
|
-
productRepository
|
|
69
|
-
.list({ filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("listingType", SIEVE_OP.EQ, "classified")), page: 1, pageSize: 1 })
|
|
70
|
-
.then((r) => r.total)
|
|
71
|
-
.catch(() => 0),
|
|
72
|
-
productRepository
|
|
73
|
-
.list({ filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("listingType", SIEVE_OP.EQ, "digital-code")), page: 1, pageSize: 1 })
|
|
74
|
-
.then((r) => r.total)
|
|
75
|
-
.catch(() => 0),
|
|
76
|
-
productRepository
|
|
77
|
-
.list({ filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("listingType", SIEVE_OP.EQ, "live")), page: 1, pageSize: 1 })
|
|
78
|
-
.then((r) => r.total)
|
|
79
|
-
.catch(() => 0),
|
|
80
|
-
productRepository
|
|
81
|
-
.list({ filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("listingType", SIEVE_OP.EQ, "art|stickers")), page: 1, pageSize: 1 })
|
|
82
|
-
.then((r) => r.total)
|
|
83
|
-
.catch(() => 0),
|
|
54
|
+
listingTabCounts(STORE_PAGE_TABS, { storeId }),
|
|
84
55
|
couponsRepository
|
|
85
56
|
.list({ filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("validity.isActive", SIEVE_OP.EQ, "true")), page: 1, pageSize: 1 })
|
|
86
57
|
.then((r) => r.total)
|
|
@@ -90,46 +61,28 @@ export async function StoreDetailLayoutView({ storeSlug, activeTab, children, sc
|
|
|
90
61
|
.then((r) => r.total)
|
|
91
62
|
.catch(() => 0),
|
|
92
63
|
])
|
|
93
|
-
: [
|
|
94
|
-
const listingCounts = {
|
|
95
|
-
products: productsCount,
|
|
96
|
-
auctions: auctionsCount,
|
|
97
|
-
"pre-orders": preOrdersCount,
|
|
98
|
-
"prize-draws": prizeDrawsCount,
|
|
99
|
-
bundles: bundlesCount,
|
|
100
|
-
classifieds: classifiedsCount,
|
|
101
|
-
"digital-codes": digitalCodesCount,
|
|
102
|
-
live: liveCount,
|
|
103
|
-
art: artStickersCount,
|
|
104
|
-
};
|
|
105
|
-
const TAB_LISTING_TYPE = {
|
|
106
|
-
products: "standard",
|
|
107
|
-
auctions: "auction",
|
|
108
|
-
"pre-orders": "pre-order",
|
|
109
|
-
"prize-draws": "prize-draw",
|
|
110
|
-
classifieds: "classified",
|
|
111
|
-
"digital-codes": "digital-code",
|
|
112
|
-
live: "live",
|
|
113
|
-
};
|
|
64
|
+
: [{}, 0, 0];
|
|
114
65
|
const visibleStoreTabs = STORE_PAGE_TABS.filter((tab) => {
|
|
115
66
|
if (tab.id === "bundles") {
|
|
116
67
|
if (!isCategoryTypeEnabled("bundle", settings))
|
|
117
68
|
return false;
|
|
118
|
-
return listingCounts[tab.id] > 0;
|
|
119
69
|
}
|
|
120
|
-
|
|
121
|
-
|
|
70
|
+
else if (tab.id === pluginFor("art").tabSlug) {
|
|
71
|
+
// Combined tab — visible if either underlying listing type is enabled.
|
|
122
72
|
if (!(isListingTypeEnabled("art", settings) || isListingTypeEnabled("stickers", settings)))
|
|
123
73
|
return false;
|
|
124
|
-
return listingCounts[tab.id] > 0;
|
|
125
74
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
75
|
+
else if (tab.listingType) {
|
|
76
|
+
if (!isListingTypeEnabled(tab.listingType, settings))
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
129
79
|
// A store with zero items of a given listing type shouldn't offer a tab
|
|
130
80
|
// that leads to an empty page — matches the "hide empty tab" rule below
|
|
131
|
-
// for coupons/reviews.
|
|
132
|
-
|
|
81
|
+
// for coupons/reviews. `undefined` means the count query FAILED, not zero,
|
|
82
|
+
// so the tab stays visible rather than hiding real stock behind a
|
|
83
|
+
// swallowed error (Root Cause #59) — this used to be `.catch(() => 0)`.
|
|
84
|
+
const count = listingCounts[tab.id];
|
|
85
|
+
return count === undefined || count > 0;
|
|
133
86
|
});
|
|
134
87
|
const dropdownTabs = visibleStoreTabs.map((tab) => ({
|
|
135
88
|
value: tab.id,
|
|
@@ -145,5 +98,5 @@ export async function StoreDetailLayoutView({ storeSlug, activeTab, children, sc
|
|
|
145
98
|
: []),
|
|
146
99
|
{ value: "about", label: "About", href: String(ROUTES.PUBLIC.STORE_ABOUT(storeSlug)) },
|
|
147
100
|
];
|
|
148
|
-
return (_jsxs(Main, { children: [_jsx(StoreHeader, { store: store, trust: trust }), _jsxs(Container, { size: "xl", className: "mt-6", children: [_jsx(StoreNavTabs, { dropdownTabs: dropdownTabs, dropdownPlaceholder: "Browse listings", tabs: tabs, activeValue: activeTab }), _jsx(Section, { padding: "t-lg", children: children })] })] }));
|
|
101
|
+
return (_jsxs(Main, { children: [_jsx(StoreHeader, { store: toStoreDetail(store), trust: trust }), _jsxs(Container, { size: "xl", className: "mt-6", children: [_jsx(StoreNavTabs, { dropdownTabs: dropdownTabs, dropdownPlaceholder: "Browse listings", tabs: tabs, activeValue: activeTab }), _jsx(Section, { padding: "t-lg", children: children })] })] }));
|
|
149
102
|
}
|
|
@@ -8,9 +8,12 @@ import { Div, FilterDrawer, ListingToolbar, Pagination, Row, Text, StickyToolbar
|
|
|
8
8
|
import { DigitalCodeFilters } from "../../digital-codes/components/DigitalCodeFilters";
|
|
9
9
|
import { InteractiveProductCard } from "../../products/components/InteractiveProductCard";
|
|
10
10
|
import { PRODUCT_FIELDS } from "../../../constants/field-names";
|
|
11
|
-
import { TABLE_KEYS } from "../../../constants/table-keys";
|
|
12
11
|
import { sortBy } from "../../../constants/sort";
|
|
13
12
|
import { ROUTES } from "../../../next";
|
|
13
|
+
import { AvailabilityTabs } from "../../products/components/AvailabilityTabs";
|
|
14
|
+
import { AVAILABILITY_VALUES } from "../../../constants/field-names";
|
|
15
|
+
import { TABLE_KEYS } from "../../../constants/table-keys";
|
|
16
|
+
const STORE_DIGITAL_CODE_TYPES = ["digital-code"];
|
|
14
17
|
const DEFAULT_SORT = sortBy(PRODUCT_FIELDS.CREATED_AT);
|
|
15
18
|
const SORT_OPTIONS = [
|
|
16
19
|
{ value: sortBy(PRODUCT_FIELDS.CREATED_AT), label: "Newest First" },
|
|
@@ -28,6 +31,12 @@ export function StoreDigitalCodesListing({ storeId, initialData }) {
|
|
|
28
31
|
const applyFilters = useCallback(() => { onFilterApply(); setFilterOpen(false); }, [onFilterApply]);
|
|
29
32
|
const resetAll = useCallback(() => { onResetAll({ q: "", sort: "" }); setSearchInput(""); }, [onResetAll]);
|
|
30
33
|
const hasActiveState = !!table.get("q") || table.get("sort") !== DEFAULT_SORT || filterActiveCount > 0;
|
|
34
|
+
// Absent means "available" — the same default `listStoreProducts`
|
|
35
|
+
// resolves server-side. These six store tabs sent NO availability
|
|
36
|
+
// param at all until 2026-08-24, while their SSR fetch did apply one,
|
|
37
|
+
// so any client refetch silently widened the list (Root Cause #30).
|
|
38
|
+
const availability = table.get(TABLE_KEYS.AVAILABILITY) ||
|
|
39
|
+
AVAILABILITY_VALUES.AVAILABLE;
|
|
31
40
|
const params = {
|
|
32
41
|
q: table.get("q") || undefined,
|
|
33
42
|
minPrice: table.get(TABLE_KEYS.MIN_PRICE) ? Number(table.get(TABLE_KEYS.MIN_PRICE)) : undefined,
|
|
@@ -42,10 +51,11 @@ export function StoreDigitalCodesListing({ storeId, initialData }) {
|
|
|
42
51
|
typeFacets: {
|
|
43
52
|
[TABLE_KEYS.DELIVERY_METHOD]: table.get(TABLE_KEYS.DELIVERY_METHOD),
|
|
44
53
|
},
|
|
54
|
+
availability,
|
|
45
55
|
};
|
|
46
56
|
const { products, totalPages, page, isLoading } = useProducts(params, { initialData });
|
|
47
57
|
const gridClass = "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-[var(--appkit-space-4)]";
|
|
48
|
-
return (_jsxs(Div, { className: "min-h-[200px]", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search digital codes\u2026", onSearchChange: setSearchInput, onSearchCommit: () => table.set("q", searchInput.trim()), sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => table.set("sort", v), onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), _jsx(Div, { padding: "y-lg", children: _jsx(Div, { className: gridClass, children: isLoading
|
|
58
|
+
return (_jsxs(Div, { className: "min-h-[200px]", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search digital codes\u2026", onSearchChange: setSearchInput, onSearchCommit: () => table.set("q", searchInput.trim()), sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => table.set("sort", v), onResetAll: resetAll, hasActiveState: hasActiveState }), _jsx(Div, { padding: "y-sm", children: _jsx(AvailabilityTabs, { types: STORE_DIGITAL_CODE_TYPES }) }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), _jsx(Div, { padding: "y-lg", children: _jsx(Div, { className: gridClass, children: isLoading
|
|
49
59
|
? Array.from({ length: 8 }).map((_, i) => _jsx(Div, { surface: "muted", rounded: "xl", className: "aspect-square animate-pulse" }, i))
|
|
50
60
|
: products.length === 0
|
|
51
61
|
? _jsx(Div, { paddingY: "y-4xl", className: "col-span-full text-left", children: _jsx(Text, { color: "muted", children: "No digital codes in this store yet." }) })
|
|
@@ -8,9 +8,12 @@ import { Div, FilterDrawer, ListingToolbar, Pagination, Row, Text, StickyToolbar
|
|
|
8
8
|
import { LiveItemFilters } from "../../live/components/LiveItemFilters";
|
|
9
9
|
import { InteractiveProductCard } from "../../products/components/InteractiveProductCard";
|
|
10
10
|
import { PRODUCT_FIELDS } from "../../../constants/field-names";
|
|
11
|
-
import { TABLE_KEYS } from "../../../constants/table-keys";
|
|
12
11
|
import { sortBy } from "../../../constants/sort";
|
|
13
12
|
import { ROUTES } from "../../../next";
|
|
13
|
+
import { AvailabilityTabs } from "../../products/components/AvailabilityTabs";
|
|
14
|
+
import { AVAILABILITY_VALUES } from "../../../constants/field-names";
|
|
15
|
+
import { TABLE_KEYS } from "../../../constants/table-keys";
|
|
16
|
+
const STORE_LIVE_TYPES = ["live"];
|
|
14
17
|
const DEFAULT_SORT = sortBy(PRODUCT_FIELDS.CREATED_AT);
|
|
15
18
|
const SORT_OPTIONS = [
|
|
16
19
|
{ value: sortBy(PRODUCT_FIELDS.CREATED_AT), label: "Newest First" },
|
|
@@ -28,6 +31,12 @@ export function StoreLiveItemsListing({ storeId, initialData }) {
|
|
|
28
31
|
const applyFilters = useCallback(() => { onFilterApply(); setFilterOpen(false); }, [onFilterApply]);
|
|
29
32
|
const resetAll = useCallback(() => { onResetAll({ q: "", sort: "" }); setSearchInput(""); }, [onResetAll]);
|
|
30
33
|
const hasActiveState = !!table.get("q") || table.get("sort") !== DEFAULT_SORT || filterActiveCount > 0;
|
|
34
|
+
// Absent means "available" — the same default `listStoreProducts`
|
|
35
|
+
// resolves server-side. These six store tabs sent NO availability
|
|
36
|
+
// param at all until 2026-08-24, while their SSR fetch did apply one,
|
|
37
|
+
// so any client refetch silently widened the list (Root Cause #30).
|
|
38
|
+
const availability = table.get(TABLE_KEYS.AVAILABILITY) ||
|
|
39
|
+
AVAILABILITY_VALUES.AVAILABLE;
|
|
31
40
|
const params = {
|
|
32
41
|
q: table.get("q") || undefined,
|
|
33
42
|
minPrice: table.get(TABLE_KEYS.MIN_PRICE) ? Number(table.get(TABLE_KEYS.MIN_PRICE)) : undefined,
|
|
@@ -44,10 +53,11 @@ export function StoreLiveItemsListing({ storeId, initialData }) {
|
|
|
44
53
|
[TABLE_KEYS.LIVE_SEX]: table.get(TABLE_KEYS.LIVE_SEX),
|
|
45
54
|
[TABLE_KEYS.JURISDICTION]: table.get(TABLE_KEYS.JURISDICTION),
|
|
46
55
|
},
|
|
56
|
+
availability,
|
|
47
57
|
};
|
|
48
58
|
const { products, totalPages, page, isLoading } = useProducts(params, { initialData });
|
|
49
59
|
const gridClass = "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-[var(--appkit-space-4)]";
|
|
50
|
-
return (_jsxs(Div, { className: "min-h-[200px]", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search live animals & plants\u2026", onSearchChange: setSearchInput, onSearchCommit: () => table.set("q", searchInput.trim()), sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => table.set("sort", v), onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), _jsx(Div, { padding: "y-lg", children: _jsx(Div, { className: gridClass, children: isLoading
|
|
60
|
+
return (_jsxs(Div, { className: "min-h-[200px]", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search live animals & plants\u2026", onSearchChange: setSearchInput, onSearchCommit: () => table.set("q", searchInput.trim()), sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => table.set("sort", v), onResetAll: resetAll, hasActiveState: hasActiveState }), _jsx(Div, { padding: "y-sm", children: _jsx(AvailabilityTabs, { types: STORE_LIVE_TYPES }) }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), _jsx(Div, { padding: "y-lg", children: _jsx(Div, { className: gridClass, children: isLoading
|
|
51
61
|
? Array.from({ length: 8 }).map((_, i) => _jsx(Div, { surface: "muted", rounded: "xl", className: "aspect-square animate-pulse" }, i))
|
|
52
62
|
: products.length === 0
|
|
53
63
|
? _jsx(Div, { paddingY: "y-4xl", className: "col-span-full text-left", children: _jsx(Text, { color: "muted", children: "No live items in this store yet." }) })
|
|
@@ -9,6 +9,10 @@ import { MarketplacePreorderCard } from "../../pre-orders/components/Marketplace
|
|
|
9
9
|
import { ProductFilters } from "../../products/components/ProductFilters";
|
|
10
10
|
import { ROUTES } from "../../../next";
|
|
11
11
|
import { PREORDER_PUBLIC_SORT_OPTIONS } from "../../products/constants/sieve";
|
|
12
|
+
import { AvailabilityTabs } from "../../products/components/AvailabilityTabs";
|
|
13
|
+
import { AVAILABILITY_VALUES } from "../../../constants/field-names";
|
|
14
|
+
import { TABLE_KEYS } from "../../../constants/table-keys";
|
|
15
|
+
const STORE_PRE_ORDER_TYPES = ["pre-order"];
|
|
12
16
|
const __P = {
|
|
13
17
|
p3: "p-[var(--appkit-space-3)]",
|
|
14
18
|
};
|
|
@@ -38,6 +42,12 @@ export function StorePreOrdersListing({ storeId, initialData }) {
|
|
|
38
42
|
const hasActiveState = !!table.get("q") ||
|
|
39
43
|
table.get("sort") !== DEFAULT_SORT ||
|
|
40
44
|
filterActiveCount > 0;
|
|
45
|
+
// Absent means "available" — the same default `listStoreProducts`
|
|
46
|
+
// resolves server-side. These six store tabs sent NO availability
|
|
47
|
+
// param at all until 2026-08-24, while their SSR fetch did apply one,
|
|
48
|
+
// so any client refetch silently widened the list (Root Cause #30).
|
|
49
|
+
const availability = table.get(TABLE_KEYS.AVAILABILITY) ||
|
|
50
|
+
AVAILABILITY_VALUES.AVAILABLE;
|
|
41
51
|
const params = {
|
|
42
52
|
q: table.get("q") || undefined,
|
|
43
53
|
minPrice: table.get("minPrice") ? Number(table.get("minPrice")) : undefined,
|
|
@@ -47,6 +57,7 @@ export function StorePreOrdersListing({ storeId, initialData }) {
|
|
|
47
57
|
perPage: table.getNumber("pageSize", 24),
|
|
48
58
|
storeId: storeId || undefined,
|
|
49
59
|
listingType: "pre-order",
|
|
60
|
+
availability,
|
|
50
61
|
};
|
|
51
62
|
const { products: preOrders, totalPages, page, isLoading } = useProducts(params, { initialData });
|
|
52
63
|
const commitSearch = useCallback(() => {
|
|
@@ -61,5 +72,5 @@ export function StorePreOrdersListing({ storeId, initialData }) {
|
|
|
61
72
|
return;
|
|
62
73
|
setView(v);
|
|
63
74
|
table.set("view", v);
|
|
64
|
-
}, onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), _jsx(Div, { padding: "y-lg", children: isLoading ? (_jsx(Div, { className: gridClass, children: Array.from({ length: 8 }).map((_, i) => (_jsxs(Div, { className: "overflow-hidden animate-pulse", border: "subtle", rounded: "xl", children: [_jsx(Div, { className: "aspect-square", surface: "subtle" }), _jsxs(Stack, { className: `${__P.p3}`, gap: "sm", children: [_jsx(Div, { className: "h-3 w-3/4", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-3 w-1/2", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-8", surface: "subtle", rounded: "default" })] })] }, i))) })) : preOrders.length === 0 ? (_jsx(Text, { paddingY: "3xl", color: "muted", size: "sm", align: "start", children: "This store has no pre-orders yet." })) : view === "list" ? (_jsx(Stack, { className: "divide-y divide-zinc-100 divide-[var(--appkit-color-border-subtle)]", border: "subtle", rounded: "xl", children: preOrders.map((product) => (_jsx(MarketplacePreorderCard, { product: product, variant: "list", hrefBuilder: (p) => String(ROUTES.PUBLIC.PRE_ORDER_DETAIL(p.id)) }, product.id))) })) : (_jsx(Div, { className: gridClass, children: preOrders.map((product) => (_jsx(MarketplacePreorderCard, { product: product, variant: "grid", hrefBuilder: (p) => String(ROUTES.PUBLIC.PRE_ORDER_DETAIL(p.id)) }, product.id))) })) }), _jsx(FilterDrawer, { open: filterOpen, onOpen: openFilters, onClose: () => setFilterOpen(false), onApply: applyFilters, onReset: onFilterClear, activeCount: filterActiveCount, hideTrigger: true, children: _jsx(ProductFilters, { table: pendingTable, currencyPrefix: "\u20B9" }) })] }));
|
|
75
|
+
}, onResetAll: resetAll, hasActiveState: hasActiveState }), _jsx(Div, { padding: "y-sm", children: _jsx(AvailabilityTabs, { types: STORE_PRE_ORDER_TYPES }) }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), _jsx(Div, { padding: "y-lg", children: isLoading ? (_jsx(Div, { className: gridClass, children: Array.from({ length: 8 }).map((_, i) => (_jsxs(Div, { className: "overflow-hidden animate-pulse", border: "subtle", rounded: "xl", children: [_jsx(Div, { className: "aspect-square", surface: "subtle" }), _jsxs(Stack, { className: `${__P.p3}`, gap: "sm", children: [_jsx(Div, { className: "h-3 w-3/4", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-3 w-1/2", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-8", surface: "subtle", rounded: "default" })] })] }, i))) })) : preOrders.length === 0 ? (_jsx(Text, { paddingY: "3xl", color: "muted", size: "sm", align: "start", children: "This store has no pre-orders yet." })) : view === "list" ? (_jsx(Stack, { className: "divide-y divide-zinc-100 divide-[var(--appkit-color-border-subtle)]", border: "subtle", rounded: "xl", children: preOrders.map((product) => (_jsx(MarketplacePreorderCard, { product: product, variant: "list", hrefBuilder: (p) => String(ROUTES.PUBLIC.PRE_ORDER_DETAIL(p.id)) }, product.id))) })) : (_jsx(Div, { className: gridClass, children: preOrders.map((product) => (_jsx(MarketplacePreorderCard, { product: product, variant: "grid", hrefBuilder: (p) => String(ROUTES.PUBLIC.PRE_ORDER_DETAIL(p.id)) }, product.id))) })) }), _jsx(FilterDrawer, { open: filterOpen, onOpen: openFilters, onClose: () => setFilterOpen(false), onApply: applyFilters, onReset: onFilterClear, activeCount: filterActiveCount, hideTrigger: true, children: _jsx(ProductFilters, { table: pendingTable, currencyPrefix: "\u20B9" }) })] }));
|
|
65
76
|
}
|
|
@@ -13,6 +13,9 @@ import { ProductFilters, PRODUCT_PUBLIC_SORT_OPTIONS } from "../../products/comp
|
|
|
13
13
|
import { useGuestCart } from "../../cart/hooks/useGuestCart";
|
|
14
14
|
import { useGuestWishlist } from "../../wishlist/hooks/useGuestWishlist";
|
|
15
15
|
import { pushCartOp, pushWishlistOp } from "../../cart/utils/pending-ops";
|
|
16
|
+
import { AvailabilityTabs } from "../../products/components/AvailabilityTabs";
|
|
17
|
+
import { AVAILABILITY_VALUES } from "../../../constants/field-names";
|
|
18
|
+
import { TABLE_KEYS } from "../../../constants/table-keys";
|
|
16
19
|
const __P = {
|
|
17
20
|
p3: "p-[var(--appkit-space-3)]",
|
|
18
21
|
};
|
|
@@ -43,6 +46,12 @@ export function StoreProductsListing({ storeId, listingTypes = ["standard"], ini
|
|
|
43
46
|
const hasActiveState = !!table.get("q") ||
|
|
44
47
|
table.get("sort") !== "-createdAt" ||
|
|
45
48
|
filterActiveCount > 0;
|
|
49
|
+
// Absent means "available" — the same default `listStoreProducts`
|
|
50
|
+
// resolves server-side. These six store tabs sent NO availability
|
|
51
|
+
// param at all until 2026-08-24, while their SSR fetch did apply one,
|
|
52
|
+
// so any client refetch silently widened the list (Root Cause #30).
|
|
53
|
+
const availability = table.get(TABLE_KEYS.AVAILABILITY) ||
|
|
54
|
+
AVAILABILITY_VALUES.AVAILABLE;
|
|
46
55
|
const params = {
|
|
47
56
|
q: table.get("q") || undefined,
|
|
48
57
|
condition: table.get("condition") || undefined,
|
|
@@ -55,6 +64,7 @@ export function StoreProductsListing({ storeId, listingTypes = ["standard"], ini
|
|
|
55
64
|
storeId: storeId || undefined,
|
|
56
65
|
// Pipe-joined OR-group when the tab spans several types.
|
|
57
66
|
listingType: listingTypes.join("|"),
|
|
67
|
+
availability,
|
|
58
68
|
};
|
|
59
69
|
const { products, totalPages, page, isLoading } = useProducts(params, { initialData });
|
|
60
70
|
const commitSearch = useCallback(() => {
|
|
@@ -94,5 +104,5 @@ export function StoreProductsListing({ storeId, listingTypes = ["standard"], ini
|
|
|
94
104
|
}, [localCart, showToast]);
|
|
95
105
|
return (_jsxs(Div, { className: "min-h-[200px]", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search store products...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || "-createdAt", sortOptions: PRODUCT_PUBLIC_SORT_OPTIONS, onSortChange: (v) => {
|
|
96
106
|
table.set("sort", v);
|
|
97
|
-
}, view: view === "card" ? "grid" : "list", onViewChange: (v) => handleViewToggle(v === "grid" ? "card" : "list"), onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), _jsx(Div, { padding: "y-lg", children: isLoading ? (_jsx(Div, { layout: "grid", gap: "6", className: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-4", children: Array.from({ length: 8 }).map((_, i) => (_jsxs(Div, { className: "overflow-hidden animate-pulse", border: "subtle", rounded: "xl", children: [_jsx(Div, { className: "aspect-square", surface: "subtle" }), _jsxs(Stack, { className: `${__P.p3}`, gap: "sm", children: [_jsx(Div, { className: "h-3 w-3/4", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-3 w-1/2", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-4 w-1/3", surface: "subtle", rounded: "default" })] })] }, i))) })) : (_jsx(ProductGrid, { products: products, getProductHref: (p) => String(ROUTES.PUBLIC.PRODUCT_DETAIL(p.slug || p.id)), view: view, emptyLabel: "This store has no products yet.", onWishlistToggle: handleWishlistToggle, wishlistedIds: wishlistedIds, onAddToCart: handleAddToCart })) }), _jsx(FilterDrawer, { open: filterOpen, onOpen: openFilters, onClose: () => setFilterOpen(false), onApply: applyFilters, onReset: onFilterClear, activeCount: filterActiveCount, hideTrigger: true, children: _jsx(ProductFilters, { table: pendingTable, currencyPrefix: "\u20B9" }) }), _jsx(LoginRequiredModal, { isOpen: modalOpen, onClose: closeModal, message: modalMessage })] }));
|
|
107
|
+
}, view: view === "card" ? "grid" : "list", onViewChange: (v) => handleViewToggle(v === "grid" ? "card" : "list"), onResetAll: resetAll, hasActiveState: hasActiveState }), _jsx(Div, { padding: "y-sm", children: _jsx(AvailabilityTabs, { types: listingTypes }) }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), _jsx(Div, { padding: "y-lg", children: isLoading ? (_jsx(Div, { layout: "grid", gap: "6", className: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-4", children: Array.from({ length: 8 }).map((_, i) => (_jsxs(Div, { className: "overflow-hidden animate-pulse", border: "subtle", rounded: "xl", children: [_jsx(Div, { className: "aspect-square", surface: "subtle" }), _jsxs(Stack, { className: `${__P.p3}`, gap: "sm", children: [_jsx(Div, { className: "h-3 w-3/4", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-3 w-1/2", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-4 w-1/3", surface: "subtle", rounded: "default" })] })] }, i))) })) : (_jsx(ProductGrid, { products: products, getProductHref: (p) => String(ROUTES.PUBLIC.PRODUCT_DETAIL(p.slug || p.id)), view: view, emptyLabel: "This store has no products yet.", onWishlistToggle: handleWishlistToggle, wishlistedIds: wishlistedIds, onAddToCart: handleAddToCart })) }), _jsx(FilterDrawer, { open: filterOpen, onOpen: openFilters, onClose: () => setFilterOpen(false), onApply: applyFilters, onReset: onFilterClear, activeCount: filterActiveCount, hideTrigger: true, children: _jsx(ProductFilters, { table: pendingTable, currencyPrefix: "\u20B9" }) }), _jsx(LoginRequiredModal, { isOpen: modalOpen, onClose: closeModal, message: modalMessage })] }));
|
|
98
108
|
}
|
|
@@ -118,6 +118,12 @@ export class StoreRepository extends BaseRepository {
|
|
|
118
118
|
[STORE_FIELDS.STORE_CATEGORY]: { canFilter: true, canSort: false },
|
|
119
119
|
[STORE_FIELDS.STATUS]: { canFilter: true, canSort: false },
|
|
120
120
|
[STORE_FIELDS.IS_PUBLIC]: { canFilter: true, canSort: false },
|
|
121
|
+
// The public /stores toolbar has always emitted `isFeatured==true` for its
|
|
122
|
+
// "Featured" toggle, and the API allowlist has always accepted it — but it
|
|
123
|
+
// was absent from this map, so sievejs (`throwExceptions: false`) dropped
|
|
124
|
+
// the clause and the toggle did nothing at all. Root Cause #62's
|
|
125
|
+
// EMITTED_BUT_UNFILTERABLE, live in production.
|
|
126
|
+
[STORE_FIELDS.IS_FEATURED]: { canFilter: true, canSort: false },
|
|
121
127
|
[STORE_FIELDS.CREATED_AT]: { canFilter: false, canSort: true },
|
|
122
128
|
"stats.itemsSold": { canFilter: false, canSort: true },
|
|
123
129
|
"stats.averageRating": { canFilter: false, canSort: true },
|