@mohasinac/appkit 4.13.1 → 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 +1 -1
|
@@ -106,35 +106,35 @@ export declare const bundleQueryRuleSchema: z.ZodDiscriminatedUnion<"type", [z.Z
|
|
|
106
106
|
tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
107
107
|
listingType: z.ZodOptional<z.ZodEnum<["standard", "pre-order", "prize-draw"]>>;
|
|
108
108
|
}, "strip", z.ZodTypeAny, {
|
|
109
|
-
|
|
109
|
+
categorySlug?: string | undefined;
|
|
110
110
|
brandSlug?: string | undefined;
|
|
111
111
|
tags?: string[] | undefined;
|
|
112
|
-
categorySlug?: string | undefined;
|
|
113
|
-
}, {
|
|
114
112
|
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
113
|
+
}, {
|
|
114
|
+
categorySlug?: string | undefined;
|
|
115
115
|
brandSlug?: string | undefined;
|
|
116
116
|
tags?: string[] | undefined;
|
|
117
|
-
|
|
117
|
+
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
118
118
|
}>;
|
|
119
119
|
orderBy: z.ZodOptional<z.ZodEnum<["price-asc", "price-desc", "createdAt-desc"]>>;
|
|
120
120
|
limit: z.ZodNumber;
|
|
121
121
|
}, "strip", z.ZodTypeAny, {
|
|
122
122
|
type: "dynamic";
|
|
123
123
|
filter: {
|
|
124
|
-
|
|
124
|
+
categorySlug?: string | undefined;
|
|
125
125
|
brandSlug?: string | undefined;
|
|
126
126
|
tags?: string[] | undefined;
|
|
127
|
-
|
|
127
|
+
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
128
128
|
};
|
|
129
129
|
limit: number;
|
|
130
130
|
orderBy?: "price-asc" | "price-desc" | "createdAt-desc" | undefined;
|
|
131
131
|
}, {
|
|
132
132
|
type: "dynamic";
|
|
133
133
|
filter: {
|
|
134
|
-
|
|
134
|
+
categorySlug?: string | undefined;
|
|
135
135
|
brandSlug?: string | undefined;
|
|
136
136
|
tags?: string[] | undefined;
|
|
137
|
-
|
|
137
|
+
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
138
138
|
};
|
|
139
139
|
limit: number;
|
|
140
140
|
orderBy?: "price-asc" | "price-desc" | "createdAt-desc" | undefined;
|
|
@@ -260,35 +260,35 @@ export declare const categoryFirestoreSchema: z.ZodObject<{
|
|
|
260
260
|
tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
261
261
|
listingType: z.ZodOptional<z.ZodEnum<["standard", "pre-order", "prize-draw"]>>;
|
|
262
262
|
}, "strip", z.ZodTypeAny, {
|
|
263
|
-
|
|
263
|
+
categorySlug?: string | undefined;
|
|
264
264
|
brandSlug?: string | undefined;
|
|
265
265
|
tags?: string[] | undefined;
|
|
266
|
-
categorySlug?: string | undefined;
|
|
267
|
-
}, {
|
|
268
266
|
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
267
|
+
}, {
|
|
268
|
+
categorySlug?: string | undefined;
|
|
269
269
|
brandSlug?: string | undefined;
|
|
270
270
|
tags?: string[] | undefined;
|
|
271
|
-
|
|
271
|
+
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
272
272
|
}>;
|
|
273
273
|
orderBy: z.ZodOptional<z.ZodEnum<["price-asc", "price-desc", "createdAt-desc"]>>;
|
|
274
274
|
limit: z.ZodNumber;
|
|
275
275
|
}, "strip", z.ZodTypeAny, {
|
|
276
276
|
type: "dynamic";
|
|
277
277
|
filter: {
|
|
278
|
-
|
|
278
|
+
categorySlug?: string | undefined;
|
|
279
279
|
brandSlug?: string | undefined;
|
|
280
280
|
tags?: string[] | undefined;
|
|
281
|
-
|
|
281
|
+
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
282
282
|
};
|
|
283
283
|
limit: number;
|
|
284
284
|
orderBy?: "price-asc" | "price-desc" | "createdAt-desc" | undefined;
|
|
285
285
|
}, {
|
|
286
286
|
type: "dynamic";
|
|
287
287
|
filter: {
|
|
288
|
-
|
|
288
|
+
categorySlug?: string | undefined;
|
|
289
289
|
brandSlug?: string | undefined;
|
|
290
290
|
tags?: string[] | undefined;
|
|
291
|
-
|
|
291
|
+
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
292
292
|
};
|
|
293
293
|
limit: number;
|
|
294
294
|
orderBy?: "price-asc" | "price-desc" | "createdAt-desc" | undefined;
|
|
@@ -394,11 +394,10 @@ export declare const categoryFirestoreSchema: z.ZodObject<{
|
|
|
394
394
|
toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
|
|
395
395
|
}, z.ZodTypeAny, "passthrough">;
|
|
396
396
|
slug: string;
|
|
397
|
-
order: number;
|
|
398
|
-
position: number;
|
|
399
|
-
isFeatured: boolean;
|
|
400
397
|
isActive: boolean;
|
|
398
|
+
order: number;
|
|
401
399
|
createdBy: string;
|
|
400
|
+
isFeatured: boolean;
|
|
402
401
|
rootId: string;
|
|
403
402
|
tier: number;
|
|
404
403
|
isLeaf: boolean;
|
|
@@ -409,6 +408,7 @@ export declare const categoryFirestoreSchema: z.ZodObject<{
|
|
|
409
408
|
ogImage?: string | undefined;
|
|
410
409
|
canonicalUrl?: string | undefined;
|
|
411
410
|
};
|
|
411
|
+
position: number;
|
|
412
412
|
parentIds: string[];
|
|
413
413
|
isSearchable: boolean;
|
|
414
414
|
childrenIds: string[];
|
|
@@ -466,10 +466,10 @@ export declare const categoryFirestoreSchema: z.ZodObject<{
|
|
|
466
466
|
} | {
|
|
467
467
|
type: "dynamic";
|
|
468
468
|
filter: {
|
|
469
|
-
|
|
469
|
+
categorySlug?: string | undefined;
|
|
470
470
|
brandSlug?: string | undefined;
|
|
471
471
|
tags?: string[] | undefined;
|
|
472
|
-
|
|
472
|
+
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
473
473
|
};
|
|
474
474
|
limit: number;
|
|
475
475
|
orderBy?: "price-asc" | "price-desc" | "createdAt-desc" | undefined;
|
|
@@ -493,11 +493,10 @@ export declare const categoryFirestoreSchema: z.ZodObject<{
|
|
|
493
493
|
toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
|
|
494
494
|
}, z.ZodTypeAny, "passthrough">;
|
|
495
495
|
slug: string;
|
|
496
|
-
order: number;
|
|
497
|
-
position: number;
|
|
498
|
-
isFeatured: boolean;
|
|
499
496
|
isActive: boolean;
|
|
497
|
+
order: number;
|
|
500
498
|
createdBy: string;
|
|
499
|
+
isFeatured: boolean;
|
|
501
500
|
rootId: string;
|
|
502
501
|
tier: number;
|
|
503
502
|
isLeaf: boolean;
|
|
@@ -508,6 +507,7 @@ export declare const categoryFirestoreSchema: z.ZodObject<{
|
|
|
508
507
|
ogImage?: string | undefined;
|
|
509
508
|
canonicalUrl?: string | undefined;
|
|
510
509
|
};
|
|
510
|
+
position: number;
|
|
511
511
|
parentIds: string[];
|
|
512
512
|
isSearchable: boolean;
|
|
513
513
|
childrenIds: string[];
|
|
@@ -565,10 +565,10 @@ export declare const categoryFirestoreSchema: z.ZodObject<{
|
|
|
565
565
|
} | {
|
|
566
566
|
type: "dynamic";
|
|
567
567
|
filter: {
|
|
568
|
-
|
|
568
|
+
categorySlug?: string | undefined;
|
|
569
569
|
brandSlug?: string | undefined;
|
|
570
570
|
tags?: string[] | undefined;
|
|
571
|
-
|
|
571
|
+
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
572
572
|
};
|
|
573
573
|
limit: number;
|
|
574
574
|
orderBy?: "price-asc" | "price-desc" | "createdAt-desc" | undefined;
|
|
@@ -3,5 +3,20 @@ export interface ClassifiedDetailPageViewProps {
|
|
|
3
3
|
slug: string;
|
|
4
4
|
/** Pre-fetched product document — dedupes with generateMetadata() via React.cache(). */
|
|
5
5
|
initialProduct?: ProductDocument | null;
|
|
6
|
+
/**
|
|
7
|
+
* Render prop for offer UI, mounted inside the contact-seller panel.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately the SAME shape `ProductDetailPageView.renderOfferAction` uses,
|
|
10
|
+
* so both detail views share one contract and both consumer pages share one
|
|
11
|
+
* snippet. Called only when all three offer gates pass: `featureFlags.offers`,
|
|
12
|
+
* the classified type's `canMakeOffer` capability, and the seller's own
|
|
13
|
+
* `allowOffers` opt-in.
|
|
14
|
+
*/
|
|
15
|
+
renderOfferAction?: (opts: {
|
|
16
|
+
productId: string;
|
|
17
|
+
price: number;
|
|
18
|
+
currency: string;
|
|
19
|
+
minOfferPercent: number;
|
|
20
|
+
}) => React.ReactNode;
|
|
6
21
|
}
|
|
7
|
-
export declare function ClassifiedDetailPageView({ slug, initialProduct }: ClassifiedDetailPageViewProps): Promise<import("react").JSX.Element>;
|
|
22
|
+
export declare function ClassifiedDetailPageView({ slug, initialProduct, renderOfferAction }: ClassifiedDetailPageViewProps): Promise<import("react").JSX.Element>;
|
|
@@ -21,6 +21,9 @@ import { computeRelatedItems } from "../../../_internal/server/features/products
|
|
|
21
21
|
import { GroupedListingsCarousel } from "../../grouped/components/GroupedListingsCarousel";
|
|
22
22
|
import { getGroupsWithItemsForProduct } from "../../../_internal/server/features/grouped/data";
|
|
23
23
|
import { ClassifiedContactSellerPanel } from "./ClassifiedContactSellerPanel";
|
|
24
|
+
import { getSiteSettingsGlobal } from "../../admin/utils/getSiteSettingsGlobal";
|
|
25
|
+
import { canMakeOffer } from "../../../_internal/shared/listing-types/capabilities";
|
|
26
|
+
import { DEFAULT_MIN_OFFER_PERCENT } from "../../../_internal/shared/features/offers/config";
|
|
24
27
|
import { ListingBottomActions } from "../../products/components/ListingBottomActions";
|
|
25
28
|
function toDescriptionHtml(raw) {
|
|
26
29
|
if (!raw)
|
|
@@ -28,7 +31,7 @@ function toDescriptionHtml(raw) {
|
|
|
28
31
|
const s = typeof raw === "string" ? raw : JSON.stringify(raw);
|
|
29
32
|
return normalizeRichTextHtml(s);
|
|
30
33
|
}
|
|
31
|
-
export async function ClassifiedDetailPageView({ slug, initialProduct }) {
|
|
34
|
+
export async function ClassifiedDetailPageView({ slug, initialProduct, renderOfferAction }) {
|
|
32
35
|
const product = initialProduct !== undefined
|
|
33
36
|
? (initialProduct ?? undefined)
|
|
34
37
|
: await getClassifiedForDetail(slug).catch(() => undefined);
|
|
@@ -52,10 +55,19 @@ export async function ClassifiedDetailPageView({ slug, initialProduct }) {
|
|
|
52
55
|
const specs = Array.isArray(p.specifications) ? p.specifications : [];
|
|
53
56
|
const customSections = Array.isArray(p.customSections) ? p.customSections : [];
|
|
54
57
|
const descriptionHtml = toDescriptionHtml(p.description);
|
|
55
|
-
const [{ relatedItems, relatedByBrand, relatedByTags, relatedByStore }, groups] = await Promise.all([
|
|
58
|
+
const [{ relatedItems, relatedByBrand, relatedByTags, relatedByStore }, groups, siteSettings] = await Promise.all([
|
|
56
59
|
computeRelatedItems(product),
|
|
57
60
|
getGroupsWithItemsForProduct(product.id),
|
|
61
|
+
getSiteSettingsGlobal().catch(() => null),
|
|
58
62
|
]);
|
|
63
|
+
// Classifieds are the one non-standard type where haggling is the norm, so
|
|
64
|
+
// `canMakeOffer` is true for them — but the seller still opts in per listing
|
|
65
|
+
// (`allowOffers`, usually alongside `classified.negotiable`).
|
|
66
|
+
const offersAvailable = siteSettings?.featureFlags?.offers !== false &&
|
|
67
|
+
canMakeOffer("classified") &&
|
|
68
|
+
p.allowOffers === true &&
|
|
69
|
+
price !== null &&
|
|
70
|
+
!!renderOfferAction;
|
|
59
71
|
return (_jsxs(Main, { children: [_jsx(HistoryTracker, { productId: String(p.id ?? p.slug ?? ""), productType: "product", snapshot: {
|
|
60
72
|
title,
|
|
61
73
|
thumb: images[0],
|
|
@@ -66,5 +78,13 @@ export async function ClassifiedDetailPageView({ slug, initialProduct }) {
|
|
|
66
78
|
id: s.id,
|
|
67
79
|
label: s.title,
|
|
68
80
|
content: _jsx(CustomSectionTabContent, { section: s }),
|
|
69
|
-
})) })), renderBuyBar: () => (
|
|
81
|
+
})) })), renderBuyBar: () => (_jsxs(Stack, { id: "classified-contact-bar", className: "p-[var(--appkit-space-5)]", border: "subtle", gap: "md", rounded: "xl", surface: "muted", children: [offersAvailable &&
|
|
82
|
+
renderOfferAction({
|
|
83
|
+
productId: String(product.id),
|
|
84
|
+
price: price,
|
|
85
|
+
currency,
|
|
86
|
+
minOfferPercent: typeof p.minOfferPercent === "number"
|
|
87
|
+
? p.minOfferPercent
|
|
88
|
+
: DEFAULT_MIN_OFFER_PERCENT,
|
|
89
|
+
}), _jsx(ClassifiedContactSellerPanel, { productId: String(product.id), onContactSeller: startClassifiedConversationAction })] })), renderRelated: () => (_jsxs(Stack, { gap: "xl", children: [_jsx(GroupedListingsCarousel, { groups: groups }), _jsx(RelatedItemsSection, { relatedItems: relatedItems, relatedByBrand: relatedByBrand, relatedByTags: relatedByTags, relatedByStore: relatedByStore, categoryLabel: categoryName || category || undefined, brandLabel: brand, storeLabel: storeName ?? undefined })] })) }), _jsx(ListingBottomActions, { listingType: "classified", anchorId: "classified-contact-bar", price: price, currency: currency })] })] }));
|
|
70
90
|
}
|
|
@@ -5,22 +5,26 @@ import { sortBy } from "@mohasinac/appkit/client";
|
|
|
5
5
|
import React from "react";
|
|
6
6
|
import { FilterChipGroup, ListingLayout } from "../../../ui";
|
|
7
7
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
8
|
-
import { ADMIN_EVENT_STATUS_TABS } from "../../admin/constants/filter-tabs";
|
|
8
|
+
import { ADMIN_EVENT_STATUS_TABS, ALL_TAB } from "../../admin/constants/filter-tabs";
|
|
9
|
+
import { ALL_EVENT_TYPES, EVENT_TYPE_LABELS } from "../types";
|
|
9
10
|
import { toRecordArray, toRelativeDate, toStringValue, } from "../../admin/hooks/useAdminListingData";
|
|
10
11
|
import { DataListingView } from "../../admin/components/DataListingView";
|
|
11
12
|
import { AdminEventEditorView } from "./AdminEventEditorView";
|
|
12
13
|
import { ADMIN_BULK_ACTIONS, ROW_ACTION_META } from "../../products/constants/action-defs";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Derived from the `EventType` union (2026-08-24).
|
|
16
|
+
*
|
|
17
|
+
* The hand-written list this replaces offered `contest`, `giveaway` and
|
|
18
|
+
* `flash-sale` — none of which are `EventType` values, so each was fed straight
|
|
19
|
+
* into `sieveFilter("type", EQ, id)` and matched zero rows forever — while
|
|
20
|
+
* omitting five real types (`offer`, `feedback`, `raffle`, `spin_wheel`,
|
|
21
|
+
* `lottery`). It carried a TODO deferring the fix on the grounds of "avoid
|
|
22
|
+
* silently breaking saved-filter URLs"; that reasoning didn't hold, since a URL
|
|
23
|
+
* naming a dead id was already returning nothing (Root Cause #33 + #61).
|
|
24
|
+
*/
|
|
16
25
|
const TYPE_OPTIONS = [
|
|
17
|
-
|
|
18
|
-
{ id:
|
|
19
|
-
{ id: "giveaway", label: "Giveaway" },
|
|
20
|
-
{ id: "sale", label: "Sale" },
|
|
21
|
-
{ id: "poll", label: "Poll" },
|
|
22
|
-
{ id: "survey", label: "Survey" },
|
|
23
|
-
{ id: "flash-sale", label: "Flash Sale" },
|
|
26
|
+
ALL_TAB,
|
|
27
|
+
...ALL_EVENT_TYPES.map((type) => ({ id: type, label: EVENT_TYPE_LABELS[type] })),
|
|
24
28
|
];
|
|
25
29
|
export function AdminEventsView({ children, ...props }) {
|
|
26
30
|
if (React.Children.count(children) > 0) {
|
|
@@ -104,5 +104,13 @@ export declare function getEventSortOptions(variant: EventFilterVariant): Readon
|
|
|
104
104
|
export interface EventFiltersProps {
|
|
105
105
|
table: UrlTable;
|
|
106
106
|
variant?: EventFilterVariant;
|
|
107
|
+
/**
|
|
108
|
+
* Matching-row counts keyed by event type AND status value. Optional — when
|
|
109
|
+
* absent every facet renders uncounted and nothing is hidden, which is the
|
|
110
|
+
* pre-existing behaviour.
|
|
111
|
+
*/
|
|
112
|
+
counts?: Record<string, number | undefined>;
|
|
113
|
+
/** Drop facets whose count is 0. Requires `counts`. */
|
|
114
|
+
hideEmpty?: boolean;
|
|
107
115
|
}
|
|
108
|
-
export declare function EventFilters({ table, variant }: EventFiltersProps): import("react").JSX.Element;
|
|
116
|
+
export declare function EventFilters({ table, variant, counts, hideEmpty, }: EventFiltersProps): import("react").JSX.Element;
|
|
@@ -8,6 +8,25 @@ import { Div } from "../../../ui";
|
|
|
8
8
|
import { TABLE_KEYS } from "../../../constants/table-keys";
|
|
9
9
|
import { EVENT_FIELDS } from "../../../constants/field-names";
|
|
10
10
|
import { sortBy } from "../../../constants/sort";
|
|
11
|
+
import { ALL_EVENT_STATUSES, ALL_EVENT_TYPES, } from "../types";
|
|
12
|
+
/**
|
|
13
|
+
* `sale` -> `eventTypeSale`, `spin_wheel` -> `eventTypeSpinWheel`.
|
|
14
|
+
*
|
|
15
|
+
* Derived rather than a lookup map so a new union member cannot be silently
|
|
16
|
+
* label-less; a missing i18n key surfaces as the key itself, which is loud.
|
|
17
|
+
*/
|
|
18
|
+
function pascal(value) {
|
|
19
|
+
return value
|
|
20
|
+
.split("_")
|
|
21
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
22
|
+
.join("");
|
|
23
|
+
}
|
|
24
|
+
function eventTypeLabelKey(value) {
|
|
25
|
+
return `eventType${pascal(value)}`;
|
|
26
|
+
}
|
|
27
|
+
function eventStatusLabelKey(value) {
|
|
28
|
+
return `eventStatus${pascal(value)}`;
|
|
29
|
+
}
|
|
11
30
|
export const EVENT_FILTER_KEYS = {
|
|
12
31
|
admin: ["type", TABLE_KEYS.STATUS, TABLE_KEYS.DATE_FROM, TABLE_KEYS.DATE_TO],
|
|
13
32
|
seller: ["type", TABLE_KEYS.STATUS, TABLE_KEYS.DATE_FROM, TABLE_KEYS.DATE_TO],
|
|
@@ -48,27 +67,32 @@ export function getEventSortOptions(variant) {
|
|
|
48
67
|
return EVENT_PUBLIC_SORT_OPTIONS;
|
|
49
68
|
}
|
|
50
69
|
}
|
|
51
|
-
export function EventFilters({ table, variant = "admin" }) {
|
|
70
|
+
export function EventFilters({ table, variant = "admin", counts, hideEmpty = false, }) {
|
|
52
71
|
const t = useTranslations("filters");
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const adminStatusOptions =
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
];
|
|
72
|
+
// Derived from the unions, not hand-listed. The previous literals were
|
|
73
|
+
// missing `lottery` (type) and `cancelled` (admin status) — a facet that
|
|
74
|
+
// doesn't exist can never be selected, so those events were unfilterable
|
|
75
|
+
// (Root Cause #61).
|
|
76
|
+
const typeOptions = ALL_EVENT_TYPES.map((value) => ({
|
|
77
|
+
value,
|
|
78
|
+
label: t(eventTypeLabelKey(value)),
|
|
79
|
+
count: counts?.[value],
|
|
80
|
+
}));
|
|
81
|
+
const adminStatusOptions = ALL_EVENT_STATUSES.map((value) => ({
|
|
82
|
+
value,
|
|
83
|
+
label: t(eventStatusLabelKey(value)),
|
|
84
|
+
count: counts?.[value],
|
|
85
|
+
}));
|
|
86
|
+
// Deliberately narrower than the union: a shopper has no use for draft,
|
|
87
|
+
// paused or cancelled events, and the public list query only ever returns
|
|
88
|
+
// active ones anyway. Kept as an explicit subset of ALL_EVENT_STATUSES so it
|
|
89
|
+
// is a documented omission rather than another drifted literal.
|
|
90
|
+
const PUBLIC_STATUSES = ["active", "ended"];
|
|
91
|
+
const publicStatusOptions = PUBLIC_STATUSES.map((value) => ({
|
|
92
|
+
value,
|
|
93
|
+
label: t(eventStatusLabelKey(value)),
|
|
94
|
+
count: counts?.[value],
|
|
95
|
+
}));
|
|
72
96
|
const statusOptions = variant === "public" ? publicStatusOptions : adminStatusOptions;
|
|
73
97
|
const selectedType = table.get("type")
|
|
74
98
|
? table.get("type").split("|").filter(Boolean)
|
|
@@ -76,5 +100,5 @@ export function EventFilters({ table, variant = "admin" }) {
|
|
|
76
100
|
const selectedStatus = table.get("status")
|
|
77
101
|
? table.get("status").split("|").filter(Boolean)
|
|
78
102
|
: [];
|
|
79
|
-
return (_jsxs(Div, { children: [_jsx(FilterFacetSection, { title: t("type"), options: typeOptions, selected: selectedType, onChange: (vals) => table.set("type", vals.join("|")), searchable: false, defaultCollapsed: false }), _jsx(FilterFacetSection, { title: t("status"), options: statusOptions, selected: selectedStatus, onChange: (vals) => table.set("status", vals.join("|")), searchable: false, defaultCollapsed: false }), _jsx(RangeFilter, { title: t("dateRange"), type: "date", minValue: table.get("dateFrom"), maxValue: table.get("dateTo"), onMinChange: (v) => table.set("dateFrom", v), onMaxChange: (v) => table.set("dateTo", v), minPlaceholder: t("minDate"), maxPlaceholder: t("maxDate"), defaultCollapsed: true }), _jsx(SwitchFilter, { title: t("expired"), label: t("showExpiredOnly"), checked: table.get("showExpired") === "true", onChange: (v) => table.set("showExpired", v ? "true" : "") })] }));
|
|
103
|
+
return (_jsxs(Div, { children: [_jsx(FilterFacetSection, { title: t("type"), options: typeOptions, selected: selectedType, onChange: (vals) => table.set("type", vals.join("|")), searchable: false, defaultCollapsed: false, hideEmpty: hideEmpty }), _jsx(FilterFacetSection, { title: t("status"), options: statusOptions, selected: selectedStatus, onChange: (vals) => table.set("status", vals.join("|")), hideEmpty: hideEmpty, searchable: false, defaultCollapsed: false }), _jsx(RangeFilter, { title: t("dateRange"), type: "date", minValue: table.get("dateFrom"), maxValue: table.get("dateTo"), onMinChange: (v) => table.set("dateFrom", v), onMaxChange: (v) => table.set("dateTo", v), minPlaceholder: t("minDate"), maxPlaceholder: t("maxDate"), defaultCollapsed: true }), _jsx(SwitchFilter, { title: t("expired"), label: t("showExpiredOnly"), checked: table.get("showExpired") === "true", onChange: (v) => table.set("showExpired", v ? "true" : "") })] }));
|
|
80
104
|
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
export interface EventsIndexListingProps {
|
|
3
|
+
/**
|
|
4
|
+
* Event counts keyed by type AND status value, resolved server-side. Drives
|
|
5
|
+
* both the facet count badges and hiding facets that would return nothing.
|
|
6
|
+
*/
|
|
7
|
+
facetCounts?: Record<string, number | undefined>;
|
|
3
8
|
initialData?: any;
|
|
4
9
|
}
|
|
5
|
-
export declare function EventsIndexListing({ initialData }: EventsIndexListingProps): React.JSX.Element;
|
|
10
|
+
export declare function EventsIndexListing({ initialData, facetCounts }: EventsIndexListingProps): React.JSX.Element;
|
|
@@ -18,7 +18,7 @@ const __O = {
|
|
|
18
18
|
};
|
|
19
19
|
const PAGE_SIZE = 24;
|
|
20
20
|
const FILTER_KEYS = [TABLE_KEYS.TYPE, TABLE_KEYS.STATUS, TABLE_KEYS.DATE_FROM, TABLE_KEYS.DATE_TO, TABLE_KEYS.SHOW_EXPIRED];
|
|
21
|
-
export function EventsIndexListing({ initialData }) {
|
|
21
|
+
export function EventsIndexListing({ initialData, facetCounts }) {
|
|
22
22
|
const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: sortBy(EVENT_FIELDS.STARTS_AT, "ASC") } });
|
|
23
23
|
const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
|
|
24
24
|
const [filterOpen, setFilterOpen] = useState(false);
|
|
@@ -123,5 +123,5 @@ export function EventsIndexListing({ initialData }) {
|
|
|
123
123
|
}, [searchInput, table]);
|
|
124
124
|
return (_jsxs(Div, { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search events...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get(TABLE_KEYS.SORT) || sortBy(EVENT_FIELDS.STARTS_AT, "ASC"), sortOptions: EVENT_PUBLIC_SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, view: view, onViewChange: handleViewToggle, onResetAll: resetAll, hasActiveState: hasActiveState, toggles: [
|
|
125
125
|
{ label: "Show expired", active: showExpired, onChange: (next) => table.set(TABLE_KEYS.SHOW_EXPIRED, next ? "true" : "") },
|
|
126
|
-
] }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), _jsx(Div, { padding: "y-lg", children: isLoading ? (_jsx(Div, { layout: "grid", gap: "6", className: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3", children: Array.from({ length: 6 }).map((_, i) => (_jsxs(Div, { className: `${__O.hidden} animate-pulse`, border: "subtle", rounded: "xl", children: [_jsx(Div, { className: "aspect-video", surface: "subtle" }), _jsxs(Stack, { className: `${__P.p4}`, gap: "sm", children: [_jsx(Div, { className: "h-4 w-3/4", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-3 w-full", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-3 w-2/3", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-8 mt-2", surface: "subtle", rounded: "default" })] })] }, i))) })) : events.length === 0 ? (_jsx(Text, { paddingY: "3xl", color: "muted", size: "sm", align: "start", children: "No events found." })) : view === "list" ? (_jsx(Stack, { className: "divide-y divide-zinc-100 divide-[var(--appkit-color-border-subtle)]", border: "subtle", rounded: "xl", children: events.map((event) => (_jsx(EventCard, { event: event }, event.id))) })) : (_jsx(Div, { layout: "grid", gap: "6", className: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3", children: events.map((event) => (_jsx(EventCard, { event: event }, event.id))) })) }), _jsx(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearFilters, activeCount: activeFilterCount, children: _jsx(EventFilters, { table: pendingTable, variant: "public" }) })] }));
|
|
126
|
+
] }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), _jsx(Div, { padding: "y-lg", children: isLoading ? (_jsx(Div, { layout: "grid", gap: "6", className: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3", children: Array.from({ length: 6 }).map((_, i) => (_jsxs(Div, { className: `${__O.hidden} animate-pulse`, border: "subtle", rounded: "xl", children: [_jsx(Div, { className: "aspect-video", surface: "subtle" }), _jsxs(Stack, { className: `${__P.p4}`, gap: "sm", children: [_jsx(Div, { className: "h-4 w-3/4", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-3 w-full", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-3 w-2/3", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-8 mt-2", surface: "subtle", rounded: "default" })] })] }, i))) })) : events.length === 0 ? (_jsx(Text, { paddingY: "3xl", color: "muted", size: "sm", align: "start", children: "No events found." })) : view === "list" ? (_jsx(Stack, { className: "divide-y divide-zinc-100 divide-[var(--appkit-color-border-subtle)]", border: "subtle", rounded: "xl", children: events.map((event) => (_jsx(EventCard, { event: event }, event.id))) })) : (_jsx(Div, { layout: "grid", gap: "6", className: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3", children: events.map((event) => (_jsx(EventCard, { event: event }, event.id))) })) }), _jsx(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearFilters, activeCount: activeFilterCount, children: _jsx(EventFilters, { table: pendingTable, variant: "public", counts: facetCounts, hideEmpty: Boolean(facetCounts) }) })] }));
|
|
127
127
|
}
|
|
@@ -45,8 +45,17 @@ export async function EventsListPageView({ searchParams = {} }) {
|
|
|
45
45
|
const page = Number(sp(searchParams, "page")) || 1;
|
|
46
46
|
const pageSize = Number(sp(searchParams, "pageSize")) || 24;
|
|
47
47
|
const filters = buildEventFilters(searchParams);
|
|
48
|
-
const result = await
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
const [result, facetCounts] = await Promise.all([
|
|
49
|
+
eventRepository
|
|
50
|
+
.list({ filters, sorts: sort, page, pageSize })
|
|
51
|
+
.catch(() => null),
|
|
52
|
+
// Facet counts are deliberately NOT narrowed by the shopper's own type or
|
|
53
|
+
// status selection: a count that shrank to zero as you ticked boxes would
|
|
54
|
+
// hide the very facet you'd need to untick. They answer "does this kind of
|
|
55
|
+
// event exist at all", which is the question that decides visibility.
|
|
56
|
+
eventRepository
|
|
57
|
+
.facetCountsForTypesAndStatuses()
|
|
58
|
+
.catch(() => ({})),
|
|
59
|
+
]);
|
|
60
|
+
return (_jsx(Main, { children: _jsx(Section, { padding: "y-2xl", children: _jsxs(Container, { size: "xl", children: [_jsx(Heading, { level: 1, className: "mb-8", color: "primary", size: "3xl", weight: "semibold", children: "Events" }), _jsx(AdSlot, { id: "listing-sidebar-top", className: "mb-6" }), _jsx(EventsIndexListing, { initialData: result, facetCounts: facetCounts }), _jsx(AdSlot, { id: "listing-sidebar-bottom", className: "mt-8" })] }) }) }));
|
|
52
61
|
}
|
|
@@ -5,6 +5,23 @@ declare class EventRepository extends BaseRepository<EventDocument> {
|
|
|
5
5
|
static readonly SIEVE_FIELDS: FirebaseSieveFields;
|
|
6
6
|
constructor();
|
|
7
7
|
list(model: SieveModel): Promise<FirebaseSieveResult<EventDocument>>;
|
|
8
|
+
/**
|
|
9
|
+
* How many events exist per `type` and per `status` — the numbers behind the
|
|
10
|
+
* facet checkboxes, and what lets a type with no events disappear from the
|
|
11
|
+
* filter instead of offering a guaranteed-empty result.
|
|
12
|
+
*
|
|
13
|
+
* Events carry no store/category/brand FK (verified against `EventDocument`),
|
|
14
|
+
* so these counts are global by nature; `baseFilters` narrows them only when
|
|
15
|
+
* a surface wants a subset (e.g. the public page counting active events).
|
|
16
|
+
*
|
|
17
|
+
* Both fields are counted in ONE parallel batch — 13 `.count()` aggregations,
|
|
18
|
+
* no document reads.
|
|
19
|
+
*/
|
|
20
|
+
facetCountsForTypesAndStatuses(opts?: {
|
|
21
|
+
types?: readonly string[];
|
|
22
|
+
statuses?: readonly string[];
|
|
23
|
+
baseFilters?: string;
|
|
24
|
+
}): Promise<Record<string, number | undefined>>;
|
|
8
25
|
findBySlug(slug: string): Promise<EventDocument | null>;
|
|
9
26
|
findByIdOrSlug(idOrSlug: string): Promise<EventDocument | null>;
|
|
10
27
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DatabaseError } from "../../../errors";
|
|
2
2
|
import { serverLogger } from "../../../monitoring";
|
|
3
3
|
import { slugify } from "../../../utils";
|
|
4
|
+
import { ALL_EVENT_STATUSES, ALL_EVENT_TYPES } from "../types";
|
|
4
5
|
import { normalizeError } from "../../../errors/normalize";
|
|
5
6
|
import { BaseRepository, prepareForFirestore, parseSieveDateValue, } from "../../../providers/db-firebase";
|
|
6
7
|
import { EVENT_FIELDS, EVENTS_COLLECTION, } from "../schemas";
|
|
@@ -12,6 +13,32 @@ class EventRepository extends BaseRepository {
|
|
|
12
13
|
async list(model) {
|
|
13
14
|
return this.sieveQuery(model, EventRepository.SIEVE_FIELDS);
|
|
14
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* How many events exist per `type` and per `status` — the numbers behind the
|
|
18
|
+
* facet checkboxes, and what lets a type with no events disappear from the
|
|
19
|
+
* filter instead of offering a guaranteed-empty result.
|
|
20
|
+
*
|
|
21
|
+
* Events carry no store/category/brand FK (verified against `EventDocument`),
|
|
22
|
+
* so these counts are global by nature; `baseFilters` narrows them only when
|
|
23
|
+
* a surface wants a subset (e.g. the public page counting active events).
|
|
24
|
+
*
|
|
25
|
+
* Both fields are counted in ONE parallel batch — 13 `.count()` aggregations,
|
|
26
|
+
* no document reads.
|
|
27
|
+
*/
|
|
28
|
+
async facetCountsForTypesAndStatuses(opts) {
|
|
29
|
+
const types = opts?.types ?? ALL_EVENT_TYPES;
|
|
30
|
+
const statuses = opts?.statuses ?? ALL_EVENT_STATUSES;
|
|
31
|
+
const [typeCounts, statusCounts] = await Promise.all([
|
|
32
|
+
this.facetCounts(EVENT_FIELDS.TYPE, types, EventRepository.SIEVE_FIELDS, {
|
|
33
|
+
baseFilters: opts?.baseFilters,
|
|
34
|
+
}),
|
|
35
|
+
this.facetCounts(EVENT_FIELDS.STATUS, statuses, EventRepository.SIEVE_FIELDS, { baseFilters: opts?.baseFilters }),
|
|
36
|
+
]);
|
|
37
|
+
// Type and status values are disjoint, so one flat map is unambiguous and
|
|
38
|
+
// lets the filter component look either up by value without knowing which
|
|
39
|
+
// field it came from.
|
|
40
|
+
return { ...typeCounts, ...statusCounts };
|
|
41
|
+
}
|
|
15
42
|
async findBySlug(slug) {
|
|
16
43
|
return this.findOneBy(EVENT_FIELDS.SLUG, slug);
|
|
17
44
|
}
|
|
@@ -128,6 +128,17 @@ export declare const EVENT_FIELDS: {
|
|
|
128
128
|
readonly ENDED: EventStatus;
|
|
129
129
|
readonly CANCELLED: EventStatus;
|
|
130
130
|
};
|
|
131
|
+
/**
|
|
132
|
+
* Every `EventType`. `LOTTERY` was missing until 2026-08-24, which is why
|
|
133
|
+
* `events-seed-data.ts` — which imports EVENT_FIELDS from HERE, not from
|
|
134
|
+
* `constants/field-names.ts` — had to write `type: "lottery"` as a raw string
|
|
135
|
+
* literal while every other row used this map.
|
|
136
|
+
*
|
|
137
|
+
* NB. there are two `EVENT_FIELDS` constants (this one and the one in
|
|
138
|
+
* `constants/field-names.ts`) and they drifted independently. Same shape as
|
|
139
|
+
* the two competing `OrderStatus` types in Root Cause #36. Keep both in step
|
|
140
|
+
* with the `EventType` / `EventStatus` unions until one of them is retired.
|
|
141
|
+
*/
|
|
131
142
|
readonly TYPE_VALUES: {
|
|
132
143
|
readonly SALE: EventType;
|
|
133
144
|
readonly OFFER: EventType;
|
|
@@ -136,6 +147,7 @@ export declare const EVENT_FIELDS: {
|
|
|
136
147
|
readonly FEEDBACK: EventType;
|
|
137
148
|
readonly RAFFLE: EventType;
|
|
138
149
|
readonly SPIN_WHEEL: EventType;
|
|
150
|
+
readonly LOTTERY: EventType;
|
|
139
151
|
};
|
|
140
152
|
readonly STATS: {
|
|
141
153
|
readonly TOTAL_ENTRIES: "stats.totalEntries";
|
|
@@ -46,6 +46,17 @@ export const EVENT_FIELDS = {
|
|
|
46
46
|
ENDED: "ended",
|
|
47
47
|
CANCELLED: "cancelled",
|
|
48
48
|
},
|
|
49
|
+
/**
|
|
50
|
+
* Every `EventType`. `LOTTERY` was missing until 2026-08-24, which is why
|
|
51
|
+
* `events-seed-data.ts` — which imports EVENT_FIELDS from HERE, not from
|
|
52
|
+
* `constants/field-names.ts` — had to write `type: "lottery"` as a raw string
|
|
53
|
+
* literal while every other row used this map.
|
|
54
|
+
*
|
|
55
|
+
* NB. there are two `EVENT_FIELDS` constants (this one and the one in
|
|
56
|
+
* `constants/field-names.ts`) and they drifted independently. Same shape as
|
|
57
|
+
* the two competing `OrderStatus` types in Root Cause #36. Keep both in step
|
|
58
|
+
* with the `EventType` / `EventStatus` unions until one of them is retired.
|
|
59
|
+
*/
|
|
49
60
|
TYPE_VALUES: {
|
|
50
61
|
SALE: "sale",
|
|
51
62
|
OFFER: "offer",
|
|
@@ -54,6 +65,7 @@ export const EVENT_FIELDS = {
|
|
|
54
65
|
FEEDBACK: "feedback",
|
|
55
66
|
RAFFLE: "raffle",
|
|
56
67
|
SPIN_WHEEL: "spin_wheel",
|
|
68
|
+
LOTTERY: "lottery",
|
|
57
69
|
},
|
|
58
70
|
STATS: {
|
|
59
71
|
TOTAL_ENTRIES: "stats.totalEntries",
|