@mohasinac/appkit 4.13.1 → 4.15.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 (493) 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 +8 -2
  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/cart/service.d.ts +3 -3
  17. package/dist/_internal/server/features/checkout/actions.js +25 -0
  18. package/dist/_internal/server/features/checkout/locked-lines.d.ts +38 -0
  19. package/dist/_internal/server/features/checkout/locked-lines.js +171 -0
  20. package/dist/_internal/server/features/checkout/source-context.d.ts +5 -0
  21. package/dist/_internal/server/features/checkout/source-context.js +157 -0
  22. package/dist/_internal/server/features/homepage/index.d.ts +0 -1
  23. package/dist/_internal/server/features/homepage/index.js +7 -1
  24. package/dist/_internal/server/features/lottery/adapters.js +4 -0
  25. package/dist/_internal/server/features/offers/adapters.d.ts +103 -0
  26. package/dist/_internal/server/features/offers/adapters.js +88 -0
  27. package/dist/_internal/server/features/offers/index.d.ts +2 -0
  28. package/dist/_internal/server/features/offers/index.js +1 -0
  29. package/dist/_internal/server/features/orders/adapters.js +24 -0
  30. package/dist/_internal/server/features/products/data.js +15 -37
  31. package/dist/_internal/server/features/products/index.d.ts +1 -1
  32. package/dist/_internal/server/features/products/index.js +1 -1
  33. package/dist/_internal/server/features/products/list-public.d.ts +46 -20
  34. package/dist/_internal/server/features/products/list-public.js +266 -90
  35. package/dist/_internal/server/features/products/listing-tab-counts.d.ts +44 -0
  36. package/dist/_internal/server/features/products/listing-tab-counts.js +97 -0
  37. package/dist/_internal/server/features/site-settings/adapters.d.ts +51 -0
  38. package/dist/_internal/server/features/site-settings/adapters.js +75 -0
  39. package/dist/_internal/server/features/site-settings/index.d.ts +1 -0
  40. package/dist/_internal/server/features/site-settings/index.js +1 -0
  41. package/dist/_internal/server/features/stores/adapters.d.ts +56 -0
  42. package/dist/_internal/server/features/stores/adapters.js +91 -0
  43. package/dist/_internal/server/features/stores/index.d.ts +1 -0
  44. package/dist/_internal/server/features/stores/index.js +1 -0
  45. package/dist/_internal/server/jobs/core/auctionSettlement.js +56 -2
  46. package/dist/_internal/server/jobs/core/offerExpiry.js +55 -19
  47. package/dist/_internal/server/jobs/core/paymentReviewAutoApprove.d.ts +5 -0
  48. package/dist/_internal/server/jobs/core/paymentReviewAutoApprove.js +33 -1
  49. package/dist/_internal/server/jobs/handlers/messages.d.ts +7 -0
  50. package/dist/_internal/server/jobs/handlers/messages.js +10 -0
  51. package/dist/_internal/shared/actions/action-registry.js +17 -1
  52. package/dist/_internal/shared/checkout/lanes.d.ts +25 -0
  53. package/dist/_internal/shared/checkout/lanes.js +26 -0
  54. package/dist/_internal/shared/features/auctions/config.d.ts +27 -0
  55. package/dist/_internal/shared/features/auctions/config.js +27 -0
  56. package/dist/_internal/shared/features/auctions/schema.d.ts +14 -2
  57. package/dist/_internal/shared/features/auctions/schema.js +13 -1
  58. package/dist/_internal/shared/features/blog/schema.d.ts +2 -2
  59. package/dist/_internal/shared/features/cart/schema.d.ts +20 -15
  60. package/dist/_internal/shared/features/cart/schema.js +15 -0
  61. package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +32 -32
  62. package/dist/_internal/shared/features/emi/schedule.d.ts +24 -3
  63. package/dist/_internal/shared/features/emi/schedule.js +20 -5
  64. package/dist/_internal/shared/features/events/schema.d.ts +2 -2
  65. package/dist/_internal/shared/features/homepage/section-gate.d.ts +14 -0
  66. package/dist/_internal/shared/features/homepage/section-gate.js +51 -0
  67. package/dist/_internal/shared/features/offers/config.d.ts +30 -0
  68. package/dist/_internal/shared/features/offers/config.js +59 -0
  69. package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
  70. package/dist/_internal/shared/features/products/schema.d.ts +30 -30
  71. package/dist/_internal/shared/features/products/to-product-item.js +6 -0
  72. package/dist/_internal/shared/features/reviews/schema.d.ts +2 -2
  73. package/dist/_internal/shared/features/site-settings/fees.d.ts +60 -0
  74. package/dist/_internal/shared/features/site-settings/fees.js +39 -0
  75. package/dist/_internal/shared/features/site-settings/types.d.ts +40 -0
  76. package/dist/_internal/shared/features/site-settings/types.js +1 -0
  77. package/dist/_internal/shared/history/history.d.ts +88 -0
  78. package/dist/_internal/shared/history/history.js +198 -0
  79. package/dist/_internal/shared/history/index.d.ts +4 -0
  80. package/dist/_internal/shared/history/index.js +2 -0
  81. package/dist/_internal/shared/history/types.d.ts +61 -0
  82. package/dist/_internal/shared/history/types.js +6 -0
  83. package/dist/_internal/shared/listing-types/_registry.d.ts +54 -1
  84. package/dist/_internal/shared/listing-types/_registry.js +67 -0
  85. package/dist/_internal/shared/listing-types/art/config.d.ts +3 -0
  86. package/dist/_internal/shared/listing-types/art/config.js +5 -0
  87. package/dist/_internal/shared/listing-types/auction/config.d.ts +13 -0
  88. package/dist/_internal/shared/listing-types/auction/config.js +21 -0
  89. package/dist/_internal/shared/listing-types/availability.d.ts +79 -0
  90. package/dist/_internal/shared/listing-types/availability.js +104 -0
  91. package/dist/_internal/shared/listing-types/capabilities.d.ts +15 -0
  92. package/dist/_internal/shared/listing-types/capabilities.js +12 -0
  93. package/dist/_internal/shared/listing-types/classified/config.d.ts +3 -0
  94. package/dist/_internal/shared/listing-types/classified/config.js +5 -0
  95. package/dist/_internal/shared/listing-types/digital-code/config.d.ts +11 -0
  96. package/dist/_internal/shared/listing-types/digital-code/config.js +22 -2
  97. package/dist/_internal/shared/listing-types/live/config.d.ts +3 -0
  98. package/dist/_internal/shared/listing-types/live/config.js +5 -0
  99. package/dist/_internal/shared/listing-types/pre-order/config.d.ts +3 -0
  100. package/dist/_internal/shared/listing-types/pre-order/config.js +19 -0
  101. package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +11 -0
  102. package/dist/_internal/shared/listing-types/prize-draw/config.js +15 -0
  103. package/dist/_internal/shared/listing-types/standard/config.d.ts +3 -0
  104. package/dist/_internal/shared/listing-types/standard/config.js +5 -0
  105. package/dist/_internal/shared/listing-types/stickers/config.d.ts +3 -0
  106. package/dist/_internal/shared/listing-types/stickers/config.js +5 -0
  107. package/dist/client.d.ts +20 -7
  108. package/dist/client.js +22 -4
  109. package/dist/constants/api-endpoints.d.ts +6 -0
  110. package/dist/constants/api-endpoints.js +2 -0
  111. package/dist/constants/field-names.d.ts +57 -8
  112. package/dist/constants/field-names.js +101 -8
  113. package/dist/constants/table-keys.d.ts +17 -0
  114. package/dist/constants/table-keys.js +17 -0
  115. package/dist/errors/error-codes.d.ts +13 -1
  116. package/dist/errors/error-codes.js +13 -1
  117. package/dist/errors/error-display-map.js +12 -3
  118. package/dist/errors/messages.d.ts +10 -2
  119. package/dist/errors/messages.js +10 -2
  120. package/dist/features/about/components/AboutView.d.ts +3 -0
  121. package/dist/features/about/components/AboutView.js +3 -2
  122. package/dist/features/about/components/PolicyPageView.d.ts +2 -1
  123. package/dist/features/about/components/PolicyPageView.js +61 -23
  124. package/dist/features/about/components/PublicProfileView.js +5 -0
  125. package/dist/features/about/schemas/firestore.d.ts +3 -0
  126. package/dist/features/account/components/UserBidsView.js +12 -4
  127. package/dist/features/account/components/UserOrdersView.js +7 -0
  128. package/dist/features/account/components/UserReturnsView.d.ts +3 -0
  129. package/dist/features/account/components/UserReturnsView.js +17 -1
  130. package/dist/features/account/components/index.d.ts +0 -2
  131. package/dist/features/account/components/index.js +0 -1
  132. package/dist/features/account/schemas/index.d.ts +2 -2
  133. package/dist/features/account/types/index.d.ts +21 -2
  134. package/dist/features/addresses/schemas/index.d.ts +4 -4
  135. package/dist/features/admin/components/AdminArtView.js +8 -3
  136. package/dist/features/admin/components/AdminAuditLogView.js +1 -0
  137. package/dist/features/admin/components/AdminBidsView.js +15 -2
  138. package/dist/features/admin/components/AdminBlogEditorView.js +65 -33
  139. package/dist/features/admin/components/AdminClassifiedView.js +8 -3
  140. package/dist/features/admin/components/AdminDigitalCodesView.js +8 -3
  141. package/dist/features/admin/components/AdminFeatureEditorView.js +35 -6
  142. package/dist/features/admin/components/AdminFeatureFlagsView.js +1 -0
  143. package/dist/features/admin/components/AdminLiveView.js +8 -3
  144. package/dist/features/admin/components/AdminNavEditorView.js +15 -5
  145. package/dist/features/admin/components/AdminNewsletterView.js +18 -2
  146. package/dist/features/admin/components/AdminOffersView.d.ts +4 -0
  147. package/dist/features/admin/components/AdminOffersView.js +230 -0
  148. package/dist/features/admin/components/AdminOrdersView.js +10 -1
  149. package/dist/features/admin/components/AdminPaymentMethodsView.js +24 -4
  150. package/dist/features/admin/components/AdminPrizeDrawsView.js +5 -0
  151. package/dist/features/admin/components/AdminProductsView.js +16 -29
  152. package/dist/features/admin/components/AdminScammerEditorView.d.ts +2 -1
  153. package/dist/features/admin/components/AdminScammerEditorView.js +3 -13
  154. package/dist/features/admin/components/AdminScammersView.js +3 -8
  155. package/dist/features/admin/components/AdminSectionsView.js +32 -23
  156. package/dist/features/admin/components/AdminSessionsView.js +17 -2
  157. package/dist/features/admin/components/AdminSiteSettingsView.js +31 -13
  158. package/dist/features/admin/components/AdminSiteView.js +6 -2
  159. package/dist/features/admin/components/AdminStickersView.js +8 -3
  160. package/dist/features/admin/components/ViewAuditLogEntryModal.js +1 -0
  161. package/dist/features/admin/components/index.d.ts +2 -0
  162. package/dist/features/admin/components/index.js +1 -0
  163. package/dist/features/admin/components/sections/adminSectionsTypes.d.ts +4 -2
  164. package/dist/features/admin/components/sections/adminSectionsTypes.js +45 -27
  165. package/dist/features/admin/constants/filter-tabs.d.ts +89 -0
  166. package/dist/features/admin/constants/filter-tabs.js +56 -0
  167. package/dist/features/admin/schemas/firestore.d.ts +122 -3
  168. package/dist/features/admin/schemas/firestore.js +1 -0
  169. package/dist/features/admin/schemas/homepage-section-form.d.ts +22 -0
  170. package/dist/features/admin/schemas/homepage-section-form.js +68 -0
  171. package/dist/features/admin/schemas/nav-item-form.d.ts +74 -0
  172. package/dist/features/admin/schemas/nav-item-form.js +72 -0
  173. package/dist/features/auctions/actions/bid-actions.d.ts +20 -5
  174. package/dist/features/auctions/actions/bid-actions.js +93 -20
  175. package/dist/features/auctions/components/AuctionBidsTable.d.ts +10 -1
  176. package/dist/features/auctions/components/AuctionBidsTable.js +22 -4
  177. package/dist/features/auctions/components/AuctionDetailPageView.js +11 -6
  178. package/dist/features/auctions/components/AuctionsListView.js +5 -6
  179. package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +7 -0
  180. package/dist/features/auctions/components/MarketplaceAuctionCard.js +19 -2
  181. package/dist/features/auctions/components/PlaceBidFormClient.d.ts +1 -2
  182. package/dist/features/auctions/components/PlaceBidFormClient.js +8 -4
  183. package/dist/features/auctions/components/bid-detail-fields.d.ts +29 -0
  184. package/dist/features/auctions/components/bid-detail-fields.js +103 -0
  185. package/dist/features/auctions/repository/bid.repository.d.ts +13 -0
  186. package/dist/features/auctions/repository/bid.repository.js +23 -0
  187. package/dist/features/auctions/schemas/firestore.d.ts +17 -0
  188. package/dist/features/auctions/schemas/index.d.ts +12 -12
  189. package/dist/features/audit-log/schemas/firestore.d.ts +14 -0
  190. package/dist/features/audit-log/schemas/firestore.js +7 -0
  191. package/dist/features/auth/permissions/constants.d.ts +1 -1
  192. package/dist/features/auth/permissions/constants.js +10 -1
  193. package/dist/features/blog/actions/blog-actions.d.ts +7 -7
  194. package/dist/features/blog/schemas/blog-form.d.ts +80 -0
  195. package/dist/features/blog/schemas/blog-form.js +100 -0
  196. package/dist/features/blog/schemas/index.d.ts +6 -6
  197. package/dist/features/cart/repository/cart.repository.js +1 -0
  198. package/dist/features/cart/schemas/firestore.d.ts +15 -0
  199. package/dist/features/catalogue/schemas/validation.d.ts +4 -4
  200. package/dist/features/categories/components/BrandDetailPageView.js +23 -40
  201. package/dist/features/categories/components/BrandDetailTabs.d.ts +7 -7
  202. package/dist/features/categories/components/BrandDetailTabs.js +8 -12
  203. package/dist/features/categories/components/BundleCollage.js +1 -1
  204. package/dist/features/categories/components/CategoryDetailPageView.js +53 -57
  205. package/dist/features/categories/components/CategoryDetailTabs.d.ts +10 -8
  206. package/dist/features/categories/components/CategoryDetailTabs.js +11 -16
  207. package/dist/features/categories/components/CategoryProductsListing.js +11 -1
  208. package/dist/features/categories/components/ConcernCard.js +7 -1
  209. package/dist/features/categories/schemas/firestore.d.ts +13 -0
  210. package/dist/features/categories/schemas/index.d.ts +26 -26
  211. package/dist/features/classified/components/ClassifiedDetailPageView.d.ts +16 -1
  212. package/dist/features/classified/components/ClassifiedDetailPageView.js +23 -3
  213. package/dist/features/events/components/AdminEventEditorView.js +32 -54
  214. package/dist/features/events/components/AdminEventEntriesView.js +22 -3
  215. package/dist/features/events/components/AdminEventsView.js +15 -11
  216. package/dist/features/events/components/EventFilters.d.ts +9 -1
  217. package/dist/features/events/components/EventFilters.js +45 -21
  218. package/dist/features/events/components/EventsIndexListing.d.ts +6 -1
  219. package/dist/features/events/components/EventsIndexListing.js +2 -2
  220. package/dist/features/events/components/EventsListPageView.js +13 -4
  221. package/dist/features/events/repository/events.repository.d.ts +17 -0
  222. package/dist/features/events/repository/events.repository.js +27 -0
  223. package/dist/features/events/schemas/event-form.d.ts +113 -0
  224. package/dist/features/events/schemas/event-form.js +82 -0
  225. package/dist/features/events/schemas/firestore.d.ts +12 -0
  226. package/dist/features/events/schemas/firestore.js +12 -0
  227. package/dist/features/events/schemas/index.d.ts +50 -50
  228. package/dist/features/events/types/index.d.ts +11 -0
  229. package/dist/features/events/types/index.js +57 -1
  230. package/dist/features/faq/actions/faq-actions.d.ts +12 -12
  231. package/dist/features/faq/schemas/index.d.ts +8 -8
  232. package/dist/features/filters/FilterFacetSection.d.ts +7 -1
  233. package/dist/features/filters/FilterFacetSection.js +11 -3
  234. package/dist/features/grouped/schemas/grouped-listing-form.d.ts +101 -0
  235. package/dist/features/grouped/schemas/grouped-listing-form.js +89 -0
  236. package/dist/features/grouped/schemas/index.d.ts +4 -4
  237. package/dist/features/homepage/actions/homepage-section-actions.d.ts +11 -3
  238. package/dist/features/homepage/actions/homepage-section-actions.js +33 -1
  239. package/dist/features/homepage/components/AnnouncementBar.d.ts +7 -1
  240. package/dist/features/homepage/components/AnnouncementBar.js +3 -3
  241. package/dist/features/homepage/components/MarketplaceHomepageView.js +20 -6
  242. package/dist/features/homepage/hooks/homepage-query.d.ts +16 -0
  243. package/dist/features/homepage/hooks/homepage-query.js +45 -0
  244. package/dist/features/homepage/hooks/useFeaturedAuctions.d.ts +10 -0
  245. package/dist/features/homepage/hooks/useFeaturedAuctions.js +28 -8
  246. package/dist/features/homepage/hooks/useFeaturedPreOrders.js +17 -8
  247. package/dist/features/homepage/hooks/useFeaturedProducts.js +15 -8
  248. package/dist/features/homepage/schemas/index.d.ts +33 -2
  249. package/dist/features/homepage/schemas/index.js +24 -0
  250. package/dist/features/layout/AppLayoutShell.d.ts +11 -1
  251. package/dist/features/layout/AppLayoutShell.js +15 -14
  252. package/dist/features/layout/BackToTop.d.ts +9 -0
  253. package/dist/features/layout/BackToTop.js +10 -1
  254. package/dist/features/layout/BottomActions.js +28 -25
  255. package/dist/features/layout/BottomChrome.d.ts +34 -0
  256. package/dist/features/layout/BottomChrome.js +55 -0
  257. package/dist/features/layout/BottomNavLayout.d.ts +6 -0
  258. package/dist/features/layout/BottomNavLayout.js +7 -1
  259. package/dist/features/layout/BottomNavbar.js +15 -2
  260. package/dist/features/layout/FooterLayout.js +11 -1
  261. package/dist/features/layout/NavbarLayout.js +1 -1
  262. package/dist/features/layout/TitleBarLayout.d.ts +7 -0
  263. package/dist/features/layout/TitleBarLayout.js +28 -5
  264. package/dist/features/layout/index.d.ts +2 -0
  265. package/dist/features/layout/index.js +1 -0
  266. package/dist/features/lottery/types/index.d.ts +3 -0
  267. package/dist/features/media/MediaPickerModal.js +5 -1
  268. package/dist/features/messages/schemas/index.d.ts +2 -2
  269. package/dist/features/orders/components/OrderScopeTabs.d.ts +20 -0
  270. package/dist/features/orders/components/OrderScopeTabs.js +31 -0
  271. package/dist/features/orders/components/OrderStatusTimeline.d.ts +5 -1
  272. package/dist/features/orders/components/OrderStatusTimeline.js +39 -20
  273. package/dist/features/orders/constants/order-scope.d.ts +48 -0
  274. package/dist/features/orders/constants/order-scope.js +111 -0
  275. package/dist/features/orders/repository/orders.repository.d.ts +54 -7
  276. package/dist/features/orders/repository/orders.repository.js +121 -22
  277. package/dist/features/orders/schemas/firestore.d.ts +152 -0
  278. package/dist/features/orders/schemas/firestore.js +30 -0
  279. package/dist/features/orders/schemas/index.d.ts +18 -18
  280. package/dist/features/orders/types/index.d.ts +35 -7
  281. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +14 -9
  282. package/dist/features/pre-orders/components/PreOrdersListView.js +6 -5
  283. package/dist/features/pre-orders/schemas/index.d.ts +1 -1
  284. package/dist/features/products/actions/product-actions.d.ts +14 -0
  285. package/dist/features/products/actions/product-actions.js +49 -11
  286. package/dist/features/products/api/route.d.ts +12 -0
  287. package/dist/features/products/api/route.js +42 -100
  288. package/dist/features/products/components/ArtStickersListView.js +2 -2
  289. package/dist/features/products/components/AuctionsIndexListing.js +13 -11
  290. package/dist/features/products/components/AvailabilityTabs.d.ts +11 -0
  291. package/dist/features/products/components/AvailabilityTabs.js +47 -0
  292. package/dist/features/products/components/GroupSettingsPanel.js +5 -1
  293. package/dist/features/products/components/MakeOfferButton.js +48 -49
  294. package/dist/features/products/components/PrizeDrawCollage.d.ts +20 -4
  295. package/dist/features/products/components/PrizeDrawCollage.js +9 -1
  296. package/dist/features/products/components/PrizeDrawsIndexListing.js +14 -12
  297. package/dist/features/products/components/PrizeDrawsListingView.js +2 -2
  298. package/dist/features/products/components/PrizeDrawsSection.d.ts +7 -1
  299. package/dist/features/products/components/PrizeDrawsSection.js +23 -18
  300. package/dist/features/products/components/ProductDetailPageView.d.ts +4 -1
  301. package/dist/features/products/components/ProductDetailPageView.js +18 -4
  302. package/dist/features/products/components/ProductForm.js +5 -2
  303. package/dist/features/products/components/ProductGrid.js +6 -1
  304. package/dist/features/products/components/ProductsIndexListing.js +22 -32
  305. package/dist/features/products/components/ProductsIndexPageView.js +6 -9
  306. package/dist/features/products/components/index.d.ts +2 -2
  307. package/dist/features/products/components/index.js +1 -1
  308. package/dist/features/products/config/listing-type-listing-config.d.ts +20 -0
  309. package/dist/features/products/config/listing-type-listing-config.js +22 -10
  310. package/dist/features/products/constants/action-defs.d.ts +2 -0
  311. package/dist/features/products/constants/action-defs.js +6 -0
  312. package/dist/features/products/hooks/useAvailabilityScope.d.ts +13 -0
  313. package/dist/features/products/hooks/useAvailabilityScope.js +19 -0
  314. package/dist/features/products/hooks/useProducts.d.ts +5 -0
  315. package/dist/features/products/hooks/useProducts.js +13 -2
  316. package/dist/features/products/repository/products.repository.d.ts +31 -2
  317. package/dist/features/products/repository/products.repository.js +53 -21
  318. package/dist/features/products/schemas/firestore.d.ts +17 -3
  319. package/dist/features/products/schemas/firestore.js +7 -2
  320. package/dist/features/products/schemas/index.d.ts +64 -64
  321. package/dist/features/products/schemas/product-features.validators.d.ts +79 -6
  322. package/dist/features/products/schemas/product-features.validators.js +63 -0
  323. package/dist/features/products/types/index.d.ts +16 -1
  324. package/dist/features/promotions/schemas/index.d.ts +2 -2
  325. package/dist/features/reviews/schemas/index.d.ts +16 -16
  326. package/dist/features/scams/constants/scammer-status-display.d.ts +28 -0
  327. package/dist/features/scams/constants/scammer-status-display.js +79 -0
  328. package/dist/features/search/schemas/index.d.ts +4 -4
  329. package/dist/features/seller/actions/offer-actions.js +57 -4
  330. package/dist/features/seller/components/OfferPhaseTimeline.d.ts +59 -0
  331. package/dist/features/seller/components/OfferPhaseTimeline.js +107 -0
  332. package/dist/features/seller/components/SellerArtView.js +5 -0
  333. package/dist/features/seller/components/SellerAuctionsView.js +13 -15
  334. package/dist/features/seller/components/SellerBidsView.js +11 -4
  335. package/dist/features/seller/components/SellerClassifiedView.js +5 -0
  336. package/dist/features/seller/components/SellerCouponEditorView.js +17 -17
  337. package/dist/features/seller/components/SellerDigitalCodesView.js +5 -0
  338. package/dist/features/seller/components/SellerLiveView.js +5 -0
  339. package/dist/features/seller/components/SellerOffersView.js +2 -1
  340. package/dist/features/seller/components/SellerOrdersView.js +31 -9
  341. package/dist/features/seller/components/SellerPayoutSettingsView.js +56 -31
  342. package/dist/features/seller/components/SellerPreOrdersView.js +5 -0
  343. package/dist/features/seller/components/SellerPrizeDrawsView.js +14 -16
  344. package/dist/features/seller/components/SellerProductShell.js +7 -1
  345. package/dist/features/seller/components/SellerProductsView.js +11 -8
  346. package/dist/features/seller/components/SellerStickersView.js +5 -0
  347. package/dist/features/seller/components/index.d.ts +0 -2
  348. package/dist/features/seller/components/index.js +0 -1
  349. package/dist/features/seller/repository/offer.repository.d.ts +142 -24
  350. package/dist/features/seller/repository/offer.repository.js +165 -26
  351. package/dist/features/seller/schemas/coupon-form.d.ts +72 -0
  352. package/dist/features/seller/schemas/coupon-form.js +116 -0
  353. package/dist/features/seller/schemas/firestore.d.ts +56 -2
  354. package/dist/features/seller/schemas/firestore.js +27 -0
  355. package/dist/features/seller/schemas/index.d.ts +2 -2
  356. package/dist/features/seller/schemas/offer-forms.d.ts +46 -0
  357. package/dist/features/seller/schemas/offer-forms.js +42 -0
  358. package/dist/features/seller/server.d.ts +0 -1
  359. package/dist/features/seller/server.js +0 -1
  360. package/dist/features/shell/SectionForm.d.ts +99 -0
  361. package/dist/features/shell/SectionForm.js +128 -0
  362. package/dist/features/shell/build-sections.d.ts +63 -0
  363. package/dist/features/shell/build-sections.js +207 -0
  364. package/dist/features/shell/entity-form.d.ts +109 -0
  365. package/dist/features/shell/entity-form.js +96 -0
  366. package/dist/features/shell/field-ui-meta.d.ts +115 -0
  367. package/dist/features/shell/field-ui-meta.js +324 -0
  368. package/dist/features/shell/index.d.ts +8 -0
  369. package/dist/features/shell/index.js +4 -0
  370. package/dist/features/status-history/components/StatusTimeline.d.ts +74 -0
  371. package/dist/features/status-history/components/StatusTimeline.js +46 -0
  372. package/dist/features/status-history/index.d.ts +11 -0
  373. package/dist/features/status-history/index.js +10 -0
  374. package/dist/features/store-extensions/components/ReviewDecisionModal.d.ts +27 -0
  375. package/dist/features/store-extensions/components/ReviewDecisionModal.js +82 -0
  376. package/dist/features/store-extensions/index.d.ts +12 -0
  377. package/dist/features/store-extensions/index.js +12 -0
  378. package/dist/features/store-extensions/schemas/admin-notification-form.d.ts +36 -0
  379. package/dist/features/store-extensions/schemas/admin-notification-form.js +114 -0
  380. package/dist/features/store-extensions/schemas/analytics-forms.d.ts +57 -0
  381. package/dist/features/store-extensions/schemas/analytics-forms.js +158 -0
  382. package/dist/features/store-extensions/schemas/custom-role-form.d.ts +85 -0
  383. package/dist/features/store-extensions/schemas/custom-role-form.js +118 -0
  384. package/dist/features/store-extensions/schemas/firestore.d.ts +21 -1
  385. package/dist/features/store-extensions/schemas/firestore.js +60 -0
  386. package/dist/features/store-extensions/schemas/google-config-form.d.ts +53 -0
  387. package/dist/features/store-extensions/schemas/google-config-form.js +105 -0
  388. package/dist/features/store-extensions/schemas/item-request-create-form.d.ts +28 -0
  389. package/dist/features/store-extensions/schemas/item-request-create-form.js +80 -0
  390. package/dist/features/store-extensions/schemas/listing-template-form.d.ts +78 -0
  391. package/dist/features/store-extensions/schemas/listing-template-form.js +87 -0
  392. package/dist/features/store-extensions/schemas/moderation-review-form.d.ts +49 -0
  393. package/dist/features/store-extensions/schemas/moderation-review-form.js +101 -0
  394. package/dist/features/store-extensions/schemas/payout-method-form.d.ts +153 -0
  395. package/dist/features/store-extensions/schemas/payout-method-form.js +155 -0
  396. package/dist/features/store-extensions/schemas/report-create-form.d.ts +25 -0
  397. package/dist/features/store-extensions/schemas/report-create-form.js +79 -0
  398. package/dist/features/store-extensions/schemas/report-review-form.d.ts +47 -0
  399. package/dist/features/store-extensions/schemas/report-review-form.js +111 -0
  400. package/dist/features/store-extensions/schemas/shipping-config-form.d.ts +148 -0
  401. package/dist/features/store-extensions/schemas/shipping-config-form.js +104 -0
  402. package/dist/features/store-extensions/schemas/store-category-form.d.ts +54 -0
  403. package/dist/features/store-extensions/schemas/store-category-form.js +73 -0
  404. package/dist/features/stores/api/[storeSlug]/route.js +2 -25
  405. package/dist/features/stores/components/StoreAuctionsListing.js +15 -1
  406. package/dist/features/stores/components/StoreClassifiedsListing.js +12 -2
  407. package/dist/features/stores/components/StoreDetailLayoutView.js +24 -71
  408. package/dist/features/stores/components/StoreDigitalCodesListing.js +12 -2
  409. package/dist/features/stores/components/StoreLiveItemsListing.js +12 -2
  410. package/dist/features/stores/components/StorePreOrdersListing.js +12 -1
  411. package/dist/features/stores/components/StoreProductsListing.js +11 -1
  412. package/dist/features/stores/repository/store.repository.js +6 -0
  413. package/dist/features/stores/schemas/index.d.ts +6 -6
  414. package/dist/features/support/schemas/index.d.ts +4 -4
  415. package/dist/features/tester/actions/checklist-item-actions.d.ts +4 -4
  416. package/dist/features/tester/seed-data/offers-tester-seed-data.js +119 -3
  417. package/dist/features/tester/seed-data/products-tester-seed-data.js +131 -1
  418. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +431 -1
  419. package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
  420. package/dist/index.d.ts +25 -12
  421. package/dist/index.js +26 -11
  422. package/dist/next/routing/route-map.d.ts +23 -3
  423. package/dist/next/routing/route-map.js +14 -2
  424. package/dist/providers/db-firebase/base.repository.d.ts +30 -0
  425. package/dist/providers/db-firebase/base.repository.js +50 -1
  426. package/dist/providers/db-firebase/index.d.ts +1 -1
  427. package/dist/providers/db-firebase/index.js +1 -1
  428. package/dist/providers/db-firebase/sieve.d.ts +25 -0
  429. package/dist/providers/db-firebase/sieve.js +52 -18
  430. package/dist/react/hooks/useUrlTable.js +10 -1
  431. package/dist/schemas/firestore-value.d.ts +8 -0
  432. package/dist/schemas/firestore-value.js +44 -0
  433. package/dist/schemas/index.d.ts +1 -1
  434. package/dist/schemas/index.js +1 -1
  435. package/dist/schemas/registry.d.ts +702 -69
  436. package/dist/schemas/registry.js +64 -1
  437. package/dist/seed/_helpers/category-forest.d.ts +2 -0
  438. package/dist/seed/_helpers/category-forest.js +309 -0
  439. package/dist/seed/_helpers/category-tree.d.ts +27 -0
  440. package/dist/seed/_helpers/category-tree.js +103 -0
  441. package/dist/seed/bids-seed-data.js +30 -0
  442. package/dist/seed/catalogue-seed-data.js +12 -12
  443. package/dist/seed/categories-seed-data.js +177 -162
  444. package/dist/seed/events-seed-data.js +61 -10
  445. package/dist/seed/homepage-sections-seed-data.js +5 -1
  446. package/dist/seed/offers-seed-data.js +244 -34
  447. package/dist/seed/orders-seed-data.js +336 -1
  448. package/dist/seed/products-art-seed-data.js +50 -12
  449. package/dist/seed/products-auctions-seed-data.js +138 -18
  450. package/dist/seed/products-classifieds-seed-data.js +80 -16
  451. package/dist/seed/products-digital-codes-seed-data.js +66 -18
  452. package/dist/seed/products-live-items-seed-data.js +64 -13
  453. package/dist/seed/products-preorders-seed-data.d.ts +0 -1
  454. package/dist/seed/products-preorders-seed-data.js +52 -13
  455. package/dist/seed/products-prize-draws-seed-data.js +63 -14
  456. package/dist/seed/products-standard-seed-data.js +99 -26
  457. package/dist/seed/products-stickers-seed-data.js +47 -12
  458. package/dist/seed/reviews-seed-data.js +6 -1
  459. package/dist/seed/site-settings-seed-data.d.ts +1 -38
  460. package/dist/seed/site-settings-seed-data.js +38 -76
  461. package/dist/seed/stores-seed-data.js +71 -1
  462. package/dist/seed/users-seed-data.js +15 -5
  463. package/dist/server-entry.d.ts +1 -2
  464. package/dist/server-entry.js +4 -3
  465. package/dist/server.d.ts +6 -3
  466. package/dist/server.js +13 -4
  467. package/dist/styles.css +78 -12
  468. package/dist/tailwind-utilities.css +1 -1
  469. package/dist/ui/components/Button.style.css +19 -4
  470. package/dist/ui/components/CollapsibleSection.d.ts +17 -1
  471. package/dist/ui/components/CollapsibleSection.js +6 -2
  472. package/dist/ui/components/FilterChipGroup.d.ts +25 -1
  473. package/dist/ui/components/FilterChipGroup.js +21 -4
  474. package/dist/ui/components/HandMode.style.css +47 -0
  475. package/dist/ui/components/Layout.d.ts +9 -2
  476. package/dist/ui/components/Layout.js +1 -1
  477. package/dist/ui/components/ListingLayout.js +8 -8
  478. package/dist/ui/components/ListingLayout.style.css +8 -7
  479. package/dist/ui/components/RecordDetailModal.d.ts +10 -1
  480. package/dist/ui/components/RecordDetailModal.js +2 -2
  481. package/dist/ui/components/StickyToolbar.d.ts +3 -1
  482. package/dist/ui/components/StickyToolbar.js +62 -20
  483. package/dist/ui/components/bottom-chrome-slot.d.ts +21 -0
  484. package/dist/ui/components/bottom-chrome-slot.js +29 -0
  485. package/dist/ui/components/index.style.css +3 -0
  486. package/dist/ui/forms/FormShell.d.ts +43 -13
  487. package/dist/ui/forms/FormShell.js +22 -11
  488. package/dist/ui/forms/index.d.ts +1 -1
  489. package/dist/ui/index.d.ts +1 -1
  490. package/package.json +2 -1
  491. package/scripts/node-esm-loader.mjs +65 -0
  492. package/scripts/seed-cli-loader.mjs +6 -49
  493. package/scripts/seed-cli.mjs +1 -1
@@ -7,14 +7,16 @@ export interface CategoryDetailTabsProps {
7
7
  initialProductsData?: any;
8
8
  initialBundles?: CategoryDocument[];
9
9
  initialStores?: StoreListItem[];
10
- counts?: {
11
- products?: number;
12
- auctions?: number;
13
- preOrders?: number;
14
- prizeDraws?: number;
15
- bundles?: number;
16
- stores?: number;
17
- };
10
+ /**
11
+ * tabSlug -> row count. `undefined` means the count could not be resolved,
12
+ * NOT zero — such a tab stays visible so a failed query can never hide real
13
+ * inventory (Root Cause #59).
14
+ *
15
+ * Keyed by tab id rather than by hand-named properties: the previous shape
16
+ * named only 6 of the 10 tabs, so classifieds / digital-codes / live / art
17
+ * were structurally uncountable and could never hide (Root Cause #61).
18
+ */
19
+ counts?: Record<string, number | undefined>;
18
20
  /** Enabled listing types (e.g. ["standard","auction","pre-order"]). When omitted, all tabs shown. */
19
21
  enabledListingTypes?: string[];
20
22
  /** Enabled category types (e.g. ["category","brand","bundle"]). When omitted, all tabs shown. */
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState } from "react";
4
- import { Tabs, TabsList, TabsTrigger } from "../../../ui";
4
+ import { EmptyState, Tabs, TabsList, TabsTrigger } from "../../../ui";
5
5
  import { CategoryProductsListing } from "./CategoryProductsListing";
6
6
  import { AuctionsIndexListing } from "../../products/components/AuctionsIndexListing";
7
7
  import { PreOrdersIndexListing } from "../../pre-orders/components/PreOrdersIndexListing";
@@ -39,17 +39,7 @@ const GENERIC_TAB_LISTING_TYPES = {
39
39
  [pluginFor("art").tabSlug]: ART_STICKERS_LISTING_TYPES,
40
40
  };
41
41
  export function CategoryDetailTabs({ categorySlug, categoryId, initialProductsData, initialBundles = [], initialStores = [], counts, enabledListingTypes, enabledCategoryTypes, }) {
42
- const countFor = (id) => {
43
- switch (id) {
44
- case "products": return counts?.products;
45
- case "auctions": return counts?.auctions;
46
- case "pre-orders": return counts?.preOrders;
47
- case "prize-draws": return counts?.prizeDraws;
48
- case "bundles": return counts?.bundles;
49
- case "stores": return counts?.stores;
50
- default: return undefined;
51
- }
52
- };
42
+ const countFor = (id) => counts?.[id];
53
43
  const visibleTabs = CATEGORY_PAGE_TABS.filter((t) => {
54
44
  const mapping = TAB_TYPE_MAP[t.id];
55
45
  if (mapping) {
@@ -62,14 +52,19 @@ export function CategoryDetailTabs({ categorySlug, categoryId, initialProductsDa
62
52
  return false;
63
53
  }
64
54
  }
65
- // Hide a tab only when its count is known and explicitly zero — a tab
66
- // whose count was never fetched (undefined) stays visible so we don't
67
- // silently hide a listing type this page hasn't wired count-tracking
68
- // for yet.
55
+ // Hide a tab only when its count is known and explicitly zero. `undefined`
56
+ // now means the count query FAILED (every tab is counted), so keeping it
57
+ // visible is the fail-open choice: an empty tab is a far smaller error than
58
+ // hiding a tab that holds real listings.
69
59
  const count = countFor(t.id);
70
60
  return count === undefined || count > 0;
71
61
  });
72
62
  const firstTabId = (visibleTabs[0]?.id ?? "products");
73
63
  const [activeTab, setActiveTab] = useState(firstTabId);
64
+ // Every tab counted zero — render the empty state rather than an empty tab
65
+ // strip with no body beneath it.
66
+ if (visibleTabs.length === 0) {
67
+ return (_jsx(EmptyState, { title: "Nothing listed here yet", description: "This category has no active listings right now. Check back soon." }));
68
+ }
74
69
  return (_jsxs(_Fragment, { children: [_jsx(Tabs, { value: activeTab, onChange: (v) => setActiveTab(v), className: "mb-6", children: _jsx(TabsList, { children: visibleTabs.map((t) => (_jsx(TabsTrigger, { value: t.id, badge: countFor(t.id), children: t.label }, t.id))) }) }), GENERIC_TAB_LISTING_TYPES[activeTab] && (_jsx(CategoryProductsListing, { categorySlug: categorySlug, categoryId: categoryId, listingTypes: GENERIC_TAB_LISTING_TYPES[activeTab], initialData: activeTab === pluginFor("standard").tabSlug ? initialProductsData : undefined })), activeTab === pluginFor("auction").tabSlug && (_jsx(AuctionsIndexListing, { categorySlug: categorySlug })), activeTab === pluginFor("pre-order").tabSlug && (_jsx(PreOrdersIndexListing, { categorySlug: categorySlug })), activeTab === pluginFor("prize-draw").tabSlug && (_jsx(PrizeDrawsIndexListing, { categorySlug: categorySlug })), activeTab === "bundles" && (_jsx(CategoryBundlesListing, { initialBundles: initialBundles })), activeTab === "stores" && (_jsx(CategoryStoresListing, { stores: initialStores }))] }));
75
70
  }
@@ -13,6 +13,9 @@ import { ProductFilters, PRODUCT_PUBLIC_SORT_OPTIONS } from "../../products/comp
13
13
  import { useGuestCart } from "../../cart/hooks/useGuestCart";
14
14
  import { useGuestWishlist } from "../../wishlist/hooks/useGuestWishlist";
15
15
  import { pushCartOp, pushWishlistOp } from "../../cart/utils/pending-ops";
16
+ import { AvailabilityTabs } from "../../products/components/AvailabilityTabs";
17
+ import { AVAILABILITY_VALUES } from "../../../constants/field-names";
18
+ import { TABLE_KEYS } from "../../../constants/table-keys";
16
19
  const __P = {
17
20
  p3: "p-[var(--appkit-space-3)]",
18
21
  };
@@ -38,6 +41,12 @@ export function CategoryProductsListing({ categorySlug, categoryId, brandName, l
38
41
  const localWishlist = useGuestWishlist();
39
42
  const wishlistedIds = new Set(localWishlist.items.filter((i) => i.type === "product").map((i) => i.itemId));
40
43
  const { pendingTable, filterActiveCount, onFilterApply, onFilterClear, onResetAll, onFilterReset } = usePendingTable(table, FILTER_KEYS);
44
+ // Absent means "available" — the same default `listStoreProducts`
45
+ // resolves server-side. These six store tabs sent NO availability
46
+ // param at all until 2026-08-24, while their SSR fetch did apply one,
47
+ // so any client refetch silently widened the list (Root Cause #30).
48
+ const availability = table.get(TABLE_KEYS.AVAILABILITY) ||
49
+ AVAILABILITY_VALUES.AVAILABLE;
41
50
  const params = {
42
51
  q: table.get("q") || undefined,
43
52
  category: categoryId || undefined,
@@ -52,6 +61,7 @@ export function CategoryProductsListing({ categorySlug, categoryId, brandName, l
52
61
  // sievejs parses it as a same-field OR and the Firebase adapter upgrades
53
62
  // it to a `.where(…, "in", …)` query.
54
63
  listingType: listingTypes.join("|"),
64
+ availability,
55
65
  };
56
66
  const { products, totalPages, page, isLoading } = useProducts(params, { initialData });
57
67
  const commitSearch = useCallback(() => {
@@ -106,7 +116,7 @@ export function CategoryProductsListing({ categorySlug, categoryId, brandName, l
106
116
  }, [localCart, showToast]);
107
117
  return (_jsxs(Div, { className: "min-h-[200px]", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: `Search in ${categorySlug.replace(/-/g, " ")}...`, onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || "-createdAt", sortOptions: PRODUCT_PUBLIC_SORT_OPTIONS, onSortChange: (v) => {
108
118
  table.set("sort", v);
109
- }, view: view === "card" ? "grid" : "list", onViewChange: (v) => handleViewToggle(v === "grid" ? "card" : "list"), onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), _jsx(Div, { padding: "y-lg", children: renderCategoryProductGrid({
119
+ }, view: view === "card" ? "grid" : "list", onViewChange: (v) => handleViewToggle(v === "grid" ? "card" : "list"), onResetAll: resetAll, hasActiveState: hasActiveState }), _jsx(Div, { padding: "y-sm", children: _jsx(AvailabilityTabs, { types: listingTypes }) }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), _jsx(Div, { padding: "y-lg", children: renderCategoryProductGrid({
110
120
  isLoading, products: products, view,
111
121
  getProductHref: (p) => String(ROUTES.PUBLIC.PRODUCT_DETAIL(p.slug || p.id)),
112
122
  onWishlistToggle: handleWishlistToggle, wishlistedIds, onAddToCart: handleAddToCart,
@@ -2,5 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Button, Div, Heading, Text } from "../../../ui";
3
3
  import { MediaImage } from "../../media/MediaImage";
4
4
  export function ConcernCard({ concern, onClick, className = "", }) {
5
- return (_jsxs(Button, { type: "button", variant: "outline", onClick: () => onClick?.(concern), className: `group flex flex-col items-center gap-[var(--appkit-space-3)] rounded-xl border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] p-[var(--appkit-space-4)] text-left shadow-sm transition hover:border-primary dark:hover:border-primary-400 hover:shadow-md ${className}`, children: [concern.display?.coverImage && (_jsx(Div, { className: "relative h-16 w-16", rounded: "full", overflow: "hidden", children: _jsx(MediaImage, { src: concern.display.coverImage, alt: concern.name, size: "thumbnail" }) })), _jsxs(Div, { children: [_jsx(Heading, { level: 3, className: "text-[var(--appkit-color-text)] group-hover:text-primary dark:group-hover:text-primary-400", size: "sm", weight: "semibold", children: concern.name }), concern.description && (_jsx(Text, { className: `mt-1`, color: "muted", truncate: 2, size: "xs", children: concern.description }))] })] }));
5
+ return (_jsxs(Button, { type: "button", variant: "outline", onClick: () => onClick?.(concern),
6
+ // No bare `flex` here: globals.css declares `.flex` un-layered + !important,
7
+ // which overrides `.appkit-button`'s own display. It is redundant anyway —
8
+ // the button is already a flex container. `flex-col items-center` now
9
+ // actually reaches the icon and label, which have been rendering
10
+ // side-by-side since the ripple wrapper landed (Root Cause #68).
11
+ className: `group flex-col items-center gap-[var(--appkit-space-3)] rounded-xl border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] p-[var(--appkit-space-4)] text-left shadow-sm transition hover:border-primary dark:hover:border-primary-400 hover:shadow-md ${className}`, children: [concern.display?.coverImage && (_jsx(Div, { className: "relative h-16 w-16", rounded: "full", overflow: "hidden", children: _jsx(MediaImage, { src: concern.display.coverImage, alt: concern.name, size: "thumbnail" }) })), _jsxs(Div, { children: [_jsx(Heading, { level: 3, className: "text-[var(--appkit-color-text)] group-hover:text-primary dark:group-hover:text-primary-400", size: "sm", weight: "semibold", children: concern.name }), concern.description && (_jsx(Text, { className: `mt-1`, color: "muted", truncate: 2, size: "xs", children: concern.description }))] })] }));
6
12
  }
@@ -162,6 +162,19 @@ export interface CategoryDocument extends BaseDocument {
162
162
  bundleQueryResolvedAt?: Date;
163
163
  /** Hand-picked products list (mirror of bundleQueryRule for static rules); kept for index-friendly queries. */
164
164
  bundleProductIds?: string[];
165
+ /**
166
+ * Categories this bundle belongs to — the union of its member products'
167
+ * `categorySlugs`. A bundle row has no category of its own, so without this
168
+ * the category page could not scope its Bundles tab at all and counted every
169
+ * active bundle site-wide.
170
+ *
171
+ * Denormalised at bundle create/update time and refreshed by the daily bundle
172
+ * stock sync. Per Root Cause #42 a mirror is never trusted alone: readers
173
+ * treat an ABSENT mirror as "unscoped" (show it) rather than "belongs to no
174
+ * category" (hide it), so a write path that forgets to set it degrades to
175
+ * over-inclusion instead of silently losing the bundle.
176
+ */
177
+ bundleCategorySlugs?: string[];
165
178
  /**
166
179
  * Sum of member products' individual prices (decimal rupees) — the "buy
167
180
  * separately" total the discount badge is measured against. Denormalised
@@ -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
  }
@@ -2,14 +2,14 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { normalizeError } from "../../../errors/normalize";
4
4
  import { useApiMutation } from "@mohasinac/appkit/client";
5
- import React, { useEffect, useMemo } from "react";
6
- import { z } from "zod";
5
+ import React, { useEffect } from "react";
7
6
  import { useQuery } from "@tanstack/react-query";
8
7
  import { Alert, Button, Div, Grid, Heading, Input, Label, RichTextEditor, Row, Select, Stack, StackedViewShell, TagInput, Text, Textarea, Toggle, } from "../../../ui";
9
8
  import { FormShellContext, useFormShellState, applyZodIssues, FormErrorSummary } from "../../../ui/forms";
10
9
  import { apiClient } from "../../../http";
11
10
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
12
- import { StepForm } from "../../shell";
11
+ import { SectionForm, useSectionFormNav } from "../../shell";
12
+ import { eventDraftSchema } from "../schemas/event-form";
13
13
  import { ProductInlineSelect } from "../../seller/components/ProductInlineSelect";
14
14
  import { CouponInlineSelect } from "../../seller/components/CouponInlineSelect";
15
15
  // Covers the cross-type required fields plus the two conditional rules the
@@ -19,27 +19,6 @@ import { CouponInlineSelect } from "../../seller/components/CouponInlineSelect";
19
19
  // form-builder arrays, raffle/spin config) are deliberately left unvalidated
20
20
  // — modeling their full conditional shape correctly would need much deeper
21
21
  // per-type domain rules than this pass is scoped for.
22
- const eventDraftSchema = z.object({
23
- type: z.string(),
24
- title: z.string().min(1, "Title is required"),
25
- startsAt: z.string().min(1, "Start date is required"),
26
- endsAt: z.string().min(1, "End date is required"),
27
- couponId: z.string(),
28
- displayCode: z.string(),
29
- pollOptions: z.array(z.object({ id: z.string(), label: z.string() })),
30
- }).passthrough().superRefine((v, ctx) => {
31
- if (v.type === "offer") {
32
- if (!v.couponId.trim()) {
33
- ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["couponId"], message: "Coupon is required for offer events" });
34
- }
35
- if (!v.displayCode.trim()) {
36
- ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["displayCode"], message: "Display code is required for offer events" });
37
- }
38
- }
39
- if (v.type === "poll" && v.pollOptions.filter((o) => o.label.trim()).length < 2) {
40
- ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["pollOptions"], message: "Poll events require at least 2 options" });
41
- }
42
- });
43
22
  const __P = {
44
23
  p4: "p-[var(--appkit-space-4)]",
45
24
  };
@@ -226,7 +205,6 @@ export function AdminEventEditorView({ eventId, onSaved, embedded, allowedTypes,
226
205
  const isEdit = Boolean(eventId);
227
206
  const [draft, setDraft] = React.useState(DEFAULT_DRAFT);
228
207
  const [slugManual, setSlugManual] = React.useState(false);
229
- const [currentStep, setCurrentStep] = React.useState(0);
230
208
  const [saveMessage, setSaveMessage] = React.useState(null);
231
209
  const [triggerMessage, setTriggerMessage] = React.useState(null);
232
210
  const [raffleWinnerName, setRaffleWinnerName] = React.useState("");
@@ -358,44 +336,49 @@ export function AdminEventEditorView({ eventId, onSaved, embedded, allowedTypes,
358
336
  });
359
337
  const isLoading = saveMutation.isPending || eventQuery.isLoading;
360
338
  // --- steps ---
361
- const steps = [
339
+ /**
340
+ * Sections, not steps — every field reachable at once, one submit at the
341
+ * bottom. The old wizard gated Settings behind Details validating, so a
342
+ * missing end date made an event's poll options unreachable.
343
+ *
344
+ * Ids match the schema's `section` annotations exactly, which is what lets
345
+ * `<FormErrorSummary>` jump to the right panel.
346
+ */
347
+ const sections = [
362
348
  {
349
+ id: "details",
350
+ required: true,
351
+ quick: true,
363
352
  label: "Details",
364
353
  fields: ["type", "title", "slug", "description", "startsAt", "endsAt", "tags"],
365
- validate: (values) => {
366
- if (!values.title.trim())
367
- return "Title is required";
368
- if (!values.startsAt)
369
- return "Start date is required";
370
- if (!values.endsAt)
371
- return "End date is required";
372
- return null;
373
- },
354
+ // The per-step `validate` is gone: every rule it stated is already in
355
+ // eventDraftSchema (title/startsAt/endsAt are .min(1)), and it only ever
356
+ // acted as a gate to the next step.
374
357
  render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Event Details" }), !isEdit && (_jsx(Select, { label: "Event type", value: values.type, options: allowedTypes ? EVENT_TYPE_OPTIONS.filter((o) => allowedTypes.includes(o.value)) : EVENT_TYPE_OPTIONS, onChange: (e) => onChange({ type: e.target.value }) })), _jsx(Input, { label: "Title", value: values.title, onChange: (e) => {
375
358
  const v = e.target.value;
376
359
  onChange({ title: v, ...(!slugManual && { slug: toEventSlug(v) }) });
377
360
  }, placeholder: "Charizard Flash Sale 2026", required: true }), _jsx(Input, { label: "Slug", value: values.slug, onChange: (e) => { setSlugManual(true); onChange({ slug: e.target.value }); }, placeholder: "event-charizard-flash-sale-2026", helperText: "Auto-generated from title. Must start with 'event-'." }), _jsxs(Stack, { gap: "xs", children: [_jsx(Label, { children: "Description" }), _jsx(RichTextEditor, { value: values.description, onChange: (v) => onChange({ description: v }), minHeightClassName: "min-h-[120px]", placeholder: "Describe this event\u2026" })] }), _jsxs(Grid, { cols: 2, gap: "sm", children: [_jsx(Input, { label: "Starts at", type: "datetime-local", value: values.startsAt, onChange: (e) => onChange({ startsAt: e.target.value }), required: true }), _jsx(Input, { label: "Ends at", type: "datetime-local", value: values.endsAt, onChange: (e) => onChange({ endsAt: e.target.value }), required: true })] }), _jsx(TagInput, { label: "Tags", value: values.tags, onChange: (t) => onChange({ tags: t }), placeholder: "e.g. pokemon, sale, 2026" })] })),
378
361
  },
379
362
  {
363
+ id: "media",
380
364
  label: "Media",
365
+ // <Collapse> unmounts its children — without this, collapsing the
366
+ // section mid-upload discards the transfer.
367
+ keepMounted: true,
381
368
  fields: ["coverImageUrl"],
382
369
  render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Media" }), _jsx(Input, { label: "Cover Image URL (optional)", value: values.coverImageUrl, onChange: (e) => onChange({ coverImageUrl: e.target.value }), placeholder: "https://\u2026", helperText: "Direct link to the event cover image." })] })),
383
370
  },
384
371
  {
372
+ id: "settings",
385
373
  label: "Settings",
386
374
  fields: ["status", "allowGuestParticipation", "discountPercent", "saleBannerText", "couponId", "displayCode", "offerBannerText", "pollOptions", "resultsVisibility", "allowMultiSelect", "allowComment", "maxEntriesPerUser", "hasLeaderboard", "hasPointSystem", "pointsLabel", "entryReviewRequired", "surveyFields", "anonymous", "feedbackFields"],
387
- validate: (values) => {
388
- if (values.type === "offer" && !values.couponId.trim())
389
- return "Coupon ID is required for offer events";
390
- if (values.type === "offer" && !values.displayCode.trim())
391
- return "Display code is required for offer events";
392
- if (values.type === "poll" && values.pollOptions.filter((o) => o.label.trim()).length < 2)
393
- return "Poll events require at least 2 options";
394
- return null;
395
- },
375
+ // Same: the offer-coupon, offer-display-code and poll-minimum-options
376
+ // rules are all stated in eventDraftSchema's superRefine, which now
377
+ // surfaces them inline on the field instead of as a step-blocking banner.
396
378
  render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Event Settings" }), isEdit && (_jsx(Select, { label: "Status", value: values.status, options: EVENT_STATUS_OPTIONS, onChange: (e) => onChange({ status: e.target.value }) })), values.createdBy && (_jsxs(Stack, { gap: "none", children: [_jsx(Text, { size: "sm", weight: "medium", className: "mb-1", children: "Created by" }), _jsx(Text, { size: "sm", color: "muted", children: values.createdBy })] })), _jsxs(Stack, { gap: "xs", surface: "muted", rounded: "lg", border: "default", padding: "sm", children: [_jsx(Toggle, { checked: values.allowGuestParticipation, onChange: (v) => onChange({ allowGuestParticipation: v }), label: "Allow guest participation (no login required)" }), _jsx(Text, { size: "xs", color: "muted", children: "When enabled, unauthenticated visitors can participate in this event (poll vote, survey/feedback response, raffle entry, or wheel spin), identified by a hashed IP address instead of an account. Applies uniformly to whatever entry mechanism this event type uses." })] }), values.type === "sale" && (_jsxs(Stack, { gap: "xs", surface: "muted", rounded: "lg", border: "default", padding: "sm", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "muted", children: "Sale configuration" }), _jsxs(Grid, { cols: 2, gap: "sm", children: [_jsx(Input, { label: "Discount %", type: "number", value: values.discountPercent, onChange: (e) => onChange({ discountPercent: e.target.value }), placeholder: "10" }), _jsx(Input, { label: "Banner text (optional)", value: values.saleBannerText, onChange: (e) => onChange({ saleBannerText: e.target.value }), placeholder: "Limited time \u2014 ends Sunday!" })] })] })), values.type === "offer" && (_jsxs(Stack, { gap: "xs", surface: "muted", rounded: "lg", border: "default", padding: "sm", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "muted", children: "Offer configuration" }), _jsxs(Grid, { cols: 2, gap: "sm", children: [_jsxs(Div, { children: [_jsx(Text, { size: "sm", weight: "medium", className: "mb-1", children: "Coupon" }), _jsx(CouponInlineSelect, { scope: "admin", value: values.couponId, onChange: (id) => onChange({ couponId: id ?? "" }), placeholder: "Search coupons\u2026", allowCreate: false })] }), _jsx(Input, { label: "Display code", value: values.displayCode, onChange: (e) => onChange({ displayCode: e.target.value }), placeholder: "CHARIZARD25", required: true })] }), _jsx(Input, { label: "Banner text (optional)", value: values.offerBannerText, onChange: (e) => onChange({ offerBannerText: e.target.value }), placeholder: "Use CHARIZARD25 at checkout" })] })), values.type === "poll" && (_jsxs(Stack, { gap: "md", rounded: "xl", border: "default", padding: "md", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "muted", children: "Poll configuration" }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Options (minimum 2)" }), values.pollOptions.map((opt, idx) => (_jsxs(Row, { gap: "xs", children: [_jsx(Div, { className: "flex-1", children: _jsx(Input, { value: opt.label, onChange: (e) => onChange({ pollOptions: values.pollOptions.map((o) => o.id === opt.id ? { ...o, label: e.target.value } : o) }), placeholder: `Option ${idx + 1}` }) }), values.pollOptions.length > 2 && (_jsx(Button, { variant: "ghost", type: "button", onClick: () => onChange({ pollOptions: values.pollOptions.filter((o) => o.id !== opt.id) }), className: CLS_REMOVE_BTN_PX2, "aria-label": "Remove option", children: "\u00D7" }))] }, opt.id))), _jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => onChange({ pollOptions: [...values.pollOptions, { id: `opt${Date.now()}`, label: "" }] }), children: "+ Add option" })] }), _jsx(Select, { label: "Results visibility", value: values.resultsVisibility, options: POLL_VISIBILITY_OPTIONS, onChange: (e) => onChange({ resultsVisibility: e.target.value }) }), _jsxs(Stack, { gap: "sm", children: [_jsx(Toggle, { checked: values.allowMultiSelect, onChange: (v) => onChange({ allowMultiSelect: v }), label: "Allow multi-select" }), _jsx(Toggle, { checked: values.allowComment, onChange: (v) => onChange({ allowComment: v }), label: "Allow comment with vote" })] })] })), values.type === "survey" && (_jsxs(Stack, { gap: "md", rounded: "xl", border: "default", padding: "md", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "muted", children: "Survey configuration" }), _jsxs(Grid, { cols: 2, gap: "sm", children: [_jsx(Input, { label: "Max entries per user", type: "number", value: values.maxEntriesPerUser, onChange: (e) => onChange({ maxEntriesPerUser: e.target.value }), placeholder: "1" }), values.hasPointSystem && (_jsx(Input, { label: "Points label", value: values.pointsLabel, onChange: (e) => onChange({ pointsLabel: e.target.value }), placeholder: "Points" }))] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Toggle, { checked: values.requireLogin, onChange: (v) => onChange({ requireLogin: v }), label: "Require login to participate" }), _jsx(Toggle, { checked: values.hasLeaderboard, onChange: (v) => onChange({ hasLeaderboard: v }), label: "Show leaderboard" }), _jsx(Toggle, { checked: values.hasPointSystem, onChange: (v) => onChange({ hasPointSystem: v }), label: "Enable point system" }), _jsx(Toggle, { checked: values.entryReviewRequired, onChange: (v) => onChange({ entryReviewRequired: v }), label: "Require employee review before entry is approved" })] }), _jsx(FormFieldBuilder, { fields: values.surveyFields, setFields: (f) => onChange({ surveyFields: f }) })] })), values.type === "feedback" && (_jsxs(Stack, { gap: "md", rounded: "xl", border: "default", padding: "md", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "muted", children: "Feedback configuration" }), _jsx(Toggle, { checked: values.anonymous, onChange: (v) => onChange({ anonymous: v }), label: "Allow anonymous submissions" }), _jsx(FormFieldBuilder, { fields: values.feedbackFields, setFields: (f) => onChange({ feedbackFields: f }) })] }))] })),
397
379
  },
398
380
  {
381
+ id: "raffle",
399
382
  label: "Raffle / Spin",
400
383
  fields: ["hasRaffle", "raffleType", "raffleTopN", "rafflePrize", "rafflePrizeCouponId", "rafflePrizeProductIds", "spinPrizes", "spinMaxPerUser", "spinWindowStart", "spinWindowEnd"],
401
384
  render: ({ values, onChange }) => {
@@ -407,16 +390,11 @@ export function AdminEventEditorView({ eventId, onSaved, embedded, allowedTypes,
407
390
  },
408
391
  ];
409
392
  const alertSection = eventQuery.error ? (_jsx(Alert, { variant: "error", title: "Could not load event", children: eventQuery.error instanceof Error ? eventQuery.error.message : "Unknown error" })) : null;
410
- const fieldToStepIndex = useMemo(() => {
411
- const map = {};
412
- steps.forEach((step, i) => {
413
- step.fields?.forEach((field) => { map[field] = i; });
414
- });
415
- return map;
416
- // eslint-disable-next-line react-hooks/exhaustive-deps
417
- }, [steps.length]);
418
- const wizardShellCtx = useMemo(() => ({ ...shellCtx, fieldToStepIndex, goToStep: (n) => setCurrentStep(n) }), [shellCtx, fieldToStepIndex, setCurrentStep]);
419
- const formContent = (_jsxs(Stack, { gap: "sm", children: [alertSection, _jsxs(FormShellContext.Provider, { value: wizardShellCtx, children: [_jsx(FormErrorSummary, {}), _jsx(StepForm, { steps: steps, values: draft, onChange: update, onComplete: () => { saveMutation.mutate(); }, formId: "admin-event", currentStep: currentStep, onStepChange: setCurrentStep, completeLabel: isEdit ? "Save Changes" : "Create Event", isLoading: isLoading })] }), saveMessage && (_jsx(Alert, { variant: saveMessage.toLowerCase().includes("fail") || saveMessage.toLowerCase().includes("error") ? "error" : "success", title: "Save status", children: saveMessage }))] }));
393
+ // Replaces the hand-rolled fieldToStepIndex + goToStep pair. The hook owns
394
+ // the expand-then-scroll ordering a raw setState cannot: a collapsed panel
395
+ // must MOUNT before scrollIntoView and focus can reach the offending field.
396
+ const { openIds, setOpenIds, goToSection, fieldToSectionIndex, sectionMeta } = useSectionFormNav(sections, draft);
397
+ const formContent = (_jsxs(Stack, { gap: "sm", children: [alertSection, _jsxs(FormShellContext.Provider, { value: shellCtx, children: [_jsx(FormErrorSummary, {}), _jsx(SectionForm, { sections: sections, values: draft, onChange: update, onSubmit: () => { saveMutation.mutate(); }, schema: eventDraftSchema, openIds: openIds, onOpenChange: setOpenIds, submitLabel: isEdit ? "Save Changes" : "Create Event", isLoading: isLoading })] }), saveMessage && (_jsx(Alert, { variant: saveMessage.toLowerCase().includes("fail") || saveMessage.toLowerCase().includes("error") ? "error" : "success", title: "Save status", children: saveMessage }))] }));
420
398
  if (embedded) {
421
399
  return _jsx(Div, { className: `${__O.yAuto} ${__P.p4}`, children: formContent });
422
400
  }
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useApiMutation, sieveFilter, SIEVE_OP, sortBy } from "@mohasinac/appkit/client";
4
- import React from "react";
4
+ import React, { useState } from "react";
5
5
  import { useQuery, useQueryClient } from "@tanstack/react-query";
6
- import { Alert, Button, Div, Input, Row, Select, Stack, Text, useToast } from "../../../ui";
6
+ import { Alert, Button, Div, Input, Row, Select, Stack, Text, useToast, RecordDetailModal, } from "../../../ui";
7
7
  import { apiClient } from "../../../http";
8
8
  import { normalizeError } from "../../../errors/normalize";
9
9
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
@@ -128,6 +128,10 @@ export function AdminEventEntriesView({ eventId, entriesEndpoint, entryReviewEnd
128
128
  },
129
129
  ];
130
130
  const eventTitle = statsQuery.data?.event?.title;
131
+ // Approve / Waitlist / Cancel were offered on an entry the admin could never
132
+ // read — the poll vote, the comment and the survey answers were all invisible
133
+ // (Root Cause #56, "acting blind"). The row already carries the whole entry.
134
+ const [detail, setDetail] = useState(null);
131
135
  const config = {
132
136
  portal: "admin",
133
137
  title: eventTitle ? `${eventTitle} Entries` : "Event Entries",
@@ -139,6 +143,7 @@ export function AdminEventEntriesView({ eventId, entriesEndpoint, entryReviewEnd
139
143
  endpoint: resolvedEntriesEndpoint,
140
144
  sortOptions: [{ value: sortBy("submittedAt", "DESC"), label: "Most recent" }],
141
145
  columns,
146
+ onRowClick: (row) => setDetail(row),
142
147
  mapRows: (response) => response.items ?? [],
143
148
  getTotal: (response) => response.total ?? (response.items ?? []).length,
144
149
  buildFilters: (state) => state.reviewStatus ? sieveFilter("reviewStatus", SIEVE_OP.EQ, state.reviewStatus) : undefined,
@@ -146,5 +151,19 @@ export function AdminEventEntriesView({ eventId, entriesEndpoint, entryReviewEnd
146
151
  toolbarExtra: eventId ? (_jsx(Button, { variant: "ghost", action: ACTIONS.ADMIN["export-event-entries"], onClick: handleExportReport })) : undefined,
147
152
  renderAboveContent: () => (_jsxs(Stack, { gap: "3", className: "px-[var(--appkit-space-3)] pb-[var(--appkit-space-2)]", children: [!eventId ? (_jsx(Alert, { variant: "warning", title: "Missing event id", children: "Event id is required to load entries." })) : null, statsQuery.error ? (_jsx(Alert, { variant: "error", title: "Could not load event stats", children: statsQuery.error instanceof Error ? statsQuery.error.message : "Unknown error" })) : null, _jsxs(Div, { layout: "grid", gap: "3", className: "grid-cols-1 sm:grid-cols-3", children: [_jsx(Alert, { variant: "info", title: "Total entries", children: String(statsQuery.data?.stats?.totalEntries ?? 0) }), _jsx(Alert, { variant: "success", title: "Approved", children: String(statsQuery.data?.stats?.approvedEntries ?? 0) }), _jsx(Alert, { variant: "warning", title: "Flagged", children: String(statsQuery.data?.stats?.flaggedEntries ?? 0) })] })] })),
148
153
  };
149
- return _jsx(DataListingView, { config: config });
154
+ return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(RecordDetailModal, { isOpen: detail !== null, onClose: () => setDetail(null), title: detail?.userDisplayName || detail?.userEmail || "Entry", badges: detail ? [{ label: detail.reviewStatus }] : undefined, description: detail?.pollComment, fields: detail
155
+ ? [
156
+ { label: "Entrant", value: detail.userDisplayName ?? detail.userId ?? "—" },
157
+ { label: "Email", value: detail.userEmail ?? "—" },
158
+ { label: "Review status", value: detail.reviewStatus },
159
+ { label: "Points", value: detail.points != null ? String(detail.points) : "—" },
160
+ { label: "Raffle eligible", value: detail.raffleEligible ? "Yes" : "No" },
161
+ { label: "Poll votes", value: detail.pollVotes?.join(", ") || "—" },
162
+ { label: "Reviewed by", value: detail.reviewedBy ?? "—" },
163
+ { label: "Review note", value: detail.reviewNote ?? "—" },
164
+ { label: "Entry ID", value: detail.id },
165
+ ]
166
+ : undefined,
167
+ // The survey/feedback answers — the actual submission being judged.
168
+ metadata: detail?.formResponses })] }));
150
169
  }