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