@mohasinac/appkit 4.13.0 → 4.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (377) hide show
  1. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +14 -5
  2. package/dist/_internal/client/features/lottery/LotteryAdminEditView.d.ts +3 -0
  3. package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +6 -0
  4. package/dist/_internal/client/features/lottery/LotteryDetailView.d.ts +8 -0
  5. package/dist/_internal/client/features/lottery/LotteryDetailView.js +4 -1
  6. package/dist/_internal/client/features/lottery/LotteryListView.d.ts +7 -0
  7. package/dist/_internal/client/features/lottery/LotteryListView.js +1 -1
  8. package/dist/_internal/client/features/lottery/PrizeDrawLotteryDetailView.js +4 -1
  9. package/dist/_internal/client/features/lottery/slot-collage-items.d.ts +15 -0
  10. package/dist/_internal/client/features/lottery/slot-collage-items.js +13 -0
  11. package/dist/_internal/server/features/auctions/actions.js +6 -0
  12. package/dist/_internal/server/features/bundles/data.d.ts +16 -0
  13. package/dist/_internal/server/features/bundles/data.js +26 -0
  14. package/dist/_internal/server/features/bundles/index.d.ts +1 -1
  15. package/dist/_internal/server/features/bundles/index.js +1 -1
  16. package/dist/_internal/server/features/checkout/actions.js +6 -0
  17. package/dist/_internal/server/features/checkout/locked-lines.d.ts +38 -0
  18. package/dist/_internal/server/features/checkout/locked-lines.js +171 -0
  19. package/dist/_internal/server/features/homepage/index.d.ts +0 -1
  20. package/dist/_internal/server/features/homepage/index.js +7 -1
  21. package/dist/_internal/server/features/lottery/adapters.js +4 -0
  22. package/dist/_internal/server/features/products/data.js +15 -37
  23. package/dist/_internal/server/features/products/index.d.ts +1 -1
  24. package/dist/_internal/server/features/products/index.js +1 -1
  25. package/dist/_internal/server/features/products/list-public.d.ts +46 -20
  26. package/dist/_internal/server/features/products/list-public.js +266 -90
  27. package/dist/_internal/server/features/products/listing-tab-counts.d.ts +44 -0
  28. package/dist/_internal/server/features/products/listing-tab-counts.js +97 -0
  29. package/dist/_internal/server/features/site-settings/adapters.d.ts +51 -0
  30. package/dist/_internal/server/features/site-settings/adapters.js +75 -0
  31. package/dist/_internal/server/features/site-settings/index.d.ts +1 -0
  32. package/dist/_internal/server/features/site-settings/index.js +1 -0
  33. package/dist/_internal/server/features/stores/adapters.d.ts +56 -0
  34. package/dist/_internal/server/features/stores/adapters.js +91 -0
  35. package/dist/_internal/server/features/stores/index.d.ts +1 -0
  36. package/dist/_internal/server/features/stores/index.js +1 -0
  37. package/dist/_internal/server/jobs/core/auctionSettlement.js +56 -2
  38. package/dist/_internal/server/jobs/core/offerExpiry.js +45 -9
  39. package/dist/_internal/server/jobs/core/paymentReviewAutoApprove.d.ts +5 -0
  40. package/dist/_internal/server/jobs/core/paymentReviewAutoApprove.js +33 -1
  41. package/dist/_internal/server/jobs/handlers/messages.d.ts +7 -0
  42. package/dist/_internal/server/jobs/handlers/messages.js +10 -0
  43. package/dist/_internal/shared/actions/action-registry.js +15 -1
  44. package/dist/_internal/shared/checkout/lanes.d.ts +25 -0
  45. package/dist/_internal/shared/checkout/lanes.js +26 -0
  46. package/dist/_internal/shared/features/auctions/config.d.ts +27 -0
  47. package/dist/_internal/shared/features/auctions/config.js +27 -0
  48. package/dist/_internal/shared/features/blog/schema.d.ts +2 -2
  49. package/dist/_internal/shared/features/cart/schema.d.ts +12 -12
  50. package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +32 -32
  51. package/dist/_internal/shared/features/emi/schedule.d.ts +24 -3
  52. package/dist/_internal/shared/features/emi/schedule.js +20 -5
  53. package/dist/_internal/shared/features/events/schema.d.ts +2 -2
  54. package/dist/_internal/shared/features/homepage/section-gate.d.ts +14 -0
  55. package/dist/_internal/shared/features/homepage/section-gate.js +51 -0
  56. package/dist/_internal/shared/features/offers/config.d.ts +30 -0
  57. package/dist/_internal/shared/features/offers/config.js +59 -0
  58. package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
  59. package/dist/_internal/shared/features/products/schema.d.ts +32 -32
  60. package/dist/_internal/shared/features/products/to-product-item.js +6 -0
  61. package/dist/_internal/shared/features/reviews/schema.d.ts +2 -2
  62. package/dist/_internal/shared/features/site-settings/fees.d.ts +60 -0
  63. package/dist/_internal/shared/features/site-settings/fees.js +39 -0
  64. package/dist/_internal/shared/features/site-settings/types.d.ts +40 -0
  65. package/dist/_internal/shared/features/site-settings/types.js +1 -0
  66. package/dist/_internal/shared/history/history.d.ts +66 -0
  67. package/dist/_internal/shared/history/history.js +158 -0
  68. package/dist/_internal/shared/history/index.d.ts +4 -0
  69. package/dist/_internal/shared/history/index.js +2 -0
  70. package/dist/_internal/shared/history/types.d.ts +61 -0
  71. package/dist/_internal/shared/history/types.js +6 -0
  72. package/dist/_internal/shared/listing-types/_registry.d.ts +54 -1
  73. package/dist/_internal/shared/listing-types/_registry.js +67 -0
  74. package/dist/_internal/shared/listing-types/art/config.d.ts +3 -0
  75. package/dist/_internal/shared/listing-types/art/config.js +5 -0
  76. package/dist/_internal/shared/listing-types/auction/config.d.ts +13 -0
  77. package/dist/_internal/shared/listing-types/auction/config.js +21 -0
  78. package/dist/_internal/shared/listing-types/availability.d.ts +79 -0
  79. package/dist/_internal/shared/listing-types/availability.js +104 -0
  80. package/dist/_internal/shared/listing-types/capabilities.d.ts +15 -0
  81. package/dist/_internal/shared/listing-types/capabilities.js +12 -0
  82. package/dist/_internal/shared/listing-types/classified/config.d.ts +3 -0
  83. package/dist/_internal/shared/listing-types/classified/config.js +5 -0
  84. package/dist/_internal/shared/listing-types/digital-code/config.d.ts +11 -0
  85. package/dist/_internal/shared/listing-types/digital-code/config.js +22 -2
  86. package/dist/_internal/shared/listing-types/live/config.d.ts +3 -0
  87. package/dist/_internal/shared/listing-types/live/config.js +5 -0
  88. package/dist/_internal/shared/listing-types/pre-order/config.d.ts +3 -0
  89. package/dist/_internal/shared/listing-types/pre-order/config.js +19 -0
  90. package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +11 -0
  91. package/dist/_internal/shared/listing-types/prize-draw/config.js +15 -0
  92. package/dist/_internal/shared/listing-types/standard/config.d.ts +3 -0
  93. package/dist/_internal/shared/listing-types/standard/config.js +5 -0
  94. package/dist/_internal/shared/listing-types/stickers/config.d.ts +3 -0
  95. package/dist/_internal/shared/listing-types/stickers/config.js +5 -0
  96. package/dist/client.d.ts +7 -5
  97. package/dist/client.js +2 -2
  98. package/dist/constants/api-endpoints.d.ts +6 -0
  99. package/dist/constants/api-endpoints.js +2 -0
  100. package/dist/constants/field-names.d.ts +49 -2
  101. package/dist/constants/field-names.js +53 -2
  102. package/dist/constants/table-keys.d.ts +17 -0
  103. package/dist/constants/table-keys.js +17 -0
  104. package/dist/errors/error-codes.d.ts +13 -1
  105. package/dist/errors/error-codes.js +13 -1
  106. package/dist/errors/error-display-map.js +12 -3
  107. package/dist/errors/messages.d.ts +10 -2
  108. package/dist/errors/messages.js +10 -2
  109. package/dist/features/about/components/AboutView.d.ts +3 -0
  110. package/dist/features/about/components/AboutView.js +3 -2
  111. package/dist/features/about/components/PolicyPageView.d.ts +2 -1
  112. package/dist/features/about/components/PolicyPageView.js +61 -23
  113. package/dist/features/about/components/PublicProfileView.js +5 -0
  114. package/dist/features/about/schemas/firestore.d.ts +3 -0
  115. package/dist/features/account/components/UserOrdersView.js +7 -0
  116. package/dist/features/account/components/index.d.ts +0 -2
  117. package/dist/features/account/components/index.js +0 -1
  118. package/dist/features/account/schemas/index.d.ts +2 -2
  119. package/dist/features/account/types/index.d.ts +21 -2
  120. package/dist/features/addresses/schemas/index.d.ts +4 -4
  121. package/dist/features/admin/components/AdminArtView.js +8 -3
  122. package/dist/features/admin/components/AdminClassifiedView.js +8 -3
  123. package/dist/features/admin/components/AdminDigitalCodesView.js +8 -3
  124. package/dist/features/admin/components/AdminFeatureFlagsView.js +1 -0
  125. package/dist/features/admin/components/AdminLiveView.js +8 -3
  126. package/dist/features/admin/components/AdminOffersView.d.ts +4 -0
  127. package/dist/features/admin/components/AdminOffersView.js +186 -0
  128. package/dist/features/admin/components/AdminOrdersView.js +10 -1
  129. package/dist/features/admin/components/AdminPrizeDrawsView.js +5 -0
  130. package/dist/features/admin/components/AdminProductsView.js +16 -29
  131. package/dist/features/admin/components/AdminSiteSettingsView.js +31 -13
  132. package/dist/features/admin/components/AdminSiteView.js +6 -2
  133. package/dist/features/admin/components/AdminStickersView.js +8 -3
  134. package/dist/features/admin/components/index.d.ts +2 -0
  135. package/dist/features/admin/components/index.js +1 -0
  136. package/dist/features/admin/constants/filter-tabs.d.ts +86 -0
  137. package/dist/features/admin/constants/filter-tabs.js +55 -0
  138. package/dist/features/admin/schemas/firestore.d.ts +122 -3
  139. package/dist/features/admin/schemas/firestore.js +1 -0
  140. package/dist/features/auctions/actions/bid-actions.d.ts +20 -5
  141. package/dist/features/auctions/actions/bid-actions.js +93 -20
  142. package/dist/features/auctions/components/AuctionDetailPageView.js +11 -6
  143. package/dist/features/auctions/components/AuctionsListView.js +5 -6
  144. package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +7 -0
  145. package/dist/features/auctions/components/MarketplaceAuctionCard.js +19 -2
  146. package/dist/features/auctions/components/PlaceBidFormClient.d.ts +1 -2
  147. package/dist/features/auctions/components/PlaceBidFormClient.js +8 -4
  148. package/dist/features/auctions/repository/bid.repository.d.ts +13 -0
  149. package/dist/features/auctions/repository/bid.repository.js +23 -0
  150. package/dist/features/auctions/schemas/firestore.d.ts +17 -0
  151. package/dist/features/auctions/schemas/index.d.ts +12 -12
  152. package/dist/features/auth/permissions/constants.d.ts +1 -1
  153. package/dist/features/auth/permissions/constants.js +10 -1
  154. package/dist/features/blog/actions/blog-actions.d.ts +7 -7
  155. package/dist/features/blog/schemas/index.d.ts +6 -6
  156. package/dist/features/cart/repository/cart.repository.js +1 -0
  157. package/dist/features/cart/schemas/firestore.d.ts +15 -0
  158. package/dist/features/catalogue/schemas/validation.d.ts +4 -4
  159. package/dist/features/categories/components/BrandDetailPageView.js +23 -40
  160. package/dist/features/categories/components/BrandDetailTabs.d.ts +7 -7
  161. package/dist/features/categories/components/BrandDetailTabs.js +8 -12
  162. package/dist/features/categories/components/BundleCollage.js +1 -1
  163. package/dist/features/categories/components/CategoryDetailPageView.js +53 -57
  164. package/dist/features/categories/components/CategoryDetailTabs.d.ts +10 -8
  165. package/dist/features/categories/components/CategoryDetailTabs.js +11 -16
  166. package/dist/features/categories/components/CategoryProductsListing.js +11 -1
  167. package/dist/features/categories/components/ConcernCard.js +7 -1
  168. package/dist/features/categories/schemas/firestore.d.ts +13 -0
  169. package/dist/features/categories/schemas/index.d.ts +26 -26
  170. package/dist/features/classified/components/ClassifiedDetailPageView.d.ts +16 -1
  171. package/dist/features/classified/components/ClassifiedDetailPageView.js +23 -3
  172. package/dist/features/events/components/AdminEventsView.js +15 -11
  173. package/dist/features/events/components/EventFilters.d.ts +9 -1
  174. package/dist/features/events/components/EventFilters.js +45 -21
  175. package/dist/features/events/components/EventsIndexListing.d.ts +6 -1
  176. package/dist/features/events/components/EventsIndexListing.js +2 -2
  177. package/dist/features/events/components/EventsListPageView.js +13 -4
  178. package/dist/features/events/repository/events.repository.d.ts +17 -0
  179. package/dist/features/events/repository/events.repository.js +27 -0
  180. package/dist/features/events/schemas/firestore.d.ts +12 -0
  181. package/dist/features/events/schemas/firestore.js +12 -0
  182. package/dist/features/events/schemas/index.d.ts +50 -50
  183. package/dist/features/events/types/index.d.ts +11 -0
  184. package/dist/features/events/types/index.js +57 -1
  185. package/dist/features/faq/actions/faq-actions.d.ts +12 -12
  186. package/dist/features/faq/schemas/index.d.ts +8 -8
  187. package/dist/features/filters/FilterFacetSection.d.ts +7 -1
  188. package/dist/features/filters/FilterFacetSection.js +11 -3
  189. package/dist/features/grouped/schemas/index.d.ts +4 -4
  190. package/dist/features/homepage/components/AnnouncementBar.d.ts +7 -1
  191. package/dist/features/homepage/components/AnnouncementBar.js +3 -3
  192. package/dist/features/homepage/components/MarketplaceHomepageView.js +20 -6
  193. package/dist/features/homepage/hooks/homepage-query.d.ts +16 -0
  194. package/dist/features/homepage/hooks/homepage-query.js +45 -0
  195. package/dist/features/homepage/hooks/useFeaturedAuctions.d.ts +10 -0
  196. package/dist/features/homepage/hooks/useFeaturedAuctions.js +28 -8
  197. package/dist/features/homepage/hooks/useFeaturedPreOrders.js +17 -8
  198. package/dist/features/homepage/hooks/useFeaturedProducts.js +15 -8
  199. package/dist/features/homepage/schemas/index.d.ts +2 -2
  200. package/dist/features/layout/AppLayoutShell.d.ts +11 -1
  201. package/dist/features/layout/AppLayoutShell.js +15 -14
  202. package/dist/features/layout/BackToTop.d.ts +9 -0
  203. package/dist/features/layout/BackToTop.js +10 -1
  204. package/dist/features/layout/BottomActions.js +28 -25
  205. package/dist/features/layout/BottomChrome.d.ts +34 -0
  206. package/dist/features/layout/BottomChrome.js +55 -0
  207. package/dist/features/layout/BottomNavLayout.d.ts +6 -0
  208. package/dist/features/layout/BottomNavLayout.js +7 -1
  209. package/dist/features/layout/BottomNavbar.js +15 -2
  210. package/dist/features/layout/FooterLayout.js +11 -1
  211. package/dist/features/layout/NavbarLayout.js +1 -1
  212. package/dist/features/layout/TitleBarLayout.d.ts +7 -0
  213. package/dist/features/layout/TitleBarLayout.js +28 -5
  214. package/dist/features/layout/index.d.ts +2 -0
  215. package/dist/features/layout/index.js +1 -0
  216. package/dist/features/lottery/types/index.d.ts +3 -0
  217. package/dist/features/media/MediaPickerModal.js +5 -1
  218. package/dist/features/messages/schemas/index.d.ts +2 -2
  219. package/dist/features/orders/components/OrderScopeTabs.d.ts +20 -0
  220. package/dist/features/orders/components/OrderScopeTabs.js +31 -0
  221. package/dist/features/orders/constants/order-scope.d.ts +48 -0
  222. package/dist/features/orders/constants/order-scope.js +111 -0
  223. package/dist/features/orders/repository/orders.repository.d.ts +54 -7
  224. package/dist/features/orders/repository/orders.repository.js +116 -22
  225. package/dist/features/orders/schemas/firestore.d.ts +117 -0
  226. package/dist/features/orders/schemas/firestore.js +30 -0
  227. package/dist/features/orders/schemas/index.d.ts +18 -18
  228. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +14 -9
  229. package/dist/features/pre-orders/components/PreOrdersListView.js +6 -5
  230. package/dist/features/pre-orders/schemas/index.d.ts +1 -1
  231. package/dist/features/products/actions/product-actions.d.ts +14 -0
  232. package/dist/features/products/actions/product-actions.js +49 -11
  233. package/dist/features/products/api/route.d.ts +12 -0
  234. package/dist/features/products/api/route.js +42 -100
  235. package/dist/features/products/components/ArtStickersListView.js +2 -2
  236. package/dist/features/products/components/AuctionsIndexListing.js +13 -11
  237. package/dist/features/products/components/AvailabilityTabs.d.ts +11 -0
  238. package/dist/features/products/components/AvailabilityTabs.js +47 -0
  239. package/dist/features/products/components/MakeOfferButton.js +48 -49
  240. package/dist/features/products/components/PrizeDrawCollage.d.ts +20 -4
  241. package/dist/features/products/components/PrizeDrawCollage.js +9 -1
  242. package/dist/features/products/components/PrizeDrawsIndexListing.js +14 -12
  243. package/dist/features/products/components/PrizeDrawsListingView.js +2 -2
  244. package/dist/features/products/components/PrizeDrawsSection.d.ts +7 -1
  245. package/dist/features/products/components/PrizeDrawsSection.js +23 -18
  246. package/dist/features/products/components/ProductDetailPageView.d.ts +4 -1
  247. package/dist/features/products/components/ProductDetailPageView.js +18 -4
  248. package/dist/features/products/components/ProductForm.js +5 -2
  249. package/dist/features/products/components/ProductGrid.js +6 -1
  250. package/dist/features/products/components/ProductsIndexListing.js +22 -32
  251. package/dist/features/products/components/ProductsIndexPageView.js +6 -9
  252. package/dist/features/products/components/index.d.ts +2 -2
  253. package/dist/features/products/components/index.js +1 -1
  254. package/dist/features/products/config/listing-type-listing-config.d.ts +20 -0
  255. package/dist/features/products/config/listing-type-listing-config.js +22 -10
  256. package/dist/features/products/constants/action-defs.d.ts +2 -0
  257. package/dist/features/products/constants/action-defs.js +6 -0
  258. package/dist/features/products/hooks/useAvailabilityScope.d.ts +13 -0
  259. package/dist/features/products/hooks/useAvailabilityScope.js +19 -0
  260. package/dist/features/products/hooks/useProducts.d.ts +5 -0
  261. package/dist/features/products/hooks/useProducts.js +13 -2
  262. package/dist/features/products/repository/products.repository.d.ts +31 -2
  263. package/dist/features/products/repository/products.repository.js +53 -21
  264. package/dist/features/products/schemas/firestore.d.ts +17 -3
  265. package/dist/features/products/schemas/firestore.js +7 -2
  266. package/dist/features/products/schemas/index.d.ts +66 -66
  267. package/dist/features/products/schemas/product-features.validators.d.ts +6 -6
  268. package/dist/features/products/types/index.d.ts +16 -1
  269. package/dist/features/promotions/schemas/index.d.ts +2 -2
  270. package/dist/features/reviews/schemas/index.d.ts +16 -16
  271. package/dist/features/search/schemas/index.d.ts +4 -4
  272. package/dist/features/seller/actions/offer-actions.js +25 -2
  273. package/dist/features/seller/components/SellerArtView.js +5 -0
  274. package/dist/features/seller/components/SellerAuctionsView.js +13 -15
  275. package/dist/features/seller/components/SellerClassifiedView.js +5 -0
  276. package/dist/features/seller/components/SellerDigitalCodesView.js +5 -0
  277. package/dist/features/seller/components/SellerLiveView.js +5 -0
  278. package/dist/features/seller/components/SellerOrdersView.js +31 -9
  279. package/dist/features/seller/components/SellerPayoutSettingsView.js +19 -18
  280. package/dist/features/seller/components/SellerPreOrdersView.js +5 -0
  281. package/dist/features/seller/components/SellerPrizeDrawsView.js +14 -16
  282. package/dist/features/seller/components/SellerProductShell.js +7 -1
  283. package/dist/features/seller/components/SellerProductsView.js +11 -8
  284. package/dist/features/seller/components/SellerStickersView.js +5 -0
  285. package/dist/features/seller/components/index.d.ts +0 -2
  286. package/dist/features/seller/components/index.js +0 -1
  287. package/dist/features/seller/repository/offer.repository.d.ts +73 -16
  288. package/dist/features/seller/repository/offer.repository.js +38 -3
  289. package/dist/features/seller/schemas/index.d.ts +2 -2
  290. package/dist/features/seller/schemas/offer-forms.d.ts +25 -0
  291. package/dist/features/seller/schemas/offer-forms.js +21 -0
  292. package/dist/features/seller/server.d.ts +0 -1
  293. package/dist/features/seller/server.js +0 -1
  294. package/dist/features/shell/SectionForm.d.ts +99 -0
  295. package/dist/features/shell/SectionForm.js +128 -0
  296. package/dist/features/shell/entity-form.d.ts +109 -0
  297. package/dist/features/shell/entity-form.js +96 -0
  298. package/dist/features/shell/index.d.ts +4 -0
  299. package/dist/features/shell/index.js +2 -0
  300. package/dist/features/stores/api/[storeSlug]/route.js +2 -25
  301. package/dist/features/stores/components/StoreAuctionsListing.js +15 -1
  302. package/dist/features/stores/components/StoreClassifiedsListing.js +12 -2
  303. package/dist/features/stores/components/StoreDetailLayoutView.js +24 -71
  304. package/dist/features/stores/components/StoreDigitalCodesListing.js +12 -2
  305. package/dist/features/stores/components/StoreLiveItemsListing.js +12 -2
  306. package/dist/features/stores/components/StorePreOrdersListing.js +12 -1
  307. package/dist/features/stores/components/StoreProductsListing.js +11 -1
  308. package/dist/features/stores/repository/store.repository.js +6 -0
  309. package/dist/features/stores/schemas/index.d.ts +6 -6
  310. package/dist/features/support/schemas/index.d.ts +4 -4
  311. package/dist/features/tester/actions/checklist-item-actions.d.ts +4 -4
  312. package/dist/features/tester/seed-data/offers-tester-seed-data.js +119 -3
  313. package/dist/features/tester/seed-data/products-tester-seed-data.js +131 -1
  314. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +105 -1
  315. package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
  316. package/dist/index.d.ts +13 -10
  317. package/dist/index.js +14 -9
  318. package/dist/next/routing/route-map.d.ts +7 -1
  319. package/dist/next/routing/route-map.js +5 -0
  320. package/dist/providers/db-firebase/base.repository.d.ts +30 -0
  321. package/dist/providers/db-firebase/base.repository.js +50 -1
  322. package/dist/providers/db-firebase/index.d.ts +1 -1
  323. package/dist/providers/db-firebase/index.js +1 -1
  324. package/dist/providers/db-firebase/sieve.d.ts +25 -0
  325. package/dist/providers/db-firebase/sieve.js +52 -18
  326. package/dist/react/hooks/useUrlTable.js +10 -1
  327. package/dist/schemas/registry.d.ts +68 -68
  328. package/dist/seed/_helpers/category-forest.d.ts +2 -0
  329. package/dist/seed/_helpers/category-forest.js +309 -0
  330. package/dist/seed/_helpers/category-tree.d.ts +27 -0
  331. package/dist/seed/_helpers/category-tree.js +103 -0
  332. package/dist/seed/catalogue-seed-data.js +12 -12
  333. package/dist/seed/categories-seed-data.js +177 -162
  334. package/dist/seed/events-seed-data.js +61 -10
  335. package/dist/seed/homepage-sections-seed-data.js +5 -1
  336. package/dist/seed/offers-seed-data.js +32 -27
  337. package/dist/seed/products-art-seed-data.js +50 -12
  338. package/dist/seed/products-auctions-seed-data.js +97 -18
  339. package/dist/seed/products-classifieds-seed-data.js +80 -16
  340. package/dist/seed/products-digital-codes-seed-data.js +66 -18
  341. package/dist/seed/products-live-items-seed-data.js +64 -13
  342. package/dist/seed/products-preorders-seed-data.d.ts +0 -1
  343. package/dist/seed/products-preorders-seed-data.js +52 -13
  344. package/dist/seed/products-prize-draws-seed-data.js +63 -14
  345. package/dist/seed/products-standard-seed-data.js +99 -26
  346. package/dist/seed/products-stickers-seed-data.js +47 -12
  347. package/dist/seed/reviews-seed-data.js +6 -1
  348. package/dist/seed/site-settings-seed-data.d.ts +1 -38
  349. package/dist/seed/site-settings-seed-data.js +38 -76
  350. package/dist/seed/stores-seed-data.js +71 -1
  351. package/dist/seed/users-seed-data.js +15 -5
  352. package/dist/server-entry.d.ts +1 -2
  353. package/dist/server-entry.js +4 -3
  354. package/dist/server.d.ts +4 -3
  355. package/dist/server.js +8 -4
  356. package/dist/styles.css +78 -12
  357. package/dist/tailwind-utilities.css +1 -1
  358. package/dist/ui/components/Button.style.css +19 -4
  359. package/dist/ui/components/CollapsibleSection.d.ts +17 -1
  360. package/dist/ui/components/CollapsibleSection.js +6 -2
  361. package/dist/ui/components/FilterChipGroup.d.ts +25 -1
  362. package/dist/ui/components/FilterChipGroup.js +21 -4
  363. package/dist/ui/components/HandMode.style.css +47 -0
  364. package/dist/ui/components/Layout.d.ts +9 -2
  365. package/dist/ui/components/Layout.js +1 -1
  366. package/dist/ui/components/ListingLayout.js +8 -8
  367. package/dist/ui/components/ListingLayout.style.css +8 -7
  368. package/dist/ui/components/StickyToolbar.d.ts +3 -1
  369. package/dist/ui/components/StickyToolbar.js +62 -20
  370. package/dist/ui/components/bottom-chrome-slot.d.ts +21 -0
  371. package/dist/ui/components/bottom-chrome-slot.js +29 -0
  372. package/dist/ui/components/index.style.css +3 -0
  373. package/dist/ui/forms/FormShell.d.ts +43 -13
  374. package/dist/ui/forms/FormShell.js +22 -11
  375. package/dist/ui/forms/index.d.ts +1 -1
  376. package/dist/ui/index.d.ts +1 -1
  377. package/package.json +2 -2
@@ -21,6 +21,9 @@ import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
21
21
  import { TABLE_KEYS, VIEW_MODE } from "../../../constants/table-keys";
22
22
  import { PREORDER_SORT_OPTIONS } from "../../products/constants/sieve";
23
23
  import { useBottomActions } from "../../layout";
24
+ import { AVAILABILITY_VALUES } from "../../../constants/field-names";
25
+ import { AvailabilityTabs } from "../../products/components/AvailabilityTabs";
26
+ const PRE_ORDER_LISTING_TYPES = ["pre-order"];
24
27
  const __P = {
25
28
  p3: "p-[var(--appkit-space-3)]",
26
29
  };
@@ -36,7 +39,8 @@ export function PreOrdersIndexListing({ initialData, categorySlug, brandName })
36
39
  const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
37
40
  const [filterOpen, setFilterOpen] = useState(false);
38
41
  const [compareIds, setCompareIds] = useState([]);
39
- const showClosed = table.get(TABLE_KEYS.SHOW_CLOSED) === "true";
42
+ const availability = table.get(TABLE_KEYS.AVAILABILITY) ||
43
+ AVAILABILITY_VALUES.AVAILABLE;
40
44
  const [view, setView] = useState(table.get(TABLE_KEYS.VIEW) || VIEW_MODE.GRID);
41
45
  const localCart = useGuestCart();
42
46
  const localWishlist = useGuestWishlist();
@@ -54,11 +58,11 @@ export function PreOrdersIndexListing({ initialData, categorySlug, brandName })
54
58
  setFilterOpen(false);
55
59
  }, [onFilterApply]);
56
60
  const resetAll = useCallback(() => {
57
- onResetAll({ [TABLE_KEYS.QUERY]: "", [TABLE_KEYS.SORT]: "", [TABLE_KEYS.SHOW_CLOSED]: "" });
61
+ onResetAll({ [TABLE_KEYS.QUERY]: "", [TABLE_KEYS.SORT]: "", [TABLE_KEYS.AVAILABILITY]: "" });
58
62
  setSearchInput("");
59
63
  }, [onResetAll]);
60
64
  const hasActiveState = !!table.get(TABLE_KEYS.QUERY) ||
61
- table.get(TABLE_KEYS.SHOW_CLOSED) === "true" ||
65
+ availability !== AVAILABILITY_VALUES.AVAILABLE ||
62
66
  table.get(TABLE_KEYS.SORT) !== DEFAULT_SORT ||
63
67
  filterActiveCount > 0;
64
68
  const params = {
@@ -76,9 +80,12 @@ export function PreOrdersIndexListing({ initialData, categorySlug, brandName })
76
80
  page: table.getNumber(TABLE_KEYS.PAGE, 1),
77
81
  perPage: table.getNumber(TABLE_KEYS.PAGE_SIZE, 24),
78
82
  listingType: "pre-order",
79
- // Hide out-of-stock pre-orders by default. Uses stockQuantity>0 (always-present field).
80
- // Quota over-sign is intentional — never block pre-orders by availability.
81
- inStock: showClosed ? undefined : true,
83
+ // "Closed" for a pre-order means its allocation filled, which the shared
84
+ // per-type predicate resolves from preOrderCurrentCount vs
85
+ // preOrderMaxQuantity. This used to be a bare stockQuantity>0, which is
86
+ // a DIFFERENT question and disagreed with what /products asked of the
87
+ // same rows.
88
+ availability,
82
89
  };
83
90
  const { products: preOrders, totalPages, page, isLoading } = useProducts(params, { initialData });
84
91
  const commitSearch = useCallback(() => {
@@ -175,9 +182,7 @@ export function PreOrdersIndexListing({ initialData, categorySlug, brandName })
175
182
  },
176
183
  },
177
184
  ] } } : {});
178
- return (_jsxs(Div, { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search pre-orders...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, onSearchKeyDown: handleSearchKeyDown, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: PREORDER_SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, view: view, onViewChange: handleViewToggle, onResetAll: resetAll, hasActiveState: hasActiveState, bulkMode: selection.isSelecting, bulkSelectedCount: selection.selectedCount, bulkTotalCount: preOrders.length, onBulkSelectAll: selection.toggleAll, onBulkClear: selection.clearSelection, toggles: [
179
- { label: "Show closed", active: showClosed, onChange: (next) => table.set(TABLE_KEYS.SHOW_CLOSED, next ? "true" : "") },
180
- ] }), _jsx(BulkActionBar, { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [
185
+ return (_jsxs(Div, { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search pre-orders...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, onSearchKeyDown: handleSearchKeyDown, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: PREORDER_SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, view: view, onViewChange: handleViewToggle, onResetAll: resetAll, hasActiveState: hasActiveState, bulkMode: selection.isSelecting, bulkSelectedCount: selection.selectedCount, bulkTotalCount: preOrders.length, onBulkSelectAll: selection.toggleAll, onBulkClear: selection.clearSelection }), _jsx(Div, { padding: "y-sm", children: _jsx(AvailabilityTabs, { types: PRE_ORDER_LISTING_TYPES }) }), _jsx(BulkActionBar, { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [
181
186
  {
182
187
  id: ACTION_ID.ADD_TO_CART,
183
188
  label: ACTION_META[ACTION_ID.ADD_TO_CART].label,
@@ -2,19 +2,20 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Container, Main, Heading, Section } from "../../../ui";
3
3
  import { AdSlot } from "../../homepage/components/AdSlot";
4
4
  import { PreOrdersIndexListing } from "./PreOrdersIndexListing";
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 PRE_ORDER_LISTING_TYPES = ["pre-order"];
7
7
  const DEFAULT_PAGE_SIZE = 24;
8
8
  const DEFAULT_SORT = "-createdAt";
9
9
  export async function PreOrdersListView({ searchParams = {} }) {
10
- // Shared with /api/products. `hideSoldByDefault` covers this page's
11
- // "Show closed" toggle — the stockQuantity predicate runs in memory over a
12
- // bounded fetch because the default sort is createdAt, not stockQuantity.
10
+ // Shared with /api/products, and derived rather than hardcoded. This view
11
+ // carried a literal `hideSoldByDefault: true` until 2026-08-24 even though
12
+ // pre-order's registered hide-default is "closed" — so /pre-orders and
13
+ // /products disagreed about what "closed" meant for the same rows.
13
14
  const result = await listPublicProducts(parsePublicProductParams(searchParams, {
14
15
  listingTypes: PRE_ORDER_LISTING_TYPES,
15
16
  pageSize: DEFAULT_PAGE_SIZE,
16
17
  sorts: DEFAULT_SORT,
17
- hideSoldByDefault: true,
18
+ ...defaultAvailabilityForListingTypes(PRE_ORDER_LISTING_TYPES),
18
19
  }));
19
20
  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: "Pre-Orders" }), _jsx(AdSlot, { id: "listing-sidebar-top", className: "mb-6" }), _jsx(PreOrdersIndexListing, { initialData: result ?? undefined }), _jsx(AdSlot, { id: "listing-sidebar-bottom", className: "mt-8" })] }) }) }));
20
21
  }
@@ -79,6 +79,7 @@ export declare const preorderItemSchema: z.ZodObject<{
79
79
  createdAt?: string | undefined;
80
80
  active?: boolean | undefined;
81
81
  images?: string[] | undefined;
82
+ isFeatured?: boolean | undefined;
82
83
  media?: {
83
84
  type: "video" | "image" | "file";
84
85
  url: string;
@@ -88,7 +89,6 @@ export declare const preorderItemSchema: z.ZodObject<{
88
89
  youtubeId?: string | undefined;
89
90
  duration?: number | undefined;
90
91
  }[] | undefined;
91
- isFeatured?: boolean | undefined;
92
92
  franchise?: string | undefined;
93
93
  preorderShipDate?: string | undefined;
94
94
  }>;
@@ -16,10 +16,24 @@ export type ProductListResult = FirebaseSieveResult<ProductDocument>;
16
16
  export declare function listProducts(params?: ProductListActionParams): Promise<ProductListResult>;
17
17
  export declare function getProductById(id: string): Promise<ProductDocument | null>;
18
18
  export declare function getFeaturedProducts(pageSize?: number): Promise<ProductListResult>;
19
+ /**
20
+ * The soonest-ending LIVE auctions.
21
+ *
22
+ * This used to be `listingType==auction,status==published` sorted
23
+ * `auctionEndDate ASC` with no lower bound — and ascending order front-loads
24
+ * the OLDEST end dates, so the homepage's "Live Auctions" strip led with the
25
+ * most-expired lots in the catalogue. Nothing about it was flagged as wrong
26
+ * because an ended auction still renders as a perfectly normal card.
27
+ *
28
+ * One listing type, sorted by the same field the scope filters on, means
29
+ * `listPublicProducts` pushes `auctionEndDate >= now` into Firestore rather
30
+ * than filtering a bounded window in memory.
31
+ */
19
32
  export declare function getFeaturedAuctions(pageSize?: number): Promise<ProductListResult>;
20
33
  export declare function getLatestProducts(pageSize?: number): Promise<ProductListResult>;
21
34
  export declare function getLatestAuctions(pageSize?: number): Promise<ProductListResult>;
22
35
  export declare function listAuctions(params?: ProductListActionParams): Promise<ProductListResult>;
36
+ /** Pre-orders still accepting orders, soonest delivery first. */
23
37
  export declare function getFeaturedPreOrders(pageSize?: number): Promise<ProductListResult>;
24
38
  export declare function getLatestPreOrders(pageSize?: number): Promise<ProductListResult>;
25
39
  export declare function listPreOrders(params?: ProductListActionParams): Promise<ProductListResult>;
@@ -1,5 +1,7 @@
1
1
  import { sieveAnd, sieveFilter, SIEVE_OP } from "@mohasinac/appkit";
2
2
  import { sortBy } from "@mohasinac/appkit";
3
+ import { listPublicProducts } from "../../../_internal/server/features/products/list-public";
4
+ import { AVAILABILITY_VALUES, PRODUCT_FIELDS } from "../../../constants/field-names";
3
5
  import { productRepository } from "../repository/products.repository";
4
6
  import { ProductStatusValues } from "../schemas";
5
7
  /**
@@ -34,21 +36,55 @@ export async function listProducts(params = {}) {
34
36
  export async function getProductById(id) {
35
37
  return productRepository.findById(id);
36
38
  }
39
+ /**
40
+ * `PublicProductListResult` → the `FirebaseSieveResult<ProductDocument>` shape
41
+ * these helpers have always returned, so their ~15 call sites (including the
42
+ * six server-action wrappers in `src/actions/product.actions.ts` and their
43
+ * tests) are unchanged by the switch to the shared query.
44
+ */
45
+ function toListResult(result, pageSize) {
46
+ if (!result) {
47
+ return { items: [], total: 0, page: 1, pageSize, totalPages: 0, hasMore: false };
48
+ }
49
+ return {
50
+ items: result.items,
51
+ total: result.total,
52
+ page: result.page,
53
+ pageSize: result.pageSize,
54
+ totalPages: result.totalPages,
55
+ hasMore: result.hasMore,
56
+ };
57
+ }
37
58
  export async function getFeaturedProducts(pageSize = 8) {
38
- return productRepository.list({
39
- filters: sieveAnd(sieveFilter("featured", SIEVE_OP.EQ, "true"), PUBLISHED_CLAUSE),
59
+ return toListResult(await listPublicProducts({
60
+ featured: true,
61
+ availability: AVAILABILITY_VALUES.AVAILABLE,
40
62
  sorts: sortBy("createdAt", "DESC"),
41
63
  page: 1,
42
64
  pageSize,
43
- });
65
+ }), pageSize);
44
66
  }
67
+ /**
68
+ * The soonest-ending LIVE auctions.
69
+ *
70
+ * This used to be `listingType==auction,status==published` sorted
71
+ * `auctionEndDate ASC` with no lower bound — and ascending order front-loads
72
+ * the OLDEST end dates, so the homepage's "Live Auctions" strip led with the
73
+ * most-expired lots in the catalogue. Nothing about it was flagged as wrong
74
+ * because an ended auction still renders as a perfectly normal card.
75
+ *
76
+ * One listing type, sorted by the same field the scope filters on, means
77
+ * `listPublicProducts` pushes `auctionEndDate >= now` into Firestore rather
78
+ * than filtering a bounded window in memory.
79
+ */
45
80
  export async function getFeaturedAuctions(pageSize = 6) {
46
- return productRepository.list({
47
- filters: AUCTIONS_PUBLISHED,
48
- sorts: sortBy("auctionEndDate", "ASC"),
81
+ return toListResult(await listPublicProducts({
82
+ listingTypes: [PRODUCT_FIELDS.LISTING_TYPE_VALUES.AUCTION],
83
+ availability: AVAILABILITY_VALUES.AVAILABLE,
84
+ sorts: sortBy(PRODUCT_FIELDS.AUCTION_END_DATE, "ASC"),
49
85
  page: 1,
50
86
  pageSize,
51
- });
87
+ }), pageSize);
52
88
  }
53
89
  export async function getLatestProducts(pageSize = 12) {
54
90
  return productRepository.list({
@@ -75,13 +111,15 @@ export async function listAuctions(params = {}) {
75
111
  pageSize,
76
112
  });
77
113
  }
114
+ /** Pre-orders still accepting orders, soonest delivery first. */
78
115
  export async function getFeaturedPreOrders(pageSize = 6) {
79
- return productRepository.list({
80
- filters: PREORDERS_PUBLISHED,
81
- sorts: sortBy("preOrderDeliveryDate", "ASC"),
116
+ return toListResult(await listPublicProducts({
117
+ listingTypes: [PRODUCT_FIELDS.LISTING_TYPE_VALUES.PRE_ORDER],
118
+ availability: AVAILABILITY_VALUES.AVAILABLE,
119
+ sorts: sortBy(PRODUCT_FIELDS.PRE_ORDER_DELIVERY_DATE, "ASC"),
82
120
  page: 1,
83
121
  pageSize,
84
- });
122
+ }), pageSize);
85
123
  }
86
124
  export async function getLatestPreOrders(pageSize = 12) {
87
125
  return productRepository.list({
@@ -13,6 +13,18 @@
13
13
  * resolved from `getProviders().db.getRepository("products")`.
14
14
  */
15
15
  import { NextResponse } from "next/server.js";
16
+ /**
17
+ * Delegates to `listPublicProducts` — the single implementation shared with
18
+ * every SSR listing view and with the reference consumer's own route.
19
+ *
20
+ * It used to be an independent copy: its own `buildFilters`, its own
21
+ * `validateSieveFilters`, and its own filter allowlist that omitted
22
+ * `auctionEndDate` / `preOrderDeliveryDate` / `prizeRevealStatus` — so on this
23
+ * path an ended auction could not be filtered out even by a caller that asked
24
+ * for it, and an `inStock=true` became a raw `stockQuantity>0` pushed straight
25
+ * into Firestore, the FAILED_PRECONDITION shape Root Cause #59 documents.
26
+ * Two implementations of one query is the drift itself; there is now one.
27
+ */
16
28
  export declare function GET(request: Request): Promise<NextResponse>;
17
29
  export declare const POST: (request: Request, context?: {
18
30
  params: Promise<Record<string, string>>;
@@ -19,6 +19,7 @@ import { createRouteHandler } from "../../../next";
19
19
  import { mediaFieldSchema } from "../../media/types/index";
20
20
  import { printMetaSchema } from "../schemas/index";
21
21
  import { sanitizeProductsForPublic } from "../utils/sanitize";
22
+ import { listPublicProducts, parsePublicProductParams, } from "../../../_internal/server/features/products/list-public";
22
23
  import { normalizeError } from "../../../errors/normalize";
23
24
  // --- Mutation schemas ---------------------------------------------------------
24
25
  // Minimal schemas for secured mutations — consumer apps can extend as needed.
@@ -49,8 +50,11 @@ const productMutateSchema = z
49
50
  sellerName: z.string().optional(),
50
51
  sellerEmail: z.string().email().optional(),
51
52
  slug: z.string().optional(),
53
+ // `bundle` is deliberately absent: SB-UNI-D moved bundles onto
54
+ // `categories` as a categoryType, so a product written with that value
55
+ // would match no listing-type query anywhere.
52
56
  listingType: z
53
- .enum(["standard", "auction", "pre-order", "prize-draw", "bundle", "classified", "digital-code", "live", "art", "stickers"])
57
+ .enum(["standard", "auction", "pre-order", "prize-draw", "classified", "digital-code", "live", "art", "stickers"])
54
58
  .optional(),
55
59
  media: z.array(mediaFieldSchema).optional(),
56
60
  })
@@ -59,114 +63,52 @@ const productMutateSchema = z
59
63
  function param(url, key) {
60
64
  return url.searchParams.get(key);
61
65
  }
62
- function numParam(url, key, fallback) {
63
- const v = url.searchParams.get(key);
64
- const n = v !== null ? Number(v) : NaN;
65
- return Number.isFinite(n) ? n : fallback;
66
- }
67
- /** Public fields callers may filter on via the ?filters= param. */
68
- const SAFE_PRODUCT_FILTER_FIELDS = new Set([
69
- "status",
70
- "category",
71
- "brand",
72
- "condition",
73
- "storeId",
74
- "title",
75
- "price",
76
- "listingType",
77
- "featured",
78
- "isPromoted",
79
- "stockQuantity",
80
- "availableQuantity",
81
- "tags",
82
- ]);
66
+ // --- GET /api/products --------------------------------------------------------
83
67
  /**
84
- * Validates a raw Sieve filter string against an allowlist of safe fields.
85
- * Drops any clause whose field name is not in the allowlist.
68
+ * Delegates to `listPublicProducts` — the single implementation shared with
69
+ * every SSR listing view and with the reference consumer's own route.
70
+ *
71
+ * It used to be an independent copy: its own `buildFilters`, its own
72
+ * `validateSieveFilters`, and its own filter allowlist that omitted
73
+ * `auctionEndDate` / `preOrderDeliveryDate` / `prizeRevealStatus` — so on this
74
+ * path an ended auction could not be filtered out even by a caller that asked
75
+ * for it, and an `inStock=true` became a raw `stockQuantity>0` pushed straight
76
+ * into Firestore, the FAILED_PRECONDITION shape Root Cause #59 documents.
77
+ * Two implementations of one query is the drift itself; there is now one.
86
78
  */
87
- function validateSieveFilters(raw, allowedFields) {
88
- return raw
89
- .split(",")
90
- .map((c) => c.trim())
91
- .filter((c) => {
92
- const m = c.match(/^([^<>=!@]+)\s*(?:==|!=|<=|>=|<|>|@=\*?)/);
93
- return m ? allowedFields.has(m[1].trim()) : false;
94
- })
95
- .join(",");
96
- }
97
- function buildFilters(url) {
98
- const parts = [];
99
- const status = param(url, "status");
100
- if (status)
101
- parts.push(`status==${status}`);
102
- const category = param(url, "category");
103
- if (category)
104
- parts.push(`category==${category}`);
105
- const brand = param(url, "brand");
106
- if (brand)
107
- parts.push(`brand==${brand}`);
108
- const condition = param(url, "condition");
109
- if (condition)
110
- parts.push(`condition==${condition}`);
111
- const storeId = param(url, "storeId");
112
- if (storeId)
113
- parts.push(`storeId==${storeId}`);
114
- const q = param(url, "q");
115
- if (q)
116
- parts.push(`title@=*${q}`);
117
- const minPrice = param(url, "minPrice");
118
- if (minPrice !== null && !Number.isNaN(Number(minPrice)))
119
- parts.push(`price>=${minPrice}`);
120
- const maxPrice = param(url, "maxPrice");
121
- if (maxPrice !== null && !Number.isNaN(Number(maxPrice)))
122
- parts.push(`price<=${maxPrice}`);
123
- const inStock = param(url, "inStock");
124
- if (inStock === "true")
125
- parts.push("stockQuantity>0");
126
- // SB1-G — canonical discriminator. Public URL accepts only ?listingType=X.
127
- const listingTypeParam = param(url, "listingType");
128
- if (listingTypeParam) {
129
- parts.push(`listingType==${listingTypeParam}`);
130
- }
131
- const featured = param(url, "featured");
132
- if (featured === "true")
133
- parts.push("featured==true");
134
- // Merge validated Sieve filters — only safe public fields allowed
135
- const raw = param(url, "filters");
136
- if (raw) {
137
- const safe = validateSieveFilters(raw, SAFE_PRODUCT_FILTER_FIELDS);
138
- if (safe)
139
- parts.push(safe);
140
- }
141
- return parts.join(",");
142
- }
143
- // --- GET /api/products --------------------------------------------------------
144
79
  export async function GET(request) {
145
80
  try {
146
81
  const url = new URL(request.url);
147
- const page = numParam(url, "page", 1);
148
- const pageSize = numParam(url, "pageSize", 20);
149
- const sort = param(url, "sorts") ?? param(url, "sort") ?? "-createdAt";
150
- const filters = buildFilters(url);
151
- const { db } = getProviders();
152
- if (!db) {
153
- return NextResponse.json({ success: false, error: "Database provider not registered" }, { status: 503 });
82
+ const listingTypeParam = param(url, "listingType");
83
+ const requestedTypes = (listingTypeParam ?? "").split("|").filter(Boolean);
84
+ const result = await listPublicProducts(parsePublicProductParams(url.searchParams, {
85
+ listingTypes: requestedTypes.length > 0 ? requestedTypes : undefined,
86
+ }));
87
+ if (!result) {
88
+ // Already logged loudly by listPublicProducts. Surfaced as an explicit
89
+ // warning rather than a bare empty page, so a broken query stays
90
+ // distinguishable from an empty catalogue.
91
+ return NextResponse.json({
92
+ success: true,
93
+ data: {
94
+ items: [],
95
+ total: 0,
96
+ page: 1,
97
+ pageSize: 0,
98
+ totalPages: 0,
99
+ hasMore: false,
100
+ warning: "Product search is temporarily unavailable.",
101
+ },
102
+ });
154
103
  }
155
- const repo = db.getRepository("products");
156
- const result = await repo.findAll({
157
- filters,
158
- sort,
159
- page,
160
- perPage: pageSize,
161
- });
162
- const totalPages = Math.max(1, Math.ceil(result.total / pageSize));
163
104
  const body = {
164
- items: sanitizeProductsForPublic(result.data),
105
+ items: sanitizeProductsForPublic(result.items),
165
106
  total: result.total,
166
107
  page: result.page,
167
- pageSize,
168
- totalPages,
169
- hasMore: result.page < totalPages,
108
+ pageSize: result.pageSize,
109
+ totalPages: result.totalPages,
110
+ hasMore: result.hasMore,
111
+ truncated: result.truncated,
170
112
  };
171
113
  const response = NextResponse.json({ success: true, data: body });
172
114
  response.headers.set("Cache-Control", "public, max-age=60, s-maxage=120, stale-while-revalidate=60");
@@ -5,7 +5,7 @@ import { ProductsIndexListing } from "./ProductsIndexListing";
5
5
  import { PRODUCT_FIELDS } from "../../../constants/field-names";
6
6
  import { sortBy } from "../../../constants/sort";
7
7
  import { ART_STICKERS_TYPE_FILTER_TABS, ART_STICKERS_LISTING_TYPES, } from "../constants/listing-tabs";
8
- import { listPublicProducts, parsePublicProductParams, defaultTogglesForListingTypes, } from "../../../_internal/server/features/products/list-public";
8
+ import { listPublicProducts, parsePublicProductParams, defaultAvailabilityForListingTypes, } from "../../../_internal/server/features/products/list-public";
9
9
  const DEFAULT_PAGE_SIZE = 24;
10
10
  const DEFAULT_SORT = sortBy(PRODUCT_FIELDS.CREATED_AT);
11
11
  export async function ArtStickersListView({ searchParams = {} }) {
@@ -18,7 +18,7 @@ export async function ArtStickersListView({ searchParams = {} }) {
18
18
  sorts: DEFAULT_SORT,
19
19
  // Derived, so this page and ProductsIndexListing can never disagree
20
20
  // about the default view (Root Cause #30).
21
- ...defaultTogglesForListingTypes(ART_STICKERS_LISTING_TYPES),
21
+ ...defaultAvailabilityForListingTypes(ART_STICKERS_LISTING_TYPES),
22
22
  }));
23
23
  return (_jsxs(Main, { children: [_jsx(Section, { border: "bottom-subtle", paddingY: "b-md", padding: "t-xl", children: _jsxs(Container, { size: "xl", children: [_jsx(Heading, { level: 1, size: "3xl", weight: "bold", color: "primary", children: "Art & Stickers" }), _jsx(Text, { className: "mt-1", color: "muted", size: "sm", children: "Original art prints and sticker packs from independent sellers" })] }) }), _jsxs(Container, { size: "xl", padding: "x-md", children: [_jsx(AdSlot, { id: "listing-sidebar-top", className: "mb-4 mt-4" }), _jsx(ProductsIndexListing, { initialData: result ?? null, listingTypes: ART_STICKERS_LISTING_TYPES, typeTabs: ART_STICKERS_TYPE_FILTER_TABS, searchPlaceholder: "Search art & stickers..." }), _jsx(AdSlot, { id: "listing-sidebar-bottom", className: "mt-8" })] })] }));
24
24
  }
@@ -17,6 +17,8 @@ import { useAuthGate } from "../../../react/hooks/useAuthGate";
17
17
  import { ACTION_ID } from "../constants/action-defs";
18
18
  import { AUCTION_PUBLIC_SORT_OPTIONS } from "../constants/sieve";
19
19
  import { useBottomActions } from "../../layout";
20
+ import { AVAILABILITY_VALUES } from "../../../constants/field-names";
21
+ import { AvailabilityTabs } from "./AvailabilityTabs";
20
22
  const __P = {
21
23
  p3: "p-[var(--appkit-space-3)]",
22
24
  };
@@ -24,6 +26,7 @@ const __O = {
24
26
  hidden: "overflow-hidden",
25
27
  };
26
28
  const DEFAULT_SORT = AUCTION_PUBLIC_SORT_OPTIONS[0].value;
29
+ const AUCTION_LISTING_TYPES = ["auction"];
27
30
  const FILTER_KEYS = [TABLE_KEYS.CATEGORY, TABLE_KEYS.BRAND, TABLE_KEYS.MIN_BID, TABLE_KEYS.MAX_BID, TABLE_KEYS.STORE_ID, TABLE_KEYS.DATE_FROM, TABLE_KEYS.DATE_TO];
28
31
  export function AuctionsIndexListing({ initialData, categorySlug, brandName }) {
29
32
  const table = useUrlTable({ defaults: { pageSize: "24", sort: DEFAULT_SORT } });
@@ -31,7 +34,8 @@ export function AuctionsIndexListing({ initialData, categorySlug, brandName }) {
31
34
  const { requireAuth, modalOpen, modalMessage, closeModal } = useAuthGate();
32
35
  const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
33
36
  const [filterOpen, setFilterOpen] = useState(false);
34
- const showEnded = table.get(TABLE_KEYS.SHOW_ENDED) === "true";
37
+ const availability = table.get(TABLE_KEYS.AVAILABILITY) ||
38
+ AVAILABILITY_VALUES.AVAILABLE;
35
39
  const [view, setView] = useState(table.get(TABLE_KEYS.VIEW) || VIEW_MODE.GRID);
36
40
  const localWishlist = useGuestWishlist();
37
41
  const wishlistedIds = new Set(localWishlist.items.filter((i) => i.type === "auction").map((i) => i.itemId));
@@ -48,11 +52,11 @@ export function AuctionsIndexListing({ initialData, categorySlug, brandName }) {
48
52
  setFilterOpen(false);
49
53
  }, [onFilterApply]);
50
54
  const resetAll = useCallback(() => {
51
- onResetAll({ [TABLE_KEYS.QUERY]: "", [TABLE_KEYS.SORT]: "", [TABLE_KEYS.SHOW_ENDED]: "" });
55
+ onResetAll({ [TABLE_KEYS.QUERY]: "", [TABLE_KEYS.SORT]: "", [TABLE_KEYS.AVAILABILITY]: "" });
52
56
  setSearchInput("");
53
57
  }, [onResetAll]);
54
58
  const hasActiveState = !!table.get(TABLE_KEYS.QUERY) ||
55
- table.get(TABLE_KEYS.SHOW_ENDED) === "true" ||
59
+ availability !== AVAILABILITY_VALUES.AVAILABLE ||
56
60
  table.get(TABLE_KEYS.SORT) !== DEFAULT_SORT ||
57
61
  filterActiveCount > 0;
58
62
  const params = {
@@ -63,16 +67,16 @@ export function AuctionsIndexListing({ initialData, categorySlug, brandName }) {
63
67
  minBid: table.get(TABLE_KEYS.MIN_BID) ? Number(table.get(TABLE_KEYS.MIN_BID)) : undefined,
64
68
  maxBid: table.get(TABLE_KEYS.MAX_BID) ? Number(table.get(TABLE_KEYS.MAX_BID)) : undefined,
65
69
  storeId: table.get(TABLE_KEYS.STORE_ID) || undefined,
66
- // When showEnded is false (default), force dateFrom=now so only live auctions appear.
67
- // When showEnded is true, respect the filter-drawer value (or show all if none set).
68
- dateFrom: showEnded
69
- ? (table.get(TABLE_KEYS.DATE_FROM) || undefined)
70
- : new Date().toISOString(),
70
+ // Now purely the drawer's own end-date window. It used to double as the
71
+ // hide-ended mechanism, which meant the drawer facet and the toggle fought
72
+ // over one param; the scope tab owns that decision instead.
73
+ dateFrom: table.get(TABLE_KEYS.DATE_FROM) || undefined,
71
74
  dateTo: table.get(TABLE_KEYS.DATE_TO) || undefined,
72
75
  sort: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT,
73
76
  page: table.getNumber(TABLE_KEYS.PAGE, 1),
74
77
  perPage: table.getNumber(TABLE_KEYS.PAGE_SIZE, 24),
75
78
  listingType: "auction",
79
+ availability,
76
80
  };
77
81
  const { products: auctions, totalPages, page, isLoading } = useProducts(params, { initialData });
78
82
  const selection = useBulkSelection({ items: auctions, keyExtractor: (a) => a.id });
@@ -131,9 +135,7 @@ export function AuctionsIndexListing({ initialData, categorySlug, brandName }) {
131
135
  },
132
136
  },
133
137
  ] } } : {});
134
- return (_jsxs(Div, { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search auctions...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, onSearchKeyDown: handleSearchKeyDown, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: AUCTION_PUBLIC_SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, view: view, onViewChange: handleViewToggle, onResetAll: resetAll, hasActiveState: hasActiveState, bulkMode: selection.isSelecting, bulkSelectedCount: selection.selectedCount, bulkTotalCount: auctions.length, onBulkSelectAll: selection.toggleAll, onBulkClear: selection.clearSelection, toggles: [
135
- { label: "Show ended", active: showEnded, onChange: (next) => table.set(TABLE_KEYS.SHOW_ENDED, next ? "true" : "") },
136
- ] }), _jsx(BulkActionBar, { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [
138
+ return (_jsxs(Div, { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search auctions...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, onSearchKeyDown: handleSearchKeyDown, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: AUCTION_PUBLIC_SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, view: view, onViewChange: handleViewToggle, onResetAll: resetAll, hasActiveState: hasActiveState, bulkMode: selection.isSelecting, bulkSelectedCount: selection.selectedCount, bulkTotalCount: auctions.length, onBulkSelectAll: selection.toggleAll, onBulkClear: selection.clearSelection }), _jsx(Div, { padding: "y-sm", children: _jsx(AvailabilityTabs, { types: AUCTION_LISTING_TYPES }) }), _jsx(BulkActionBar, { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [
137
139
  {
138
140
  id: ACTION_ID.WATCH_AUCTION,
139
141
  label: "Add to Watchlist",
@@ -0,0 +1,11 @@
1
+ import React from "react";
2
+ import type { ListingType } from "../types";
3
+ export interface AvailabilityTabsProps {
4
+ /**
5
+ * The listing types the surface spans. Drives the middle tab's wording only
6
+ * — the scope itself means the same thing for every type.
7
+ */
8
+ types: readonly ListingType[];
9
+ className?: string;
10
+ }
11
+ export declare function AvailabilityTabs({ types, className }: AvailabilityTabsProps): React.JSX.Element;
@@ -0,0 +1,47 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ /*
4
+ * WHY: Every listing surface used to carry a "Show sold" / "Show ended" /
5
+ * "Show closed" pill that WIDENED the list — flipping it mixed dead rows
6
+ * into the live ones, so there was no way to browse the archive on its
7
+ * own, and no way to be sure the default view was clean. Three URL
8
+ * spellings of one intent had also accumulated, and each listing page
9
+ * hand-built its own toggle array, so the label and the SSR default
10
+ * drifted apart per page.
11
+ *
12
+ * WHAT: One three-tab scope bar — Available / <Sold & Ended> / All — shared by
13
+ * the public browse pages, the store tabs, the category and brand
14
+ * panels, and the admin/seller dashboards. The middle label is DERIVED
15
+ * from each listing type's `hideDefault`, so /auctions reads "Ended",
16
+ * /art reads "Sold", and /products reads "Sold & Ended".
17
+ *
18
+ * EXPORTS: AvailabilityTabs, AvailabilityTabsProps
19
+ *
20
+ * @tag domain:products
21
+ * @tag layer:ui
22
+ * @tag pattern:none
23
+ * @tag access:client
24
+ * @tag consumers:ProductsIndexListing,AuctionsIndexListing,PreOrdersIndexListing,PrizeDrawsIndexListing,Store*Listing,CategoryProductsListing,Seller*View,Admin*View
25
+ * @tag sideEffects:url-mutation
26
+ */
27
+ import { useMemo } from "react";
28
+ import { Tabs, TabsList, TabsTrigger } from "../../../ui";
29
+ import { useUrlTable } from "../../../react/hooks/useUrlTable";
30
+ import { TABLE_KEYS } from "../../../constants/table-keys";
31
+ import { AVAILABILITY_VALUES } from "../../../constants/field-names";
32
+ import { availabilityTabsFor } from "../../../_internal/shared/listing-types/_registry";
33
+ export function AvailabilityTabs({ types, className }) {
34
+ const table = useUrlTable();
35
+ const tabs = useMemo(() => availabilityTabsFor(types), [types]);
36
+ // An absent param is the Available scope — the same default every SSR
37
+ // filter-builder resolves through `defaultAvailabilityForListingTypes`.
38
+ // Reading a different default here is precisely how SSR and the first
39
+ // refetch end up permanently disagreeing (Root Cause #30).
40
+ const active = table.get(TABLE_KEYS.AVAILABILITY) || AVAILABILITY_VALUES.AVAILABLE;
41
+ return (_jsx(Tabs, { value: active,
42
+ // A single `set`, never followed by `setPage`. `useUrlTable.set` already
43
+ // resets the page for any key outside NON_RESETTING_KEYS, and a
44
+ // follow-up call would read stale searchParams and overwrite this one
45
+ // (Root Cause #13).
46
+ onChange: (next) => table.set(TABLE_KEYS.AVAILABILITY, next), className: className, children: _jsx(TabsList, { children: tabs.map((tab) => (_jsx(TabsTrigger, { value: tab.id, children: tab.label }, tab.id))) }) }));
47
+ }