@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
@@ -0,0 +1,89 @@
1
+ /*
2
+ * WHY: `POST /api/store/grouped-listings` spread the raw request body into
3
+ * `.create()` and its PATCH built `{...body}` — no Zod on either. The two
4
+ * pages behind them validated one field between them (`new` checked
5
+ * `title` was non-empty and toasted; `[id]/edit` checked nothing at all).
6
+ * WHAT: One schema for the pages AND the store routes.
7
+ *
8
+ * ## `activeMemberCount` is NOT in this schema
9
+ *
10
+ * It is derived — both routes already recompute it from `productIds.length`,
11
+ * which is correct and was verified rather than assumed. Accepting it from the
12
+ * body would let a caller set a count that disagrees with the array, and the
13
+ * count is what the public visibility check reads.
14
+ *
15
+ * `slug`, `visibilityStatus` and `createdBy` are absent for the same reason:
16
+ * derived or session-owned, never typed.
17
+ *
18
+ * EXPORTS:
19
+ * groupedListingFormSchema, groupedListingCreateSchema,
20
+ * groupedListingUpdateSchema, type GroupedListingFormValues
21
+ *
22
+ * @tag domain:grouped
23
+ * @tag layer:schema
24
+ * @tag pattern:none
25
+ * @tag access:isomorphic
26
+ * @tag consumers:store/grouped-listings pages,/api/store/grouped-listings
27
+ * @tag sideEffects:none
28
+ */
29
+ import { z } from "zod";
30
+ import { annotate } from "../../shell/field-ui-meta";
31
+ /** Mirrors `GroupTheme` in ./firestore. */
32
+ const groupThemeSchema = z.enum(["related", "character", "lineage", "set", "generic"]);
33
+ /**
34
+ * 🛑 `annotate()` must be the OUTERMOST call on each field — it keys a WeakMap
35
+ * by schema instance and every zod wrapper returns a new one.
36
+ */
37
+ export const groupedListingFormSchema = z.object({
38
+ title: annotate(z.string().min(1, "Title is required").max(120, "Keep the title under 120 characters."), {
39
+ section: "basics", sectionLabel: "Group", sectionRequired: true,
40
+ quick: true, order: 1, row: "full",
41
+ }),
42
+ description: annotate(z.string().max(500, "Keep the description under 500 characters.").optional(), {
43
+ section: "basics", order: 2, row: "full",
44
+ }),
45
+ groupTheme: annotate(groupThemeSchema, {
46
+ section: "basics", quick: true, order: 3, row: "pair",
47
+ }),
48
+ productIds: annotate(z.array(z.string()), {
49
+ section: "members", sectionLabel: "Members", order: 1, row: "full", kind: "list",
50
+ }),
51
+ minActiveMembers: annotate(z.coerce.number().int("Must be a whole number.").min(1, "A group needs at least one member to show."), {
52
+ section: "members", order: 2, row: "pair",
53
+ help: "Below this many in-stock members, the group hides itself.",
54
+ }),
55
+ coverImage: annotate(z.string().optional(), {
56
+ section: "media", sectionLabel: "Media", order: 1, row: "full", kind: "media",
57
+ }),
58
+ isActive: annotate(z.boolean(), {
59
+ section: "visibility", sectionLabel: "Visibility", order: 1, row: "quarter",
60
+ }),
61
+ isFeatured: annotate(z.boolean(), {
62
+ section: "visibility", order: 2, row: "quarter",
63
+ }),
64
+ });
65
+ /**
66
+ * Create contract. `storeId` is absent — the store route sets it from the
67
+ * session, so a seller cannot file a group under another store.
68
+ */
69
+ export const groupedListingCreateSchema = groupedListingFormSchema.partial({
70
+ description: true,
71
+ coverImage: true,
72
+ isFeatured: true,
73
+ minActiveMembers: true,
74
+ });
75
+ /** Update contract — partial, `.strict()` so an unknown key is a 400. */
76
+ export const groupedListingUpdateSchema = z
77
+ .object({
78
+ title: z.string().min(1).max(120).optional(),
79
+ description: z.string().max(500).optional(),
80
+ groupTheme: groupThemeSchema.optional(),
81
+ productIds: z.array(z.string()).optional(),
82
+ minActiveMembers: z.coerce.number().int().min(1).optional(),
83
+ coverImage: z.string().optional(),
84
+ isActive: z.boolean().optional(),
85
+ isFeatured: z.boolean().optional(),
86
+ brandSlug: z.string().optional(),
87
+ categorySlug: z.string().optional(),
88
+ })
89
+ .strict();
@@ -43,9 +43,9 @@ export declare const groupedListingFirestoreSchema: z.ZodObject<{
43
43
  toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
44
44
  }, z.ZodTypeAny, "passthrough">;
45
45
  slug: string;
46
- isFeatured: boolean;
47
46
  isActive: boolean;
48
47
  createdBy: string;
48
+ isFeatured: boolean;
49
49
  productIds: string[];
50
50
  groupTheme: "set" | "related" | "character" | "lineage" | "generic";
51
51
  visibilityStatus: "hidden" | "visible";
@@ -53,8 +53,8 @@ export declare const groupedListingFirestoreSchema: z.ZodObject<{
53
53
  activeMemberCount: number;
54
54
  storeId?: string | undefined;
55
55
  description?: string | undefined;
56
- brandSlug?: string | undefined;
57
56
  categorySlug?: string | undefined;
57
+ brandSlug?: string | undefined;
58
58
  coverImage?: string | undefined;
59
59
  }, {
60
60
  id: string;
@@ -66,9 +66,9 @@ export declare const groupedListingFirestoreSchema: z.ZodObject<{
66
66
  toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
67
67
  }, z.ZodTypeAny, "passthrough">;
68
68
  slug: string;
69
- isFeatured: boolean;
70
69
  isActive: boolean;
71
70
  createdBy: string;
71
+ isFeatured: boolean;
72
72
  productIds: string[];
73
73
  groupTheme: "set" | "related" | "character" | "lineage" | "generic";
74
74
  visibilityStatus: "hidden" | "visible";
@@ -76,8 +76,8 @@ export declare const groupedListingFirestoreSchema: z.ZodObject<{
76
76
  activeMemberCount: number;
77
77
  storeId?: string | undefined;
78
78
  description?: string | undefined;
79
- brandSlug?: string | undefined;
80
79
  categorySlug?: string | undefined;
80
+ brandSlug?: string | undefined;
81
81
  coverImage?: string | undefined;
82
82
  }>;
83
83
  export type GroupedListingFromSchema = z.infer<typeof groupedListingFirestoreSchema>;
@@ -2,21 +2,29 @@ import { z } from "zod";
2
2
  import type { HomepageSectionDocument } from "../schemas";
3
3
  import type { FirebaseSieveResult } from "../../../providers/db-firebase";
4
4
  export declare const createSectionSchema: z.ZodObject<{
5
- type: z.ZodString;
5
+ type: z.ZodEnum<["welcome", "carousel", "stats", "trust-indicators", "categories", "brands", "products", "pre-orders", "auctions", "banner", "features", "reviews", "whatsapp-community", "faq", "blog-articles", "newsletter", "stores", "events", "social-feed", "custom-cards", "google-reviews", "featured-bundles", "prize-draws", "event-raffles", "collection-cards"]>;
6
6
  enabled: z.ZodDefault<z.ZodBoolean>;
7
7
  order: z.ZodDefault<z.ZodNumber>;
8
8
  config: z.ZodOptional<z.ZodObject<{}, "passthrough", z.ZodTypeAny, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">, z.objectInputType<{}, z.ZodTypeAny, "passthrough">>>;
9
9
  }, "strip", z.ZodTypeAny, {
10
- type: string;
10
+ type: "banner" | "stores" | "products" | "pre-orders" | "prize-draws" | "auctions" | "reviews" | "events" | "categories" | "brands" | "carousel" | "newsletter" | "features" | "stats" | "welcome" | "trust-indicators" | "whatsapp-community" | "faq" | "blog-articles" | "social-feed" | "custom-cards" | "google-reviews" | "featured-bundles" | "event-raffles" | "collection-cards";
11
11
  enabled: boolean;
12
12
  order: number;
13
13
  config?: z.objectOutputType<{}, z.ZodTypeAny, "passthrough"> | undefined;
14
14
  }, {
15
- type: string;
15
+ type: "banner" | "stores" | "products" | "pre-orders" | "prize-draws" | "auctions" | "reviews" | "events" | "categories" | "brands" | "carousel" | "newsletter" | "features" | "stats" | "welcome" | "trust-indicators" | "whatsapp-community" | "faq" | "blog-articles" | "social-feed" | "custom-cards" | "google-reviews" | "featured-bundles" | "event-raffles" | "collection-cards";
16
16
  enabled?: boolean | undefined;
17
17
  order?: number | undefined;
18
18
  config?: z.objectInputType<{}, z.ZodTypeAny, "passthrough"> | undefined;
19
19
  }>;
20
+ /**
21
+ * The next free `order` value.
22
+ *
23
+ * `HomepageSectionCreateInput.order` is REQUIRED, and both API create routes
24
+ * need the same answer for "the caller did not choose one". Two copies of this
25
+ * query is how they would come to disagree about where a new section lands.
26
+ */
27
+ export declare function resolveNextSectionOrder(): Promise<number>;
20
28
  export declare const updateSectionSchema: z.ZodObject<{
21
29
  order: z.ZodOptional<z.ZodNumber>;
22
30
  enabled: z.ZodOptional<z.ZodBoolean>;
@@ -1,13 +1,45 @@
1
1
  import { z } from "zod";
2
2
  import { serverLogger } from "../../../monitoring";
3
+ import { sortBy } from "../../../constants/sort";
4
+ import { HOMEPAGE_SECTION_FIELDS } from "../../../constants/field-names";
3
5
  import { homepageSectionsRepository } from "../repository/homepage-sections.repository";
6
+ import { homepageSectionTypeSchema } from "../schemas";
4
7
  // --- Schemas --------------------------------------------------------------
8
+ /*
9
+ * 🛑 `type` was `z.string().min(1)` — ANY non-empty string.
10
+ *
11
+ * This is the third of three create paths for `homepageSections`
12
+ * (`POST /api/admin/sections`, `POST /api/homepage-sections`, and this server
13
+ * action via `createHomepageSectionAction`), and it was the loosest: a caller
14
+ * could store a section whose `type` matches no renderer, which the homepage
15
+ * then skips in silence — a row that exists, occupies an order slot, and draws
16
+ * nothing.
17
+ *
18
+ * All three now agree on `homepageSectionTypeSchema`, which is derived from
19
+ * the `SectionType` union.
20
+ */
5
21
  export const createSectionSchema = z.object({
6
- type: z.string().min(1),
22
+ type: homepageSectionTypeSchema,
7
23
  enabled: z.boolean().default(true),
8
24
  order: z.number().int().default(0),
9
25
  config: z.object({}).passthrough().optional(),
10
26
  });
27
+ /**
28
+ * The next free `order` value.
29
+ *
30
+ * `HomepageSectionCreateInput.order` is REQUIRED, and both API create routes
31
+ * need the same answer for "the caller did not choose one". Two copies of this
32
+ * query is how they would come to disagree about where a new section lands.
33
+ */
34
+ export async function resolveNextSectionOrder() {
35
+ const latest = await homepageSectionsRepository.list({
36
+ sorts: sortBy(HOMEPAGE_SECTION_FIELDS.ORDER),
37
+ page: "1",
38
+ pageSize: "1",
39
+ });
40
+ const top = latest.items[0]?.order;
41
+ return typeof top === "number" ? top + 1 : 1;
42
+ }
11
43
  export const updateSectionSchema = z.object({
12
44
  order: z.number().int().optional(),
13
45
  enabled: z.boolean().optional(),
@@ -2,6 +2,12 @@ import React from "react";
2
2
  export declare function hashBannerMessage(msg: string): string;
3
3
  export interface AnnouncementBarProps {
4
4
  message: string;
5
+ /**
6
+ * Optional destination for the message. The admin editor has collected this
7
+ * (and `backgroundColor`) since it was built, but neither was ever rendered —
8
+ * so both were silently discarded on save. Wired 2026-08-24.
9
+ */
10
+ link?: string;
5
11
  className?: string;
6
12
  /** Called when the user dismisses — consumer wires this to a server action to persist. */
7
13
  onDismiss?: (hash: string) => void;
@@ -14,4 +20,4 @@ export interface AnnouncementBarProps {
14
20
  */
15
21
  overlay?: boolean;
16
22
  }
17
- export declare function AnnouncementBar({ message, className, onDismiss, overlay }: AnnouncementBarProps): React.JSX.Element | null;
23
+ export declare function AnnouncementBar({ message, link, className, onDismiss, overlay }: AnnouncementBarProps): React.JSX.Element | null;
@@ -5,7 +5,7 @@ import { useState, useEffect } from "react";
5
5
  import { X } from "lucide-react";
6
6
  import { useAuth } from "../../../react/contexts/SessionContext";
7
7
  import { Div } from "../../../ui/components/Div";
8
- import { IconButton, Row, Span } from "@mohasinac/appkit/client";
8
+ import { IconButton, Row, Span, TextLink } from "@mohasinac/appkit/client";
9
9
  const STORAGE_KEY = "letitrip:announcement-dismissed";
10
10
  const ONE_WEEK_MS = 7 * 24 * 60 * 60 * 1000;
11
11
  export function hashBannerMessage(msg) {
@@ -38,7 +38,7 @@ function saveLocalDismissal(message) {
38
38
  void normalizeError(_err); /* quota exceeded — ignore */
39
39
  }
40
40
  }
41
- export function AnnouncementBar({ message, className = "", onDismiss, overlay = false }) {
41
+ export function AnnouncementBar({ message, link, className = "", onDismiss, overlay = false }) {
42
42
  const { user } = useAuth();
43
43
  const bannerHash = hashBannerMessage(message);
44
44
  const userAlreadyDismissed = !!user?.dismissedBannerHash && user.dismissedBannerHash === bannerHash;
@@ -58,7 +58,7 @@ export function AnnouncementBar({ message, className = "", onDismiss, overlay =
58
58
  const positionCls = overlay
59
59
  ? "absolute inset-x-0 top-0 z-20 bg-primary-700/85 backdrop-blur-sm"
60
60
  : "relative left-1/2 right-1/2 w-screen -translate-x-1/2 bg-primary-700";
61
- return (_jsx(Div, { className: `${positionCls} transition-opacity duration-200 ${mounted ? "opacity-100" : "opacity-0"} ${className}`, role: "banner", children: _jsx(Div, { paddingX: "x-page", className: "container mx-auto max-w-[1920px]", children: _jsxs(Row, { textWeight: "medium", textSize: "sm", className: "relative text-left text-white", padding: "y-xs", align: "center", justify: "start", children: [_jsx(Span, { children: message }), _jsx(IconButton, { type: "button", onClick: () => {
61
+ return (_jsx(Div, { className: `${positionCls} transition-opacity duration-200 ${mounted ? "opacity-100" : "opacity-0"} ${className}`, role: "banner", children: _jsx(Div, { paddingX: "x-page", className: "container mx-auto max-w-[1920px]", children: _jsxs(Row, { textWeight: "medium", textSize: "sm", className: "relative text-left text-white", padding: "y-xs", align: "center", justify: "start", children: [link ? (_jsx(TextLink, { href: link, className: "text-white underline", children: message })) : (_jsx(Span, { children: message })), _jsx(IconButton, { type: "button", onClick: () => {
62
62
  saveLocalDismissal(message);
63
63
  onDismiss?.(bannerHash);
64
64
  setDismissed(true);
@@ -6,10 +6,12 @@ import { carouselRepository, faqsRepository, siteSettingsRepository } from "../.
6
6
  import { fetchLiveStats } from "../lib/live-stats";
7
7
  import { renderSection, AnnouncementBar } from "../lib/section-renderer";
8
8
  import { homepageSectionsRepository } from "../repository/homepage-sections.repository";
9
+ import { filterSectionsByFeatureFlags } from "../../../_internal/shared/features/homepage/section-gate";
9
10
  import { getFeaturedProducts, getFeaturedAuctions, getFeaturedPreOrders } from "../../products/actions/product-actions";
10
11
  import { listTopLevelCategories, listBrandCategories } from "../../categories/actions/category-actions";
11
12
  import { listFeaturedBundles } from "../../../_internal/server/features/bundles/data";
12
13
  import { listStores } from "../../stores/actions/store-query-actions";
14
+ import { toStoreListItem } from "../../../_internal/server/features/stores/adapters";
13
15
  import { getFeaturedBlogPosts } from "../../blog/actions/blog-actions";
14
16
  import { listPublicEvents } from "../../events/actions/event-actions";
15
17
  /**
@@ -31,10 +33,14 @@ export async function MarketplaceHomepageView({ adSlots, newsletterFormSlot, onB
31
33
  const announcementMessage = siteSettings?.announcementBar?.message?.trim() ||
32
34
  "🎉 Up to 15% Off on Pokémon TCG this week — Use code SAVE15";
33
35
  const showAnnouncement = siteSettings?.announcementBar?.enabled ?? true;
34
- const [enabledSections, rawFaqItems] = await Promise.all([
36
+ const [allSections, rawFaqItems] = await Promise.all([
35
37
  homepageSectionsRepository.getEnabledSections().catch(() => []),
36
38
  faqsRepository.getHomepageFAQs().catch(() => []),
37
39
  ]);
40
+ // Respect the feature flags. This gate existed but lived inside a function
41
+ // with no call sites, so until 2026-08-24 turning off `auctions` hid auctions
42
+ // everywhere EXCEPT the homepage, which went on advertising them.
43
+ const enabledSections = filterSectionsByFeatureFlags(allSections, siteSettings?.featureFlags);
38
44
  // Collect live metric requests from all enabled stats sections
39
45
  const liveStatRequests = [];
40
46
  for (const section of enabledSections) {
@@ -74,9 +80,13 @@ export async function MarketplaceHomepageView({ adSlots, newsletterFormSlot, onB
74
80
  // Determine which data-driven section types are active so we only fetch what's needed
75
81
  const activeTypes = new Set(orderedSections.map((s) => s.type));
76
82
  const [productsResult, auctionsResult, preOrdersResult, categoriesResult, brandsResult, bundlesResult, storesResult, blogResult, eventsResult,] = await Promise.all([
77
- activeTypes.has("products") ? getFeaturedProducts(12).catch(() => null) : null,
78
- activeTypes.has("auctions") ? getFeaturedAuctions(12).catch(() => null) : null,
79
- activeTypes.has("pre-orders") ? getFeaturedPreOrders(12).catch(() => null) : null,
83
+ // No `.catch(() => null)` on these three: they go through
84
+ // `listPublicProducts`, which already logs a failed query loudly and
85
+ // returns an empty result. Swallowing here would make a broken query
86
+ // indistinguishable from an empty catalogue (Root Cause #59).
87
+ activeTypes.has("products") ? getFeaturedProducts(12) : null,
88
+ activeTypes.has("auctions") ? getFeaturedAuctions(12) : null,
89
+ activeTypes.has("pre-orders") ? getFeaturedPreOrders(12) : null,
80
90
  activeTypes.has("categories") ? listTopLevelCategories(12).catch(() => null) : null,
81
91
  activeTypes.has("brands") ? listBrandCategories(12).catch(() => null) : null,
82
92
  activeTypes.has("featured-bundles") ? listFeaturedBundles(8).catch(() => null) : null,
@@ -104,8 +114,12 @@ export async function MarketplaceHomepageView({ adSlots, newsletterFormSlot, onB
104
114
  ? brandsResult
105
115
  : undefined,
106
116
  bundles: bundlesResult?.length ? bundlesResult : undefined,
117
+ // Projected, NOT cast. FeaturedStoresSection is a Client Component and this
118
+ // value becomes its `initialItems`, so a raw StoreDocument here would be
119
+ // serialised into the homepage's public HTML — secrets included. Every
120
+ // other cast in this object maps a document that carries no secrets.
107
121
  stores: storesResult?.items?.length
108
- ? storesResult.items
122
+ ? storesResult.items.map((s) => toStoreListItem(s))
109
123
  : undefined,
110
124
  blog: blogResult?.length
111
125
  ? blogResult
@@ -115,5 +129,5 @@ export async function MarketplaceHomepageView({ adSlots, newsletterFormSlot, onB
115
129
  : undefined,
116
130
  };
117
131
  const carouselSlides = toCarouselSlides(slides);
118
- return (_jsx(Main, { children: _jsxs(Div, { className: "relative", children: [showAnnouncement ? (_jsx(AnnouncementBar, { overlay: true, message: announcementMessage, onDismiss: onBannerDismiss })) : null, orderedSections.map((section) => renderSection(section, adSlots, newsletterFormSlot ?? null, faqItems, carouselSlides, liveStats, sectionData))] }) }));
132
+ return (_jsx(Main, { children: _jsxs(Div, { className: "relative", children: [showAnnouncement ? (_jsx(AnnouncementBar, { overlay: true, message: announcementMessage, link: siteSettings?.announcementBar?.link, onDismiss: onBannerDismiss })) : null, orderedSections.map((section) => renderSection(section, adSlots, newsletterFormSlot ?? null, faqItems, carouselSlides, liveStats, sectionData))] }) }));
119
133
  }
@@ -0,0 +1,16 @@
1
+ /** How many cards a homepage carousel wants before it stops back-filling. */
2
+ export declare const MIN_HOMEPAGE_COUNT = 12;
3
+ export interface HomepageListingQuery {
4
+ listingType?: string;
5
+ brand?: string;
6
+ featured?: boolean;
7
+ isPromoted?: boolean;
8
+ sorts?: string;
9
+ pageSize: number;
10
+ }
11
+ /**
12
+ * Always sends `availability=available`. The API treats an ABSENT value as
13
+ * "all" so that non-browse callers are unaffected — which means omitting it
14
+ * here is precisely how a homepage strip starts showing dead listings again.
15
+ */
16
+ export declare function buildHomepageListingQuery(input: HomepageListingQuery): string;
@@ -0,0 +1,45 @@
1
+ /*
2
+ * WHY: The three homepage listing hooks each hand-wrote a pre-URL-encoded
3
+ * `filters=` Sieve string — `listingType%3D%3Dauction%2Cstatus%3D%3D…`.
4
+ * Unreadable, unreviewable, and each one silently omitted any liveness
5
+ * bound, so all three showed sold-out / ended / closed rows. Worse, they
6
+ * run AFTER the SSR paint and replace it, so a fix to the server half
7
+ * alone would have been undone 30 seconds later (Root Cause #30).
8
+ *
9
+ * WHAT: Build the query string from the same TYPED params
10
+ * `parsePublicProductParams` reads on the other side, so a homepage
11
+ * strip asks precisely what its SSR counterpart asked.
12
+ *
13
+ * EXPORTS: buildHomepageListingQuery, HomepageListingQuery, MIN_HOMEPAGE_COUNT
14
+ *
15
+ * @tag domain:homepage
16
+ * @tag layer:hook
17
+ * @tag pattern:none
18
+ * @tag access:client
19
+ * @tag consumers:useFeaturedAuctions,useFeaturedPreOrders,useFeaturedProducts
20
+ * @tag sideEffects:none
21
+ */
22
+ import { AVAILABILITY_VALUES } from "../../../constants/field-names";
23
+ /** How many cards a homepage carousel wants before it stops back-filling. */
24
+ export const MIN_HOMEPAGE_COUNT = 12;
25
+ /**
26
+ * Always sends `availability=available`. The API treats an ABSENT value as
27
+ * "all" so that non-browse callers are unaffected — which means omitting it
28
+ * here is precisely how a homepage strip starts showing dead listings again.
29
+ */
30
+ export function buildHomepageListingQuery(input) {
31
+ const sp = new URLSearchParams();
32
+ sp.set("availability", AVAILABILITY_VALUES.AVAILABLE);
33
+ if (input.listingType)
34
+ sp.set("listingType", input.listingType);
35
+ if (input.brand)
36
+ sp.set("brand", input.brand);
37
+ if (input.featured)
38
+ sp.set("featured", "true");
39
+ if (input.isPromoted)
40
+ sp.set("isPromoted", "true");
41
+ if (input.sorts)
42
+ sp.set("sorts", input.sorts);
43
+ sp.set("pageSize", String(input.pageSize));
44
+ return sp.toString();
45
+ }
@@ -1,4 +1,14 @@
1
1
  import type { ProductItem } from "../../products/types";
2
+ /**
3
+ * The soonest-ending LIVE auctions, for the homepage strip.
4
+ *
5
+ * This runs 30s after the SSR paint and REPLACES it, so it has to ask the
6
+ * server exactly what `getFeaturedAuctions` asked. It did not: both queries
7
+ * here were `listingType==auction,status==published` with no end-date bound,
8
+ * hand-written as a raw pre-encoded `filters=` string. So even once the SSR
9
+ * half was fixed, the strip would have reverted to showing expired auctions
10
+ * half a minute later (Root Cause #30).
11
+ */
2
12
  export declare function useFeaturedAuctions(options?: {
3
13
  filterByBrand?: string;
4
14
  initialData?: ProductItem[];
@@ -1,21 +1,41 @@
1
1
  import { useQuery } from "@tanstack/react-query";
2
2
  import { apiClient } from "../../../http";
3
3
  import { PRODUCT_ENDPOINTS } from "../../../constants/api-endpoints";
4
- const MIN_COUNT = 12;
4
+ import { buildHomepageListingQuery, MIN_HOMEPAGE_COUNT } from "./homepage-query";
5
+ import { sortBy } from "../../../constants/sort";
6
+ import { PRODUCT_FIELDS } from "../../../constants/field-names";
7
+ /**
8
+ * The soonest-ending LIVE auctions, for the homepage strip.
9
+ *
10
+ * This runs 30s after the SSR paint and REPLACES it, so it has to ask the
11
+ * server exactly what `getFeaturedAuctions` asked. It did not: both queries
12
+ * here were `listingType==auction,status==published` with no end-date bound,
13
+ * hand-written as a raw pre-encoded `filters=` string. So even once the SSR
14
+ * half was fixed, the strip would have reverted to showing expired auctions
15
+ * half a minute later (Root Cause #30).
16
+ */
5
17
  export function useFeaturedAuctions(options) {
6
- const brandFilter = options?.filterByBrand
7
- ? `%2Cbrand%3D%3D${encodeURIComponent(options.filterByBrand)}`
8
- : "";
9
18
  return useQuery({
10
19
  queryKey: ["auctions", "featured", options?.filterByBrand ?? "all"],
11
20
  initialData: options?.initialData,
12
21
  queryFn: async () => {
13
- const promotedRes = await apiClient.get(`${PRODUCT_ENDPOINTS.LIST}?filters=listingType%3D%3Dauction%2Cstatus%3D%3Dpublished%2CisPromoted%3D%3Dtrue${brandFilter}&pageSize=18`);
22
+ const promotedRes = await apiClient.get(`${PRODUCT_ENDPOINTS.LIST}?${buildHomepageListingQuery({
23
+ listingType: "auction",
24
+ brand: options?.filterByBrand,
25
+ isPromoted: true,
26
+ sorts: sortBy(PRODUCT_FIELDS.AUCTION_END_DATE, "ASC"),
27
+ pageSize: 18,
28
+ })}`);
14
29
  const promoted = promotedRes?.items ?? [];
15
- if (promoted.length >= MIN_COUNT)
30
+ if (promoted.length >= MIN_HOMEPAGE_COUNT)
16
31
  return promoted;
17
- const remaining = MIN_COUNT - promoted.length;
18
- const latestRes = await apiClient.get(`${PRODUCT_ENDPOINTS.LIST}?filters=listingType%3D%3Dauction%2Cstatus%3D%3Dpublished${brandFilter}&sorts=-createdAt&pageSize=${remaining + promoted.length}`);
32
+ const remaining = MIN_HOMEPAGE_COUNT - promoted.length;
33
+ const latestRes = await apiClient.get(`${PRODUCT_ENDPOINTS.LIST}?${buildHomepageListingQuery({
34
+ listingType: "auction",
35
+ brand: options?.filterByBrand,
36
+ sorts: sortBy(PRODUCT_FIELDS.AUCTION_END_DATE, "ASC"),
37
+ pageSize: remaining + promoted.length,
38
+ })}`);
19
39
  const latest = latestRes?.items ?? [];
20
40
  const existingIds = new Set(promoted.map((a) => a.id));
21
41
  const filler = latest
@@ -1,21 +1,30 @@
1
1
  import { useQuery } from "@tanstack/react-query";
2
2
  import { apiClient } from "../../../http";
3
3
  import { PRODUCT_ENDPOINTS } from "../../../constants/api-endpoints";
4
- const MIN_COUNT = 12;
4
+ import { buildHomepageListingQuery, MIN_HOMEPAGE_COUNT } from "./homepage-query";
5
+ import { sortBy } from "../../../constants/sort";
6
+ import { PRODUCT_FIELDS } from "../../../constants/field-names";
5
7
  export function useFeaturedPreOrders(options) {
6
- const brandFilter = options?.filterByBrand
7
- ? `%2Cbrand%3D%3D${encodeURIComponent(options.filterByBrand)}`
8
- : "";
9
8
  return useQuery({
10
9
  queryKey: ["pre-orders", "featured", options?.filterByBrand ?? "all"],
11
10
  initialData: options?.initialData,
12
11
  queryFn: async () => {
13
- const featuredRes = await apiClient.get(`${PRODUCT_ENDPOINTS.LIST}?filters=listingType%3D%3Dpre-order%2Cstatus%3D%3Dpublished${brandFilter}&sorts=preOrderDeliveryDate&pageSize=6`);
12
+ const featuredRes = await apiClient.get(`${PRODUCT_ENDPOINTS.LIST}?${buildHomepageListingQuery({
13
+ listingType: "pre-order",
14
+ brand: options?.filterByBrand,
15
+ sorts: sortBy(PRODUCT_FIELDS.PRE_ORDER_DELIVERY_DATE, "ASC"),
16
+ pageSize: 6,
17
+ })}`);
14
18
  const featured = featuredRes?.items ?? [];
15
- if (featured.length >= MIN_COUNT)
19
+ if (featured.length >= MIN_HOMEPAGE_COUNT)
16
20
  return featured;
17
- const remaining = MIN_COUNT - featured.length;
18
- const latestRes = await apiClient.get(`${PRODUCT_ENDPOINTS.LIST}?filters=listingType%3D%3Dpre-order%2Cstatus%3D%3Dpublished${brandFilter}&sorts=-createdAt&pageSize=${remaining + featured.length}`);
21
+ const remaining = MIN_HOMEPAGE_COUNT - featured.length;
22
+ const latestRes = await apiClient.get(`${PRODUCT_ENDPOINTS.LIST}?${buildHomepageListingQuery({
23
+ listingType: "pre-order",
24
+ brand: options?.filterByBrand,
25
+ sorts: sortBy(PRODUCT_FIELDS.CREATED_AT, "DESC"),
26
+ pageSize: remaining + featured.length,
27
+ })}`);
19
28
  const latest = latestRes?.items ?? [];
20
29
  const existingIds = new Set(featured.map((p) => p.id));
21
30
  const filler = latest
@@ -1,20 +1,27 @@
1
1
  import { useQuery } from "@tanstack/react-query";
2
2
  import { apiClient } from "../../../http";
3
3
  import { PRODUCT_ENDPOINTS } from "../../../constants/api-endpoints";
4
- const MIN_COUNT = 12;
4
+ import { buildHomepageListingQuery, MIN_HOMEPAGE_COUNT } from "./homepage-query";
5
+ import { sortBy } from "../../../constants/sort";
6
+ import { PRODUCT_FIELDS } from "../../../constants/field-names";
5
7
  export function useFeaturedProducts(options) {
6
- const brandFilter = options?.filterByBrand
7
- ? `%2Cbrand%3D%3D${encodeURIComponent(options.filterByBrand)}`
8
- : "";
9
8
  return useQuery({
10
9
  queryKey: ["products", "featured", options?.filterByBrand ?? "all"],
11
10
  queryFn: async () => {
12
- const promotedRes = await apiClient.get(`${PRODUCT_ENDPOINTS.LIST}?filters=isPromoted%3D%3Dtrue%2Cstatus%3D%3Dpublished${brandFilter}&pageSize=18`);
11
+ const promotedRes = await apiClient.get(`${PRODUCT_ENDPOINTS.LIST}?${buildHomepageListingQuery({
12
+ brand: options?.filterByBrand,
13
+ isPromoted: true,
14
+ pageSize: 18,
15
+ })}`);
13
16
  const promoted = promotedRes?.items ?? [];
14
- if (promoted.length >= MIN_COUNT)
17
+ if (promoted.length >= MIN_HOMEPAGE_COUNT)
15
18
  return promotedRes;
16
- const remaining = MIN_COUNT - promoted.length;
17
- const latestRes = await apiClient.get(`${PRODUCT_ENDPOINTS.LIST}?filters=status%3D%3Dpublished${brandFilter}&sorts=-createdAt&pageSize=${remaining + promoted.length}`);
19
+ const remaining = MIN_HOMEPAGE_COUNT - promoted.length;
20
+ const latestRes = await apiClient.get(`${PRODUCT_ENDPOINTS.LIST}?${buildHomepageListingQuery({
21
+ brand: options?.filterByBrand,
22
+ sorts: sortBy(PRODUCT_FIELDS.CREATED_AT, "DESC"),
23
+ pageSize: remaining + promoted.length,
24
+ })}`);
18
25
  const latest = latestRes?.items ?? [];
19
26
  const existingIds = new Set(promoted.map((p) => p.id));
20
27
  const filler = latest
@@ -47,6 +47,37 @@ export declare const homepageSectionFirestoreSchema: z.ZodObject<{
47
47
  order: number;
48
48
  config: Record<string, JsonValue>;
49
49
  }>;
50
+ /**
51
+ * The create contract for a homepage section, shared by BOTH routes that can
52
+ * create one — `POST /api/admin/sections` (what the editor calls) and
53
+ * `POST /api/homepage-sections` (reachable by URL only).
54
+ *
55
+ * It exists because those two had drifted into being one validated path and
56
+ * one raw `{...body}` spread, and because the validated one's hand-written
57
+ * type list had fallen four values behind `SectionType` — so an admin could
58
+ * configure a Featured Bundles / Prize Draws / Event Raffles / Collection
59
+ * Cards section in full and get a 400 on save.
60
+ *
61
+ * `type` comes from `homepageSectionTypeSchema`, which is derived from the
62
+ * union, so that gap cannot reopen.
63
+ */
64
+ export declare const homepageSectionCreateSchema: z.ZodObject<{
65
+ type: z.ZodEnum<["welcome", "carousel", "stats", "trust-indicators", "categories", "brands", "products", "pre-orders", "auctions", "banner", "features", "reviews", "whatsapp-community", "faq", "blog-articles", "newsletter", "stores", "events", "social-feed", "custom-cards", "google-reviews", "featured-bundles", "prize-draws", "event-raffles", "collection-cards"]>;
66
+ enabled: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
67
+ order: z.ZodOptional<z.ZodNumber>;
68
+ config: z.ZodRecord<z.ZodString, z.ZodType<JsonValue, z.ZodTypeDef, JsonValue>>;
69
+ }, "strip", z.ZodTypeAny, {
70
+ type: "banner" | "stores" | "products" | "pre-orders" | "prize-draws" | "auctions" | "reviews" | "events" | "categories" | "brands" | "carousel" | "newsletter" | "features" | "stats" | "welcome" | "trust-indicators" | "whatsapp-community" | "faq" | "blog-articles" | "social-feed" | "custom-cards" | "google-reviews" | "featured-bundles" | "event-raffles" | "collection-cards";
71
+ enabled: boolean;
72
+ config: Record<string, JsonValue>;
73
+ order?: number | undefined;
74
+ }, {
75
+ type: "banner" | "stores" | "products" | "pre-orders" | "prize-draws" | "auctions" | "reviews" | "events" | "categories" | "brands" | "carousel" | "newsletter" | "features" | "stats" | "welcome" | "trust-indicators" | "whatsapp-community" | "faq" | "blog-articles" | "social-feed" | "custom-cards" | "google-reviews" | "featured-bundles" | "event-raffles" | "collection-cards";
76
+ config: Record<string, JsonValue>;
77
+ enabled?: boolean | undefined;
78
+ order?: number | undefined;
79
+ }>;
80
+ export type HomepageSectionCreateValues = z.infer<typeof homepageSectionCreateSchema>;
50
81
  export declare const carouselBackgroundSchema: z.ZodObject<{
51
82
  type: z.ZodEnum<["image", "video", "color", "gradient"]>;
52
83
  url: z.ZodOptional<z.ZodString>;
@@ -720,6 +751,7 @@ export declare const carouselSlideFirestoreSchema: z.ZodObject<{
720
751
  }, z.ZodTypeAny, "passthrough">;
721
752
  active: boolean;
722
753
  order: number;
754
+ createdBy: string;
723
755
  cards: {
724
756
  id: string;
725
757
  background: {
@@ -762,7 +794,6 @@ export declare const carouselSlideFirestoreSchema: z.ZodObject<{
762
794
  isButtonOnly?: boolean | undefined;
763
795
  gridCol?: 3 | 1 | 2 | undefined;
764
796
  }[];
765
- createdBy: string;
766
797
  link?: {
767
798
  url: string;
768
799
  openInNewTab: boolean;
@@ -829,6 +860,7 @@ export declare const carouselSlideFirestoreSchema: z.ZodObject<{
829
860
  }, z.ZodTypeAny, "passthrough">;
830
861
  active: boolean;
831
862
  order: number;
863
+ createdBy: string;
832
864
  cards: {
833
865
  id: string;
834
866
  background: {
@@ -871,7 +903,6 @@ export declare const carouselSlideFirestoreSchema: z.ZodObject<{
871
903
  isButtonOnly?: boolean | undefined;
872
904
  gridCol?: 3 | 1 | 2 | undefined;
873
905
  }[];
874
- createdBy: string;
875
906
  link?: {
876
907
  url: string;
877
908
  openInNewTab: boolean;
@@ -56,6 +56,30 @@ export const homepageSectionFirestoreSchema = z.object({
56
56
  config: z.record(z.string(), jsonValueSchema),
57
57
  ...auditTimestampsShape,
58
58
  });
59
+ /**
60
+ * The create contract for a homepage section, shared by BOTH routes that can
61
+ * create one — `POST /api/admin/sections` (what the editor calls) and
62
+ * `POST /api/homepage-sections` (reachable by URL only).
63
+ *
64
+ * It exists because those two had drifted into being one validated path and
65
+ * one raw `{...body}` spread, and because the validated one's hand-written
66
+ * type list had fallen four values behind `SectionType` — so an admin could
67
+ * configure a Featured Bundles / Prize Draws / Event Raffles / Collection
68
+ * Cards section in full and get a 400 on save.
69
+ *
70
+ * `type` comes from `homepageSectionTypeSchema`, which is derived from the
71
+ * union, so that gap cannot reopen.
72
+ */
73
+ export const homepageSectionCreateSchema = z.object({
74
+ type: homepageSectionTypeSchema,
75
+ enabled: z.boolean().optional().default(true),
76
+ order: z.number().int().optional(),
77
+ // Deliberately open. Every section type carries a different config shape,
78
+ // and a closed schema here would silently STRIP the builder's output for any
79
+ // type it did not enumerate — the `productBaseSchema` failure, one domain
80
+ // over.
81
+ config: z.record(z.string(), jsonValueSchema),
82
+ });
59
83
  export const carouselBackgroundSchema = z.object({
60
84
  type: z.enum(["image", "video", "color", "gradient"]),
61
85
  url: z.string().optional(),