@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
|
@@ -10,6 +10,14 @@
|
|
|
10
10
|
* primitive and stay in sync when statuses are added.
|
|
11
11
|
*/
|
|
12
12
|
export const ALL_TAB = { id: "All", label: "All" };
|
|
13
|
+
// COVERAGE (2026-08-24): `audit-filter-tab-enums` gained a check that every
|
|
14
|
+
// value of the backing enum HAS a chip, not just that every chip is a real
|
|
15
|
+
// value. It immediately found ten gaps across the seller sets — `in_review`
|
|
16
|
+
// (where a submission waits on admin approval, arguably the state a seller most
|
|
17
|
+
// wants to filter for), `archived`, `returned`, and the offer states
|
|
18
|
+
// `countered` / `withdrawn` / `paid`. Rows in those states were visible under
|
|
19
|
+
// "All" and isolatable by nothing. All ten now have chips; anything genuinely
|
|
20
|
+
// not worth a chip goes in that audit entry's `omit` list with a reason.
|
|
13
21
|
/** Admin > Products — listing status filter chip set. Real `ProductStatus`
|
|
14
22
|
* is draft|published|in_review|archived — "pending" fixed to "in_review"
|
|
15
23
|
* (its real meaning); the previous id never matched any document. */
|
|
@@ -105,12 +113,17 @@ export const ADMIN_AUDIT_LOG_ACTION_TABS = [
|
|
|
105
113
|
export const ADMIN_ORDER_STATUS_TABS = [
|
|
106
114
|
ALL_TAB,
|
|
107
115
|
{ id: "pending", label: "Pending" },
|
|
116
|
+
// `confirmed` and `returned` were both missing until 2026-08-24 even though
|
|
117
|
+
// both are real `OrderStatusValues` an order reaches — so an admin could see
|
|
118
|
+
// such an order in the All tab and had no chip that would isolate it.
|
|
119
|
+
{ id: "confirmed", label: "Confirmed" },
|
|
108
120
|
{ id: "processing", label: "Processing" },
|
|
109
121
|
{ id: "shipped", label: "Shipped" },
|
|
110
122
|
{ id: "delivered", label: "Delivered" },
|
|
111
123
|
{ id: "cancelled", label: "Cancelled" },
|
|
112
124
|
{ id: "refunded", label: "Refunded" },
|
|
113
125
|
{ id: "return_requested", label: "Return Requested" },
|
|
126
|
+
{ id: "returned", label: "Returned" },
|
|
114
127
|
];
|
|
115
128
|
/**
|
|
116
129
|
* Admin > Orders — manual-payment (cash / UPI / EMI) review queue.
|
|
@@ -177,11 +190,19 @@ export const ADMIN_EVENT_ENTRY_STATUS_TABS = [
|
|
|
177
190
|
* feature's own events/types/index.ts). A "Published" chip previously
|
|
178
191
|
* returned zero rows every time — removed rather than aliased since
|
|
179
192
|
* "Active" already covers the intended meaning. */
|
|
193
|
+
/**
|
|
194
|
+
* Every `EventStatus`, not a subset. `paused` and `cancelled` were missing
|
|
195
|
+
* until 2026-08-24 — a real status with no chip is unreachable, and
|
|
196
|
+
* `audit-filter-tab-enums` never caught it because that audit only checks the
|
|
197
|
+
* reverse (that no chip names a DEAD value).
|
|
198
|
+
*/
|
|
180
199
|
export const ADMIN_EVENT_STATUS_TABS = [
|
|
181
200
|
ALL_TAB,
|
|
182
201
|
{ id: "draft", label: "Draft" },
|
|
183
202
|
{ id: "active", label: "Active" },
|
|
203
|
+
{ id: "paused", label: "Paused" },
|
|
184
204
|
{ id: "ended", label: "Ended" },
|
|
205
|
+
{ id: "cancelled", label: "Cancelled" },
|
|
185
206
|
];
|
|
186
207
|
/** Admin > Scammers — scammer profile status filter chip set. */
|
|
187
208
|
export const ADMIN_SCAMMER_STATUS_TABS = [
|
|
@@ -242,6 +263,7 @@ export const SELLER_PRODUCT_STATUS_TABS = [
|
|
|
242
263
|
{ id: "published", label: "Active" },
|
|
243
264
|
{ id: "draft", label: "Draft" },
|
|
244
265
|
{ id: "archived", label: "Archived" },
|
|
266
|
+
{ id: "in_review", label: "In Review" },
|
|
245
267
|
];
|
|
246
268
|
/** Seller > Auctions — auction-state filter chip set. Real `ProductStatus`
|
|
247
269
|
* has no "active"/"ended"/"cancelled" values. "Active" fixed to
|
|
@@ -257,6 +279,8 @@ export const SELLER_AUCTION_STATUS_TABS = [
|
|
|
257
279
|
ALL_TAB,
|
|
258
280
|
{ id: "published", label: "Active" },
|
|
259
281
|
{ id: "draft", label: "Draft" },
|
|
282
|
+
{ id: "in_review", label: "In Review" },
|
|
283
|
+
{ id: "archived", label: "Archived" },
|
|
260
284
|
];
|
|
261
285
|
/** Seller > Pre-orders — pre-order-state filter chip set. Same root cause
|
|
262
286
|
* and fix as SELLER_AUCTION_STATUS_TABS above — no "active"/"cancelled"
|
|
@@ -267,6 +291,7 @@ export const SELLER_PRE_ORDER_STATUS_TABS = [
|
|
|
267
291
|
{ id: "published", label: "Active" },
|
|
268
292
|
{ id: "draft", label: "Draft" },
|
|
269
293
|
{ id: "archived", label: "Archived" },
|
|
294
|
+
{ id: "in_review", label: "In Review" },
|
|
270
295
|
];
|
|
271
296
|
/** Seller > Prize Draws — draw-state filter chip set. Same root cause and
|
|
272
297
|
* fix as SELLER_AUCTION_STATUS_TABS — "ended" is derived from
|
|
@@ -276,6 +301,8 @@ export const SELLER_PRIZE_DRAW_STATUS_TABS = [
|
|
|
276
301
|
ALL_TAB,
|
|
277
302
|
{ id: "published", label: "Active" },
|
|
278
303
|
{ id: "draft", label: "Draft" },
|
|
304
|
+
{ id: "in_review", label: "In Review" },
|
|
305
|
+
{ id: "archived", label: "Archived" },
|
|
279
306
|
];
|
|
280
307
|
/** Seller > Orders — order-state filter chip set. Subset of
|
|
281
308
|
* `ADMIN_ORDER_STATUS_TABS` — sellers don't see `RETURN_REQUESTED` until
|
|
@@ -286,11 +313,36 @@ export const SELLER_PRIZE_DRAW_STATUS_TABS = [
|
|
|
286
313
|
export const SELLER_ORDER_STATUS_TABS = [
|
|
287
314
|
ALL_TAB,
|
|
288
315
|
{ id: "pending", label: "Pending" },
|
|
316
|
+
// `confirmed` is settable from SellerOrdersView's own Update-Status dropdown
|
|
317
|
+
// but had no chip here, so a seller could move an order into a state they
|
|
318
|
+
// could then never filter for. `return_requested` was excluded on the theory
|
|
319
|
+
// that sellers never see one — they do, it is the state a buyer's return
|
|
320
|
+
// request lands in and the seller is the one who has to act on it.
|
|
321
|
+
{ id: "confirmed", label: "Confirmed" },
|
|
289
322
|
{ id: "processing", label: "Processing" },
|
|
290
323
|
{ id: "shipped", label: "Shipped" },
|
|
291
324
|
{ id: "delivered", label: "Delivered" },
|
|
292
325
|
{ id: "cancelled", label: "Cancelled" },
|
|
293
326
|
{ id: "refunded", label: "Refunded" },
|
|
327
|
+
{ id: "return_requested", label: "Return Requested" },
|
|
328
|
+
{ id: "returned", label: "Returned" },
|
|
329
|
+
];
|
|
330
|
+
/**
|
|
331
|
+
* Admin > Offers — the FULL `OfferStatus` union, unlike the seller variant
|
|
332
|
+
* below, which deliberately surfaces only the four states a seller acts on.
|
|
333
|
+
* An admin is auditing the whole lifecycle, so `countered`, `withdrawn` and
|
|
334
|
+
* `paid` all need to be reachable. Cross-checked against the real union by
|
|
335
|
+
* `audit-filter-tab-enums`.
|
|
336
|
+
*/
|
|
337
|
+
export const ADMIN_OFFER_STATUS_TABS = [
|
|
338
|
+
ALL_TAB,
|
|
339
|
+
{ id: "pending", label: "Pending" },
|
|
340
|
+
{ id: "countered", label: "Countered" },
|
|
341
|
+
{ id: "accepted", label: "Accepted" },
|
|
342
|
+
{ id: "paid", label: "Paid" },
|
|
343
|
+
{ id: "declined", label: "Declined" },
|
|
344
|
+
{ id: "expired", label: "Expired" },
|
|
345
|
+
{ id: "withdrawn", label: "Withdrawn" },
|
|
294
346
|
];
|
|
295
347
|
/** Seller > Offers — offer-state filter chip set. Real `OfferStatus` is
|
|
296
348
|
* pending|accepted|declined|countered|expired|withdrawn|paid — there is no
|
|
@@ -303,6 +355,9 @@ export const SELLER_OFFER_STATUS_TABS = [
|
|
|
303
355
|
{ id: "accepted", label: "Accepted" },
|
|
304
356
|
{ id: "declined", label: "Rejected" },
|
|
305
357
|
{ id: "expired", label: "Expired" },
|
|
358
|
+
{ id: "countered", label: "Countered" },
|
|
359
|
+
{ id: "withdrawn", label: "Withdrawn" },
|
|
360
|
+
{ id: "paid", label: "Paid" },
|
|
306
361
|
];
|
|
307
362
|
/** Seller > Bids — bid-state filter chip set. Uses the empty-sentinel
|
|
308
363
|
* variant (see `EMPTY_TAB`). */
|
|
@@ -275,15 +275,82 @@ export interface SiteSettingsTheme {
|
|
|
275
275
|
/** Theme id applied when the user's resolved mode is `"dark"`. */
|
|
276
276
|
defaultDarkThemeId?: string;
|
|
277
277
|
}
|
|
278
|
+
/** Third-party analytics/tag IDs. Public by nature — they ship in page markup. */
|
|
279
|
+
export interface SiteSettingsIntegrations {
|
|
280
|
+
googleAnalyticsId?: string;
|
|
281
|
+
facebookPixelId?: string;
|
|
282
|
+
gtmContainerId?: string;
|
|
283
|
+
}
|
|
284
|
+
/** Admin-tunable platform caps. Enforced server-side; not buyer-facing. */
|
|
285
|
+
export interface SiteSettingsPlatformLimits {
|
|
286
|
+
maxProductsPerStore?: number;
|
|
287
|
+
maxImagesPerProduct?: number;
|
|
288
|
+
maxVideoSizeMb?: number;
|
|
289
|
+
maxCustomFieldsPerProduct?: number;
|
|
290
|
+
maxCustomSectionsPerProduct?: number;
|
|
291
|
+
orderCancellationWindowHours?: number;
|
|
292
|
+
}
|
|
293
|
+
/** Embedded in siteSettings.adSettings — a type alias, not a collection root. */
|
|
294
|
+
export type SiteSettingsAdPlacement = {
|
|
295
|
+
id: string;
|
|
296
|
+
label: string;
|
|
297
|
+
enabled: boolean;
|
|
298
|
+
reservedHeight: number;
|
|
299
|
+
};
|
|
300
|
+
/** Embedded in siteSettings.adSettings — a type alias, not a collection root. */
|
|
301
|
+
export type SiteSettingsAdInventoryItem = {
|
|
302
|
+
id: string;
|
|
303
|
+
name: string;
|
|
304
|
+
provider: "manual" | "adsense" | "thirdParty";
|
|
305
|
+
status: "draft" | "active" | "scheduled" | "paused";
|
|
306
|
+
placementIds: string[];
|
|
307
|
+
requiresConsent: boolean;
|
|
308
|
+
priority: number;
|
|
309
|
+
startAt?: string;
|
|
310
|
+
endAt?: string;
|
|
311
|
+
createdAt: string;
|
|
312
|
+
updatedAt: string;
|
|
313
|
+
updatedBy: string;
|
|
314
|
+
creative: {
|
|
315
|
+
title?: string;
|
|
316
|
+
body?: string;
|
|
317
|
+
imageUrl?: string;
|
|
318
|
+
ctaLabel?: string;
|
|
319
|
+
ctaHref?: string;
|
|
320
|
+
adsenseSlot?: string;
|
|
321
|
+
thirdPartyUrl?: string;
|
|
322
|
+
};
|
|
323
|
+
};
|
|
324
|
+
/**
|
|
325
|
+
* Ad inventory + provider config.
|
|
326
|
+
*
|
|
327
|
+
* `providerCredentials` is masked by `GET /api/admin/ads` and must never be
|
|
328
|
+
* returned by a public endpoint; `inventory` holds draft/paused/scheduled
|
|
329
|
+
* entries that `GET /api/ads` deliberately filters out. Both are therefore in
|
|
330
|
+
* `PRIVATE_SITE_SETTINGS_FIELDS` — the whole group is server-side only.
|
|
331
|
+
*/
|
|
332
|
+
export interface SiteSettingsAdSettings {
|
|
333
|
+
consentRequired: boolean;
|
|
334
|
+
placements: readonly SiteSettingsAdPlacement[];
|
|
335
|
+
providerCredentials: {
|
|
336
|
+
adsenseClientId: string;
|
|
337
|
+
thirdPartyScriptUrl: string;
|
|
338
|
+
};
|
|
339
|
+
inventory: SiteSettingsAdInventoryItem[];
|
|
340
|
+
}
|
|
278
341
|
export interface SiteSettingsDocument extends BaseDocument {
|
|
279
342
|
id: "global";
|
|
280
343
|
siteName: string;
|
|
344
|
+
/** Short strapline shown beside the site name in admin chrome. */
|
|
345
|
+
tagline?: string;
|
|
281
346
|
motto: string;
|
|
282
347
|
logo: {
|
|
283
348
|
url: string;
|
|
284
349
|
alt: string;
|
|
285
350
|
format: "svg" | "png";
|
|
286
351
|
};
|
|
352
|
+
/** Favicon URL. Distinct from `logo.url`, which is the wordmark. */
|
|
353
|
+
favicon?: string;
|
|
287
354
|
background: {
|
|
288
355
|
light: {
|
|
289
356
|
type: "color" | "gradient" | "image" | "video";
|
|
@@ -452,6 +519,19 @@ export interface SiteSettingsDocument extends BaseDocument {
|
|
|
452
519
|
notifications: boolean;
|
|
453
520
|
sellerRegistration: boolean;
|
|
454
521
|
preOrders: boolean;
|
|
522
|
+
/**
|
|
523
|
+
* Buyer price negotiation (Make an Offer / counter-offer).
|
|
524
|
+
*
|
|
525
|
+
* The global kill switch. Per-listing opt-in still applies on top of it via
|
|
526
|
+
* `ProductDocument.allowOffers`, and only certain listing types support
|
|
527
|
+
* offers at all (`LISTING_TYPE_CAPABILITIES.canMakeOffer`) — a product needs
|
|
528
|
+
* all three to show the CTA.
|
|
529
|
+
*
|
|
530
|
+
* Guards NEW offers only. Switching it off must not strand in-flight ones:
|
|
531
|
+
* sellers keep responding, buyers keep checking out accepted offers, and
|
|
532
|
+
* both dashboards stay reachable.
|
|
533
|
+
*/
|
|
534
|
+
offers: boolean;
|
|
455
535
|
/** When true, admin users see a bypass button in checkout that skips OTP and payment. Server-enforced. */
|
|
456
536
|
adminCheckoutBypass?: boolean;
|
|
457
537
|
listingTypes?: {
|
|
@@ -471,11 +551,26 @@ export interface SiteSettingsDocument extends BaseDocument {
|
|
|
471
551
|
bundle?: boolean;
|
|
472
552
|
};
|
|
473
553
|
};
|
|
554
|
+
/**
|
|
555
|
+
* Admin-authored HTML overrides for the public policy pages. When a key holds
|
|
556
|
+
* a non-empty string, `PolicyPageView` renders it instead of the i18n
|
|
557
|
+
* `sections[]` fallback for that page.
|
|
558
|
+
*
|
|
559
|
+
* These key names are load-bearing — they must match `POLICY_META[*].firestoreField`
|
|
560
|
+
* in `features/about/components/PolicyPageView.tsx` (read side) and the
|
|
561
|
+
* `legalPages` payload built by `AdminSiteSettingsView` (write side). Until
|
|
562
|
+
* 2026-08-24 this type declared `termsOfService`/`privacyPolicy`/`shippingPolicy`,
|
|
563
|
+
* three names that neither side ever used; the read path went through an
|
|
564
|
+
* `as any` cast, so `tsc` never caught the drift (Root Cause #38 family).
|
|
565
|
+
*/
|
|
474
566
|
legalPages: {
|
|
475
|
-
|
|
476
|
-
|
|
567
|
+
terms: string;
|
|
568
|
+
privacy: string;
|
|
569
|
+
cookies: string;
|
|
477
570
|
refundPolicy: string;
|
|
478
|
-
|
|
571
|
+
shipping: string;
|
|
572
|
+
ethics: string;
|
|
573
|
+
codeOfConduct: string;
|
|
479
574
|
};
|
|
480
575
|
shipping: {
|
|
481
576
|
estimatedDays: number;
|
|
@@ -508,9 +603,21 @@ export interface SiteSettingsDocument extends BaseDocument {
|
|
|
508
603
|
};
|
|
509
604
|
newsletterEnabled?: boolean;
|
|
510
605
|
};
|
|
606
|
+
/**
|
|
607
|
+
* `message` is canonical — it is what `AnnouncementBar` and the homepage
|
|
608
|
+
* read. `AdminSiteSettingsView` used to write the text under a `text` key
|
|
609
|
+
* instead, so anything typed in the main Site Settings editor was saved and
|
|
610
|
+
* never displayed; `link`/`backgroundColor` were collected and had no
|
|
611
|
+
* renderer at all. Unified on `message` 2026-08-24 (migration
|
|
612
|
+
* `scripts/migrate-settings-wiring.mjs` copies any stray `text` across).
|
|
613
|
+
*/
|
|
511
614
|
announcementBar?: {
|
|
512
615
|
enabled: boolean;
|
|
513
616
|
message: string;
|
|
617
|
+
/** Optional destination — renders the message as a link. */
|
|
618
|
+
link?: string;
|
|
619
|
+
/** Optional CSS colour override for the bar background. */
|
|
620
|
+
backgroundColor?: string;
|
|
514
621
|
};
|
|
515
622
|
/**
|
|
516
623
|
* Image watermark configuration applied by the `/api/media/[...slug]` CDN
|
|
@@ -544,6 +651,18 @@ export interface SiteSettingsDocument extends BaseDocument {
|
|
|
544
651
|
};
|
|
545
652
|
/** Encrypted provider credentials � never return raw to the client. */
|
|
546
653
|
credentials?: SiteSettingsCredentials;
|
|
654
|
+
/**
|
|
655
|
+
* These three were written by `AdminSiteSettingsView.buildFullPayload()` and
|
|
656
|
+
* read back by it, but were never declared here. Being absent from the type
|
|
657
|
+
* meant no type-driven check could see them — and the public site-settings
|
|
658
|
+
* deny-list, which strips named fields off a spread, shipped all three to
|
|
659
|
+
* anonymous callers by default (`adSettings.providerCredentials` unmasked,
|
|
660
|
+
* plus every draft/paused ad). Declared 2026-08-24 so they are visible to
|
|
661
|
+
* `audit-public-projection-parity`.
|
|
662
|
+
*/
|
|
663
|
+
integrations?: SiteSettingsIntegrations;
|
|
664
|
+
platformLimits?: SiteSettingsPlatformLimits;
|
|
665
|
+
adSettings?: SiteSettingsAdSettings;
|
|
547
666
|
/**
|
|
548
667
|
* Theme color overrides — injected as CSS custom properties by LayoutShellClient.
|
|
549
668
|
* Keys map to --appkit-color-* variables (e.g. primary → --appkit-color-primary).
|
|
@@ -241,6 +241,7 @@ export const DEFAULT_SITE_SETTINGS_DATA = {
|
|
|
241
241
|
notifications: true,
|
|
242
242
|
sellerRegistration: true,
|
|
243
243
|
preOrders: true,
|
|
244
|
+
offers: true,
|
|
244
245
|
// W1-37 2026-05-23 — Phase 2 listing types enabled by default; all per-type
|
|
245
246
|
// surfaces (seller + admin via W1-29 + public) are now shipped.
|
|
246
247
|
listingTypes: {
|
|
@@ -14,16 +14,31 @@ export interface BuyNowAuctionInput {
|
|
|
14
14
|
}
|
|
15
15
|
export interface BuyNowAuctionResult {
|
|
16
16
|
/**
|
|
17
|
-
* Buy-Now
|
|
18
|
-
*
|
|
19
|
-
* completes
|
|
20
|
-
*
|
|
21
|
-
*
|
|
17
|
+
* Buy-Now creates neither an order nor a sale. It places a real BID at the
|
|
18
|
+
* listing's buy-now price and writes a LOCKED CART LINE pointing at it; the
|
|
19
|
+
* buyer then completes a normal order through the auction checkout lane, and
|
|
20
|
+
* only THAT closes the auction (see `claimAuctionForCheckout`).
|
|
21
|
+
*
|
|
22
|
+
* Two earlier shapes were both wrong. The original created an order document
|
|
23
|
+
* no orders UI could render and no payment path could reach (see
|
|
24
|
+
* auctionSettlement.ts). Its replacement wrote a locked cart line with no
|
|
25
|
+
* `bidId`, which every downstream sweep filters on — so the line could never
|
|
26
|
+
* lapse, could never be removed (it is `locked: true`), and permanently
|
|
27
|
+
* blocked the buyer's other two lanes.
|
|
28
|
+
*
|
|
29
|
+
* The auction itself is deliberately left ALONE here. It keeps running, keeps
|
|
30
|
+
* taking bids, and keeps accepting other buyouts. Nothing is sold until
|
|
31
|
+
* somebody pays, and which of several racing buyers that is gets decided by a
|
|
32
|
+
* transaction at order time rather than by a first-come lock here.
|
|
22
33
|
*/
|
|
23
34
|
cartLocked: true;
|
|
24
35
|
productId: string;
|
|
25
36
|
amount: number;
|
|
26
37
|
currency: string;
|
|
38
|
+
/** The bid placed at the buy-now price. Won only once the order completes. */
|
|
39
|
+
bidId: string;
|
|
40
|
+
/** When this claim lapses — 1h, clamped to the auction's own end time. */
|
|
41
|
+
checkoutDeadline: Date;
|
|
27
42
|
/** Where to send the buyer to actually pay. */
|
|
28
43
|
checkoutUrl: string;
|
|
29
44
|
}
|
|
@@ -17,7 +17,7 @@ import { storeRepository } from "../../stores/repository/store.repository";
|
|
|
17
17
|
import { siteSettingsRepository } from "../../../repositories";
|
|
18
18
|
import { getAdminRealtimeDb } from "../../../providers/db-firebase";
|
|
19
19
|
import { maskPublicBid } from "../../../security";
|
|
20
|
-
import { resolveMinBid, resolveMinBidIncrement } from "../../../_internal/shared/features/auctions/config";
|
|
20
|
+
import { isBuyNowAvailable, resolveMinBid, resolveMinBidIncrement, } from "../../../_internal/shared/features/auctions/config";
|
|
21
21
|
import { sendNotification } from "../../admin/actions/notification-actions";
|
|
22
22
|
import { BID_MESSAGES } from "../../../_internal/server/jobs/handlers/messages";
|
|
23
23
|
import { ERROR_MESSAGES, AuthorizationError, ValidationError, NotFoundError, } from "../../../errors";
|
|
@@ -25,13 +25,7 @@ import { BID_ERROR_CODES } from "../../../errors/error-codes";
|
|
|
25
25
|
import { increment } from "../../../contracts/field-ops";
|
|
26
26
|
import { getDefaultCurrency } from "../../../core/baseline-resolver";
|
|
27
27
|
import { cartRepository } from "../../cart/repository/cart.repository";
|
|
28
|
-
import {
|
|
29
|
-
import { CART_LANE, LANE_CHECKOUT_WINDOW_MS } from "../../../_internal/shared/checkout/lanes";
|
|
30
|
-
/**
|
|
31
|
-
* Buy-Now and auction settlement give the buyer the same 48h window to pay for
|
|
32
|
-
* a locked line. Kept identical on purpose — both are "you now owe this".
|
|
33
|
-
*/
|
|
34
|
-
const AUCTION_CHECKOUT_WINDOW_MS = LANE_CHECKOUT_WINDOW_MS.auction;
|
|
28
|
+
import { AUCTION_BUYOUT_WINDOW_MINUTES, AUCTION_BUYOUT_WINDOW_MS, AUCTION_CHECKOUT_URL, } from "../../../_internal/shared/checkout/lanes";
|
|
35
29
|
import { resolveDate } from "../../../utils";
|
|
36
30
|
// --- Domain Functions ----------------------------------------------------------
|
|
37
31
|
export async function placeBid(userId, userEmail, input) {
|
|
@@ -260,17 +254,62 @@ export async function buyNowAuction(userId, userName, userEmail, input) {
|
|
|
260
254
|
if (buyNowPrice === null || buyNowPrice <= 0) {
|
|
261
255
|
throw new ValidationError(ERROR_MESSAGES.BID.BUY_NOW_NO_PRICE, { code: BID_ERROR_CODES.BUY_NOW_NO_PRICE });
|
|
262
256
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
await
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
257
|
+
// The standing price this buyout has to beat. Read from the bids as well as
|
|
258
|
+
// the product because `product.currentBid` is a denormalised mirror, and a
|
|
259
|
+
// pending buyout deliberately never writes to it (see BidDocument.isBuyout) —
|
|
260
|
+
// so the bids are the authority here and buyout bids are excluded from it.
|
|
261
|
+
const activeBids = await bidRepository.getActiveByProduct(productId);
|
|
262
|
+
const standingBid = Math.max(product.currentBid ?? 0, ...activeBids.filter((e) => e.data.isBuyout !== true).map((e) => e.data.bidAmount ?? 0), 0);
|
|
263
|
+
// Replaces the old `bidsHaveStarted` gate. Buy Now used to vanish the instant
|
|
264
|
+
// anybody bid, eBay-style, which hid it on almost every real auction. What
|
|
265
|
+
// actually matters is whether it is still a better deal than the bidding.
|
|
266
|
+
if (!isBuyNowAvailable({ buyNowPrice, currentBid: standingBid, isEnded: false, isSold: product.isSold })) {
|
|
267
|
+
throw new ValidationError(ERROR_MESSAGES.BID.BUY_NOW_UNAVAILABLE, {
|
|
268
|
+
code: BID_ERROR_CODES.BUY_NOW_UNAVAILABLE,
|
|
272
269
|
});
|
|
270
|
+
}
|
|
271
|
+
// Idempotency, NOT exclusivity. Re-clicking Buy Now (or a double submit) must
|
|
272
|
+
// not stack a second hold on the same buyer — but a DIFFERENT buyer holding
|
|
273
|
+
// one is fine and deliberate: whoever pays first gets it.
|
|
274
|
+
const existingHold = activeBids.find((e) => e.data.isBuyout === true && e.data.userId === userId);
|
|
275
|
+
if (existingHold) {
|
|
276
|
+
return {
|
|
277
|
+
cartLocked: true,
|
|
278
|
+
productId,
|
|
279
|
+
amount: existingHold.data.bidAmount,
|
|
280
|
+
currency: existingHold.data.currency,
|
|
281
|
+
bidId: existingHold.data.id,
|
|
282
|
+
checkoutDeadline: new Date(Date.now() + AUCTION_BUYOUT_WINDOW_MS),
|
|
283
|
+
checkoutUrl: AUCTION_CHECKOUT_URL,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
// The product's own currency, not the site default — the cart line, the bid
|
|
287
|
+
// and the listing all have to agree, and settlement uses the bid's currency.
|
|
288
|
+
const currency = product.currency || getDefaultCurrency();
|
|
289
|
+
const profile = await userRepository.findById(userId);
|
|
290
|
+
// A real bid at the buy-now price — this is what "the bid placed is the
|
|
291
|
+
// buyout price by the buyer" means. It starts `active`/`isWinning: false`
|
|
292
|
+
// like any other bid (bidRepository.create forces both) and is promoted to
|
|
293
|
+
// `won` by claimAuctionForCheckout when the order actually lands.
|
|
294
|
+
const bid = await bidRepository.create({
|
|
295
|
+
productId,
|
|
296
|
+
productTitle: product.title,
|
|
297
|
+
userId,
|
|
298
|
+
userName: profile?.displayName ?? userName ?? userEmail ?? "Anonymous",
|
|
299
|
+
userEmail: profile?.email ?? userEmail ?? "",
|
|
300
|
+
bidAmount: buyNowPrice,
|
|
301
|
+
currency,
|
|
302
|
+
bidDate: new Date(),
|
|
303
|
+
autoMaxBid: buyNowPrice,
|
|
304
|
+
isBuyout: true,
|
|
273
305
|
});
|
|
306
|
+
// Clamped to the auction's own end: a buyout that hasn't been paid for by the
|
|
307
|
+
// time the clock runs out fails anyway, because settlement will have awarded
|
|
308
|
+
// the item to whoever actually won the bidding. Showing a deadline past that
|
|
309
|
+
// point would promise a window that does not exist.
|
|
310
|
+
const auctionEnd = product.auctionEndDate ? resolveDate(product.auctionEndDate) : null;
|
|
311
|
+
const softDeadline = Date.now() + AUCTION_BUYOUT_WINDOW_MS;
|
|
312
|
+
const checkoutDeadline = new Date(auctionEnd ? Math.min(softDeadline, auctionEnd.getTime()) : softDeadline);
|
|
274
313
|
// Locked cart line, not an order — see BuyNowAuctionResult above. Written
|
|
275
314
|
// through the repository directly (auctions are canAddToCart:false for
|
|
276
315
|
// user-initiated adds), the same deliberate bypass checkoutOffer uses.
|
|
@@ -285,18 +324,52 @@ export async function buyNowAuction(userId, userName, userEmail, input) {
|
|
|
285
324
|
storeName: product.storeName ?? "",
|
|
286
325
|
listingType: "auction",
|
|
287
326
|
isAuctionWin: true,
|
|
327
|
+
isBuyout: true,
|
|
288
328
|
auctionId: productId,
|
|
329
|
+
bidId: bid.id,
|
|
289
330
|
lockedPrice: buyNowPrice,
|
|
290
|
-
checkoutDeadline
|
|
331
|
+
checkoutDeadline,
|
|
291
332
|
locked: true,
|
|
292
333
|
});
|
|
293
|
-
|
|
334
|
+
// Best-effort, exactly like placeBid's outbid notice: the hold is already
|
|
335
|
+
// committed and a failed notification must never undo it.
|
|
336
|
+
try {
|
|
337
|
+
await sendNotification({
|
|
338
|
+
userId,
|
|
339
|
+
type: "bid_won",
|
|
340
|
+
priority: "high",
|
|
341
|
+
title: BID_MESSAGES.BUY_NOW_HELD_TITLE,
|
|
342
|
+
message: BID_MESSAGES.BUY_NOW_HELD_MESSAGE(product.title, currency, buyNowPrice, AUCTION_BUYOUT_WINDOW_MINUTES),
|
|
343
|
+
relatedId: productId,
|
|
344
|
+
relatedType: "product",
|
|
345
|
+
actionUrl: AUCTION_CHECKOUT_URL,
|
|
346
|
+
actionLabel: BID_MESSAGES.BUY_NOW_HELD_ACTION,
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
catch (notifyErr) {
|
|
350
|
+
void normalizeError(notifyErr);
|
|
351
|
+
serverLogger.warn("buyNowAuction: hold notification failed", {
|
|
352
|
+
error: notifyErr,
|
|
353
|
+
productId,
|
|
354
|
+
userId,
|
|
355
|
+
});
|
|
356
|
+
}
|
|
294
357
|
serverLogger.info("buyNowAuction", {
|
|
295
358
|
productId,
|
|
296
359
|
userId,
|
|
360
|
+
bidId: bid.id,
|
|
297
361
|
amount: buyNowPrice,
|
|
362
|
+
checkoutDeadline: checkoutDeadline.toISOString(),
|
|
298
363
|
});
|
|
299
|
-
return {
|
|
364
|
+
return {
|
|
365
|
+
cartLocked: true,
|
|
366
|
+
productId,
|
|
367
|
+
amount: buyNowPrice,
|
|
368
|
+
currency,
|
|
369
|
+
bidId: bid.id,
|
|
370
|
+
checkoutDeadline,
|
|
371
|
+
checkoutUrl: AUCTION_CHECKOUT_URL,
|
|
372
|
+
};
|
|
300
373
|
}
|
|
301
374
|
export async function listBidsByProduct(productId, params) {
|
|
302
375
|
const result = await bidRepository.list({
|
|
@@ -15,7 +15,7 @@ import { formatCurrency } from "../../../utils/number.formatter";
|
|
|
15
15
|
import { normalizeRichTextHtml } from "../../../utils/string.formatter";
|
|
16
16
|
import { safeDisplayName } from "../../../security";
|
|
17
17
|
import { getSiteSettingsGlobal } from "../../admin/utils/getSiteSettingsGlobal";
|
|
18
|
-
import { resolveMinBid, resolveMinBidIncrement, } from "../../../_internal/shared/features/auctions/config";
|
|
18
|
+
import { isBuyNowAvailable, resolveMinBid, resolveMinBidIncrement, } from "../../../_internal/shared/features/auctions/config";
|
|
19
19
|
import { Button, Container, CountdownDisplay, Div, Heading, Input, Main, Nav, RichText, Row, Section, Span, Stack, Text, Ul, Li, Dl, Dt, Dd, } from "../../../ui";
|
|
20
20
|
import { AuctionDetailView } from "../../products/components/AuctionDetailView";
|
|
21
21
|
import { ProductTabsShell } from "../../products/components/ProductTabsShell";
|
|
@@ -45,8 +45,8 @@ function toDescriptionHtml(raw) {
|
|
|
45
45
|
return normalizeRichTextHtml(s);
|
|
46
46
|
}
|
|
47
47
|
function renderAuctionInfoPanel(props) {
|
|
48
|
-
const { productId, title, currentBid, currency, bidCount, isEnded, endDate, buyNowPrice, featured, freeShipping, condition, category, categoryName, brand, brandSlug, productFeatures, features, descriptionHtml, safeSeller, storeHref } = props;
|
|
49
|
-
return (_jsxs(Stack, { gap: "md", children: [_jsxs(Div, { children: [_jsxs(Row, { gap: "xs", wrap: true, className: "mb-2", children: [_jsx(Span, { size: "xs", weight: "semibold", className: CLS_LIVE_BADGE, children: "\uD83C\uDFF7\uFE0F Live Auction" }), isEnded ? (_jsx(Span, { color: "error", surface: "danger-surface", size: "xs", weight: "medium", className: "inline-block", padding: "pill-sm", rounded: "full", children: "Ended" })) : (_jsx(Span, { color: "success", surface: "success-surface", size: "xs", weight: "medium", className: "inline-block", padding: "pill-sm", rounded: "full", children: "Active" }))] }), _jsx(Heading, { level: 1, className: "leading-snug", smSize: "2xl", color: "primary", size: "xl", weight: "bold", children: title })] }), _jsxs(Div, { children: [_jsx(Text, { className: "mb-0.5", color: "muted", size: "xs", children: "Current bid" }), _jsx(LiveBidPrice, { productId: productId, currentBid: currentBid, bidCount: bidCount, currency: currency, isEnded: isEnded, priceSize: "2xl", badgeSize: "sm" }), endDate && !isEnded && (_jsxs(Text, { className: "mt-1.5", color: "muted", size: "sm", children: ["Ends in ", _jsx(Span, { weight: "medium", color: "muted", children: _jsx(CountdownDisplay, { targetDate: endDate, format: "auto", expiredLabel: "Ended" }) })] })), endDate && _jsxs(Text, { className: "mt-0.5", color: "faint", size: "xs", children: [isEnded ? "Ended" : "Ends", " ", endDate.toLocaleString()] })] }), buyNowPrice !== null &&
|
|
48
|
+
const { productId, title, currentBid, currency, bidCount, isEnded, endDate, buyNowPrice, buyNowAvailable, featured, freeShipping, condition, category, categoryName, brand, brandSlug, productFeatures, features, descriptionHtml, safeSeller, storeHref } = props;
|
|
49
|
+
return (_jsxs(Stack, { gap: "md", children: [_jsxs(Div, { children: [_jsxs(Row, { gap: "xs", wrap: true, className: "mb-2", children: [_jsx(Span, { size: "xs", weight: "semibold", className: CLS_LIVE_BADGE, children: "\uD83C\uDFF7\uFE0F Live Auction" }), isEnded ? (_jsx(Span, { color: "error", surface: "danger-surface", size: "xs", weight: "medium", className: "inline-block", padding: "pill-sm", rounded: "full", children: "Ended" })) : (_jsx(Span, { color: "success", surface: "success-surface", size: "xs", weight: "medium", className: "inline-block", padding: "pill-sm", rounded: "full", children: "Active" }))] }), _jsx(Heading, { level: 1, className: "leading-snug", smSize: "2xl", color: "primary", size: "xl", weight: "bold", children: title })] }), _jsxs(Div, { children: [_jsx(Text, { className: "mb-0.5", color: "muted", size: "xs", children: "Current bid" }), _jsx(LiveBidPrice, { productId: productId, currentBid: currentBid, bidCount: bidCount, currency: currency, isEnded: isEnded, priceSize: "2xl", badgeSize: "sm" }), endDate && !isEnded && (_jsxs(Text, { className: "mt-1.5", color: "muted", size: "sm", children: ["Ends in ", _jsx(Span, { weight: "medium", color: "muted", children: _jsx(CountdownDisplay, { targetDate: endDate, format: "auto", expiredLabel: "Ended" }) })] })), endDate && _jsxs(Text, { className: "mt-0.5", color: "faint", size: "xs", children: [isEnded ? "Ended" : "Ends", " ", endDate.toLocaleString()] })] }), buyNowAvailable && buyNowPrice !== null && (_jsxs(Row, { align: "center", gap: "sm", className: "border border-[var(--appkit-color-primary-200)] dark:border-[var(--appkit-color-primary-800)] bg-primary-50 dark:bg-primary-900/20", padding: "inlineSm", rounded: "lg", children: [_jsx(Span, { size: "xs", color: "muted", children: "Buy Now:" }), _jsx(Span, { size: "base", weight: "bold", className: "text-primary-700 dark:text-primary-300", children: formatCurrency(buyNowPrice, currency) })] })), _jsx(ProductFeatureBadges, { featured: featured, freeShipping: freeShipping, condition: condition ?? undefined, labels: { featured: "Featured", fasterDelivery: "Faster Delivery", ratedSeller: "Rated Seller", condition: "Condition", conditionNew: "New", conditionUsed: "Used", conditionBroken: "For Parts", conditionRefurbished: "Refurbished", returnable: "Returnable", freeShipping: "Free Shipping", codAvailable: "Cash on Delivery", emiAvailable: "EMI Available", wishlistCount: (n) => `${n} wishlisted`, categoryProductCount: (n, cat) => `${n} in ${cat}` } }), (categoryName || category || brand) && (_jsxs(Row, { gap: "sm", wrap: true, children: [category && _jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(category)), className: "inline-flex items-center rounded-full border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-[var(--appkit-space-2-5)] py-[var(--appkit-space-1)] text-[length:var(--appkit-text-xs)] font-medium text-[var(--appkit-color-text-muted)] transition-colors hover:border-primary-300 hover:bg-primary-50 hover:text-primary-700 dark:hover:border-primary-700/60 dark:hover:bg-primary-900/20 dark:hover:text-primary-400", children: categoryName || category }), !category && categoryName && _jsx(Span, { layout: "inline-flex", size: "xs", weight: "medium", border: "subtle", rounded: "full", padding: "pill-sm-tall", surface: "muted", color: "muted", children: categoryName }), brand && brandSlug && _jsx(Link, { href: String(ROUTES.PUBLIC.BRAND_DETAIL(brandSlug)), className: "inline-flex items-center rounded-full border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-[var(--appkit-space-2-5)] py-[var(--appkit-space-1)] text-[length:var(--appkit-text-xs)] font-medium text-[var(--appkit-color-text-muted)] transition-colors hover:border-primary-300 hover:bg-primary-50 hover:text-primary-700 dark:hover:border-primary-700/60 dark:hover:bg-primary-900/20 dark:hover:text-primary-400", children: brand }), brand && !brandSlug && _jsx(Span, { layout: "inline-flex", size: "xs", weight: "medium", border: "subtle", rounded: "full", padding: "pill-sm-tall", surface: "muted", color: "muted", children: brand })] })), productFeatures && features.length > 0 && _jsx(FeatureBadgeList, { productFeatureIds: features, features: productFeatures }), !productFeatures && features.length > 0 && (_jsxs(Div, { border: "subtle", surface: "muted", padding: "inline", rounded: "xl", children: [_jsx(Text, { className: "mb-2 tracking-wide", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: "About this item" }), _jsx(Ul, { spacing: "comfortable", size: "sm", color: "primary", children: features.map((f, i) => _jsxs(Li, { layout: "flex-start", gap: "2", children: [_jsx(Span, { className: "mt-0.5 flex-shrink-0 text-primary-500", children: "\u2022" }), f] }, i)) })] })), descriptionHtml && _jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "text-[length:var(--appkit-text-sm)] leading-relaxed text-[var(--appkit-color-text-muted)] line-clamp-4" }), safeSeller && (_jsx(Div, { className: `${__P.p3}`, border: "subtle", rounded: "xl", surface: "muted", children: _jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-[10px] tracking-wide mb-0.5", color: "faint", transform: "uppercase", children: "Listed by" }), _jsx(Text, { size: "sm", weight: "semibold", color: "primary", children: safeSeller })] }), storeHref && _jsx(Link, { href: storeHref, className: "shrink-0 rounded-lg bg-primary/10 dark:bg-primary/20 px-[var(--appkit-space-3)] py-[var(--appkit-space-1-5)] text-[length:var(--appkit-text-xs)] font-semibold text-primary-700 dark:text-primary-300 hover:bg-primary/20 dark:hover:bg-primary/30 transition-colors", children: "Visit Store \u2192" })] }) }))] }));
|
|
50
50
|
}
|
|
51
51
|
/**
|
|
52
52
|
* Store reviews for the auction's seller.
|
|
@@ -98,7 +98,12 @@ export async function AuctionDetailPageView({ id, initialAuction, onPlaceBid, on
|
|
|
98
98
|
const isEnded = endDate ? endDate < new Date() : false;
|
|
99
99
|
const bidCount = typeof p.bidCount === "number" ? p.bidCount : 0;
|
|
100
100
|
const buyNowPrice = typeof p.buyNowPrice === "number" ? p.buyNowPrice : null;
|
|
101
|
-
const
|
|
101
|
+
const buyNowAvailable = isBuyNowAvailable({
|
|
102
|
+
buyNowPrice,
|
|
103
|
+
currentBid,
|
|
104
|
+
isEnded,
|
|
105
|
+
isSold: p.isSold === true,
|
|
106
|
+
});
|
|
102
107
|
const condition = typeof p.condition === "string" ? p.condition : null;
|
|
103
108
|
const featured = p.featured === true;
|
|
104
109
|
const shippingPaidBy = p.shippingPaidBy;
|
|
@@ -149,9 +154,9 @@ export async function AuctionDetailPageView({ id, initialAuction, onPlaceBid, on
|
|
|
149
154
|
price: typeof p.price === "number" ? p.price : undefined,
|
|
150
155
|
storeId: typeof p.storeId === "string" ? p.storeId : undefined,
|
|
151
156
|
storeName: typeof p.storeName === "string" ? p.storeName : undefined,
|
|
152
|
-
} }), _jsxs(Container, { size: "xl", padding: "y-lg", children: [_jsxs(Row, { className: "mb-4", align: "center", justify: "between", gap: "sm", wrap: true, children: [_jsxs(Nav, { "aria-label": "Breadcrumb", layout: "flex-wrap", gap: "2xs", textSize: "xs", color: "muted", children: [_jsx(Link, { href: String(ROUTES.HOME), className: CLS_BREADCRUMB_LINK, children: "Home" }), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.AUCTIONS), className: CLS_BREADCRUMB_LINK, children: "Auctions" }), category && (_jsxs(_Fragment, { children: [_jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(category)), className: CLS_BREADCRUMB_LINK, children: categoryName || category })] })), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Span, { className: "truncate max-w-[200px]", color: "muted", children: title })] }), _jsx(ShareButton, { title: title })] }), _jsx(AuctionDetailView, { renderGallery: () => (_jsx(ProductGalleryClient, { images: images, video: productVideo, productName: title })), renderInfo: () => renderAuctionInfoPanel({ productId: String(product.id), title, currentBid, currency, bidCount, isEnded, endDate, buyNowPrice, featured, freeShipping, condition, category, categoryName, brand, brandSlug, productFeatures, features, descriptionHtml, safeSeller, storeHref }), renderBidForm: () => onPlaceBid ? (_jsx(Stack, { id: "auction-bid-form", gap: "3", children: _jsxs(Stack, { className: `${__P.p5}`, border: "subtle", gap: "3", rounded: "xl", surface: "muted", children: [_jsxs(Row, { justify: "between", align: "baseline", children: [_jsx(LiveBidPrice, { productId: String(product.id), currentBid: currentBid, bidCount: bidCount, currency: currency, isEnded: isEnded, priceSize: "xl", badgeSize: "xs" }), !isEnded && (_jsx(LiveMinIncrement, { productId: String(product.id), currentBid: currentBid, bidCount: bidCount, currency: currency, isEnded: isEnded, tiers: bidIncrementTiers, minBidIncrementOverride: minBidIncrementOverride }))] }), !isEnded && endDate && (_jsxs(Text, { align: "center", size: "xs", color: "muted", children: ["Ends in ", _jsx(CountdownDisplay, { targetDate: endDate, format: "auto", expiredLabel: "Ended" })] })), _jsx(PlaceBidModalButton, { productId: String(product.id), currentBid: currentBid, startingBid: startingBid, tiers: bidIncrementTiers, minBidIncrementOverride: minBidIncrementOverride, currency: currency, isEnded: isEnded, auctionEndDate: endDate, buyNowPrice: buyNowPrice,
|
|
157
|
+
} }), _jsxs(Container, { size: "xl", padding: "y-lg", children: [_jsxs(Row, { className: "mb-4", align: "center", justify: "between", gap: "sm", wrap: true, children: [_jsxs(Nav, { "aria-label": "Breadcrumb", layout: "flex-wrap", gap: "2xs", textSize: "xs", color: "muted", children: [_jsx(Link, { href: String(ROUTES.HOME), className: CLS_BREADCRUMB_LINK, children: "Home" }), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.AUCTIONS), className: CLS_BREADCRUMB_LINK, children: "Auctions" }), category && (_jsxs(_Fragment, { children: [_jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(category)), className: CLS_BREADCRUMB_LINK, children: categoryName || category })] })), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Span, { className: "truncate max-w-[200px]", color: "muted", children: title })] }), _jsx(ShareButton, { title: title })] }), _jsx(AuctionDetailView, { renderGallery: () => (_jsx(ProductGalleryClient, { images: images, video: productVideo, productName: title })), renderInfo: () => renderAuctionInfoPanel({ productId: String(product.id), title, currentBid, currency, bidCount, isEnded, endDate, buyNowPrice, buyNowAvailable, featured, freeShipping, condition, category, categoryName, brand, brandSlug, productFeatures, features, descriptionHtml, safeSeller, storeHref }), renderBidForm: () => onPlaceBid ? (_jsx(Stack, { id: "auction-bid-form", gap: "3", children: _jsxs(Stack, { className: `${__P.p5}`, border: "subtle", gap: "3", rounded: "xl", surface: "muted", children: [_jsxs(Row, { justify: "between", align: "baseline", children: [_jsx(LiveBidPrice, { productId: String(product.id), currentBid: currentBid, bidCount: bidCount, currency: currency, isEnded: isEnded, priceSize: "xl", badgeSize: "xs" }), !isEnded && (_jsx(LiveMinIncrement, { productId: String(product.id), currentBid: currentBid, bidCount: bidCount, currency: currency, isEnded: isEnded, tiers: bidIncrementTiers, minBidIncrementOverride: minBidIncrementOverride }))] }), !isEnded && endDate && (_jsxs(Text, { align: "center", size: "xs", color: "muted", children: ["Ends in ", _jsx(CountdownDisplay, { targetDate: endDate, format: "auto", expiredLabel: "Ended" })] })), _jsx(PlaceBidModalButton, { productId: String(product.id), currentBid: currentBid, startingBid: startingBid, tiers: bidIncrementTiers, minBidIncrementOverride: minBidIncrementOverride, currency: currency, isEnded: isEnded, auctionEndDate: endDate, buyNowPrice: buyNowPrice, bidCount: bidCount, tags: tags, onPlaceBid: onPlaceBid, onBuyNow: onBuyNow, triggerClassName: "w-full" })] }) })) : (
|
|
153
158
|
/* Read-only bid panel — shown when no bid action is wired (preview/demo) */
|
|
154
|
-
_jsxs(Stack, { className: `${__P.p5}`, border: "subtle", gap: "md", rounded: "xl", surface: "muted", children: [_jsx(Stack, { gap: "xs", children: _jsxs(Text, { size: "xs", color: "muted", children: ["Starting bid: ", formatCurrency(startingBid, currency), !isEnded && _jsxs(_Fragment, { children: [" \u00B7 min increment ", formatCurrency(initialMinBidIncrement, currency)] })] }) }), _jsxs(Stack, { gap: "sm", children: [_jsx(Input, { type: "number", placeholder: `At least ${formatCurrency(initialMinBid, currency)}`, min: initialMinBid, "aria-label": "Your bid amount", disabled: isEnded }), !isEnded && endDate && (_jsxs(Text, { align: "center", size: "xs", color: "muted", children: ["Ends in ", _jsx(CountdownDisplay, { targetDate: endDate, format: "auto", expiredLabel: "Ended" })] })), _jsx(Button, { variant: "primary", size: "md", className: "w-full", disabled: isEnded, children: isEnded ? "Auction Ended" : "Place Bid" }), buyNowPrice !== null &&
|
|
159
|
+
_jsxs(Stack, { className: `${__P.p5}`, border: "subtle", gap: "md", rounded: "xl", surface: "muted", children: [_jsx(Stack, { gap: "xs", children: _jsxs(Text, { size: "xs", color: "muted", children: ["Starting bid: ", formatCurrency(startingBid, currency), !isEnded && _jsxs(_Fragment, { children: [" \u00B7 min increment ", formatCurrency(initialMinBidIncrement, currency)] })] }) }), _jsxs(Stack, { gap: "sm", children: [_jsx(Input, { type: "number", placeholder: `At least ${formatCurrency(initialMinBid, currency)}`, min: initialMinBid, "aria-label": "Your bid amount", disabled: isEnded }), !isEnded && endDate && (_jsxs(Text, { align: "center", size: "xs", color: "muted", children: ["Ends in ", _jsx(CountdownDisplay, { targetDate: endDate, format: "auto", expiredLabel: "Ended" })] })), _jsx(Button, { variant: "primary", size: "md", className: "w-full", disabled: isEnded, children: isEnded ? "Auction Ended" : "Place Bid" }), buyNowAvailable && buyNowPrice !== null && (_jsxs(Text, { align: "center", size: "xs", color: "muted", children: ["Buy Now available at ", formatCurrency(buyNowPrice, currency)] }))] }), tags.length > 0 && (_jsx(Div, { border: "default", className: "border-t", padding: "t-md", children: _jsx(Row, { wrap: true, gap: "xs", children: tags.map((tag) => (_jsx(Span, { size: "xs", rounded: "full", padding: "pill-sm-tall", surface: "subtle", color: "muted", children: tag }, tag))) }) }))] })), renderMobileBidForm: () => !isEnded && onPlaceBid ? (_jsxs(Stack, { className: `lg:hidden ${__P.p4}`, border: "subtle", gap: "3", rounded: "xl", surface: "muted", children: [_jsx(LiveBidPrice, { productId: String(product.id), currentBid: currentBid, bidCount: bidCount, currency: currency, isEnded: isEnded, priceSize: "base", badgeSize: "xs" }), endDate && (_jsxs(Text, { align: "center", size: "xs", color: "muted", children: ["Ends in ", _jsx(CountdownDisplay, { targetDate: endDate, format: "auto", expiredLabel: "Ended" })] })), _jsx(PlaceBidModalButton, { productId: String(product.id), currentBid: currentBid, startingBid: startingBid, tiers: bidIncrementTiers, minBidIncrementOverride: minBidIncrementOverride, currency: currency, isEnded: isEnded, auctionEndDate: endDate, buyNowPrice: buyNowPrice, bidCount: bidCount, tags: tags, onPlaceBid: onPlaceBid, onBuyNow: onBuyNow, triggerClassName: "w-full" })] })) : !isEnded ? (_jsxs(Div, { className: `${__P.p4} lg:hidden`, border: "subtle", rounded: "xl", surface: "muted", children: [_jsxs(Row, { align: "center", gap: "sm", className: "mb-3", children: [_jsx(Span, { size: "base", weight: "bold", className: "text-primary-600 dark:text-primary-400", children: formatCurrency(currentBid, currency) }), _jsxs(Span, { size: "xs", color: "muted", children: [bidCount, " bids"] })] }), endDate && (_jsxs(Text, { align: "center", className: "mb-3", size: "xs", color: "muted", children: ["Ends in ", _jsx(CountdownDisplay, { targetDate: endDate, format: "auto", expiredLabel: "Ended" })] })), _jsx(Button, { variant: "primary", size: "md", className: "w-full", children: "Place Bid" })] })) : null, renderSublistingSection: sublistingCategoryId
|
|
155
160
|
? () => (_jsx(SublistingCarouselSection, { sublistingCategoryId: sublistingCategoryId, currentListingId: String(product.id) }))
|
|
156
161
|
: undefined, renderTabs: () => (_jsx(ProductTabsShell, { descriptionContent: descriptionHtml ? (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm sm:prose max-w-none dark:prose-invert", className: "text-[var(--appkit-color-text-muted)]" })) : undefined, specsContent: specs.length > 0 ? (_jsx(Dl, { divide: "subtle", rounded: "xl", border: "subtle", className: "overflow-hidden", children: specs.map((s, i) => (_jsxs(Row, { gap: "md", oddEven: "zebra", surface: "default", padding: "inline", children: [_jsx(Dt, { className: "w-36 flex-shrink-0", color: "primary", weight: "medium", children: s.name }), _jsxs(Dd, { className: "flex-1", color: "muted", children: [s.value, s.unit ? ` ${s.unit}` : ""] })] }, i))) })) : undefined, customTabs: customSections.map((s) => ({
|
|
157
162
|
id: s.id,
|
|
@@ -2,20 +2,19 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Container, Heading, Main, Section } from "../../../ui";
|
|
3
3
|
import { AdSlot } from "../../homepage/components/AdSlot";
|
|
4
4
|
import { AuctionsIndexListing } from "../../products/components/AuctionsIndexListing";
|
|
5
|
-
import { listPublicProducts, parsePublicProductParams, } from "../../../_internal/server/features/products/list-public";
|
|
5
|
+
import { listPublicProducts, parsePublicProductParams, defaultAvailabilityForListingTypes, } from "../../../_internal/server/features/products/list-public";
|
|
6
6
|
const AUCTION_LISTING_TYPES = ["auction"];
|
|
7
7
|
const DEFAULT_PAGE_SIZE = 24;
|
|
8
8
|
const DEFAULT_SORT = "auctionEndDate";
|
|
9
9
|
export async function AuctionsListView({ searchParams = {} }) {
|
|
10
|
-
// Shared with /api/products
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
// Firestore rather than filtering in memory.
|
|
10
|
+
// Shared with /api/products, and derived rather than hardcoded — this view
|
|
11
|
+
// carried a literal `hideEndedByDefault: true` until 2026-08-24, which is
|
|
12
|
+
// exactly the mirrored-literal shape Root Cause #30 is written as.
|
|
14
13
|
const initial = await listPublicProducts(parsePublicProductParams(searchParams, {
|
|
15
14
|
listingTypes: AUCTION_LISTING_TYPES,
|
|
16
15
|
pageSize: DEFAULT_PAGE_SIZE,
|
|
17
16
|
sorts: DEFAULT_SORT,
|
|
18
|
-
|
|
17
|
+
...defaultAvailabilityForListingTypes(AUCTION_LISTING_TYPES),
|
|
19
18
|
}));
|
|
20
19
|
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: "Live Auctions" }), _jsx(AdSlot, { id: "listing-sidebar-top", className: "mb-6" }), _jsx(AuctionsIndexListing, { initialData: initial }), _jsx(AdSlot, { id: "listing-sidebar-bottom", className: "mt-8" })] }) }) }));
|
|
21
20
|
}
|