@mohasinac/appkit 4.9.5 → 4.11.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 (395) hide show
  1. package/dist/_internal/client/features/layout/DashboardLayoutClient.d.ts +6 -1
  2. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +4 -1
  3. package/dist/_internal/client/features/lottery/LotteryPullForm.d.ts +1 -1
  4. package/dist/_internal/client/features/lottery/LotteryPullForm.js +2 -2
  5. package/dist/_internal/server/features/admin/daily-digest-actions.d.ts +18 -0
  6. package/dist/_internal/server/features/admin/daily-digest-actions.js +37 -0
  7. package/dist/_internal/server/features/auctions/actions.js +3 -2
  8. package/dist/_internal/server/features/auctions/service.d.ts +4 -3
  9. package/dist/_internal/server/features/auctions/service.js +6 -6
  10. package/dist/_internal/server/features/audit-log/actions.d.ts +25 -0
  11. package/dist/_internal/server/features/audit-log/actions.js +38 -0
  12. package/dist/_internal/server/features/brands/actions.js +0 -2
  13. package/dist/_internal/server/features/brands/og.d.ts +4 -1
  14. package/dist/_internal/server/features/brands/og.js +1 -1
  15. package/dist/_internal/server/features/bundles/data.d.ts +9 -0
  16. package/dist/_internal/server/features/bundles/data.js +14 -0
  17. package/dist/_internal/server/features/bundles/index.d.ts +1 -1
  18. package/dist/_internal/server/features/bundles/index.js +1 -1
  19. package/dist/_internal/server/features/catalogue/og.d.ts +20 -0
  20. package/dist/_internal/server/features/catalogue/og.js +27 -0
  21. package/dist/_internal/server/features/grouped/data.d.ts +16 -0
  22. package/dist/_internal/server/features/grouped/data.js +50 -1
  23. package/dist/_internal/server/features/grouped/index.d.ts +1 -1
  24. package/dist/_internal/server/features/grouped/index.js +1 -1
  25. package/dist/_internal/server/features/orders/actions.js +9 -0
  26. package/dist/_internal/server/features/orders/adapters.js +25 -0
  27. package/dist/_internal/server/features/products/data.d.ts +23 -0
  28. package/dist/_internal/server/features/products/data.js +159 -0
  29. package/dist/_internal/server/features/products/index.d.ts +1 -1
  30. package/dist/_internal/server/features/products/index.js +1 -1
  31. package/dist/_internal/server/functions/scheduled.d.ts +3 -1
  32. package/dist/_internal/server/functions/scheduled.js +17 -1
  33. package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +40 -0
  34. package/dist/_internal/server/jobs/core/dailyStatusDigest.js +164 -0
  35. package/dist/_internal/server/jobs/core/hardBanCascade.js +11 -0
  36. package/dist/_internal/server/jobs/core/testerSandboxCleanup.d.ts +1 -0
  37. package/dist/_internal/server/jobs/core/testerSandboxCleanup.js +4 -1
  38. package/dist/_internal/server/jobs/core/testerSandboxRefresh.d.ts +12 -0
  39. package/dist/_internal/server/jobs/core/testerSandboxRefresh.js +85 -0
  40. package/dist/_internal/server/jobs/core/whatsappNotify.js +16 -0
  41. package/dist/_internal/server/jobs/handlers/dailyStatusDigest.d.ts +2 -0
  42. package/dist/_internal/server/jobs/handlers/dailyStatusDigest.js +4 -0
  43. package/dist/_internal/server/jobs/handlers/index.d.ts +2 -0
  44. package/dist/_internal/server/jobs/handlers/index.js +3 -0
  45. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.d.ts +2 -0
  46. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.js +2 -0
  47. package/dist/_internal/server/notifications/channel-health.d.ts +27 -0
  48. package/dist/_internal/server/notifications/channel-health.js +101 -0
  49. package/dist/_internal/shared/features/auctions/config.d.ts +20 -0
  50. package/dist/_internal/shared/features/auctions/config.js +31 -1
  51. package/dist/_internal/shared/features/brands/schema.d.ts +0 -6
  52. package/dist/_internal/shared/features/brands/schema.js +0 -1
  53. package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +7 -0
  54. package/dist/_internal/shared/features/categories/bundle-schemas.js +3 -0
  55. package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
  56. package/dist/_internal/shared/listing-types/art/config.d.ts +1 -1
  57. package/dist/_internal/shared/listing-types/art/config.js +1 -1
  58. package/dist/_internal/shared/listing-types/classified/config.d.ts +1 -1
  59. package/dist/_internal/shared/listing-types/classified/config.js +1 -1
  60. package/dist/_internal/shared/listing-types/digital-code/config.d.ts +1 -1
  61. package/dist/_internal/shared/listing-types/digital-code/config.js +1 -1
  62. package/dist/_internal/shared/listing-types/live/config.d.ts +1 -1
  63. package/dist/_internal/shared/listing-types/live/config.js +1 -1
  64. package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +1 -1
  65. package/dist/_internal/shared/listing-types/prize-draw/config.js +1 -1
  66. package/dist/_internal/shared/listing-types/stickers/config.d.ts +1 -1
  67. package/dist/_internal/shared/listing-types/stickers/config.js +1 -1
  68. package/dist/client.d.ts +21 -12
  69. package/dist/client.js +14 -7
  70. package/dist/constants/api-endpoints.d.ts +9 -9
  71. package/dist/constants/api-endpoints.js +3 -3
  72. package/dist/contracts/client-auth.d.ts +3 -7
  73. package/dist/contracts/email.d.ts +1 -0
  74. package/dist/features/account/components/AddressForm.js +24 -2
  75. package/dist/features/account/components/BecomeSellerView.d.ts +1 -2
  76. package/dist/features/account/components/BecomeSellerView.js +1 -1
  77. package/dist/features/account/components/NotificationBell.js +1 -1
  78. package/dist/features/account/components/UserBidsView.d.ts +1 -0
  79. package/dist/features/account/components/UserBidsView.js +47 -0
  80. package/dist/features/account/components/UserOrdersView.d.ts +4 -11
  81. package/dist/features/account/components/UserOrdersView.js +54 -4
  82. package/dist/features/account/components/UserReturnsView.d.ts +4 -9
  83. package/dist/features/account/components/UserReturnsView.js +37 -3
  84. package/dist/features/account/components/index.d.ts +3 -2
  85. package/dist/features/account/components/index.js +1 -0
  86. package/dist/features/admin/actions/admin-actions.js +22 -0
  87. package/dist/features/admin/actions/admin-coupon-actions.js +10 -0
  88. package/dist/features/admin/actions/notification-actions.js +4 -3
  89. package/dist/features/admin/components/AdminAdsView.d.ts +2 -3
  90. package/dist/features/admin/components/AdminAdsView.js +86 -89
  91. package/dist/features/admin/components/AdminAllEventEntriesView.js +18 -3
  92. package/dist/features/admin/components/AdminAuditLogView.d.ts +11 -0
  93. package/dist/features/admin/components/AdminAuditLogView.js +95 -0
  94. package/dist/features/admin/components/AdminBlogEditorView.js +37 -3
  95. package/dist/features/admin/components/AdminBrandEditorView.js +10 -6
  96. package/dist/features/admin/components/AdminBundleEditorView.js +18 -2
  97. package/dist/features/admin/components/AdminCarouselEditorView.js +2 -2
  98. package/dist/features/admin/components/AdminCarouselGroupEditorView.js +2 -2
  99. package/dist/features/admin/components/AdminCartsView.js +34 -4
  100. package/dist/features/admin/components/AdminCategoryEditorView.js +5 -4
  101. package/dist/features/admin/components/AdminCouponEditorView.js +2 -2
  102. package/dist/features/admin/components/AdminFaqEditorView.js +2 -2
  103. package/dist/features/admin/components/AdminHistoryView.js +11 -1
  104. package/dist/features/admin/components/AdminNotificationsView.js +27 -1
  105. package/dist/features/admin/components/AdminOrderEditorView.d.ts +10 -1
  106. package/dist/features/admin/components/AdminOrderEditorView.js +4 -3
  107. package/dist/features/admin/components/AdminOrdersView.js +92 -24
  108. package/dist/features/admin/components/AdminPayoutMarkPaidModal.d.ts +7 -0
  109. package/dist/features/admin/components/AdminPayoutMarkPaidModal.js +47 -0
  110. package/dist/features/admin/components/AdminPayoutsView.js +15 -31
  111. package/dist/features/admin/components/AdminProductEditorView.js +26 -3
  112. package/dist/features/admin/components/AdminSiteSettingsView.js +31 -4
  113. package/dist/features/admin/components/AdminStoreAddressesView.js +22 -2
  114. package/dist/features/admin/components/AdminStoresView.js +7 -0
  115. package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +2 -2
  116. package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +2 -2
  117. package/dist/features/admin/components/AdminUserEditorView.d.ts +2 -2
  118. package/dist/features/admin/components/AdminUserEditorView.js +4 -2
  119. package/dist/features/admin/components/AdminUsersView.js +1 -1
  120. package/dist/features/admin/components/AdminWishlistsView.js +14 -1
  121. package/dist/features/admin/components/DataListingView.d.ts +2 -2
  122. package/dist/features/admin/components/ViewAuditLogEntryModal.d.ts +19 -0
  123. package/dist/features/admin/components/ViewAuditLogEntryModal.js +22 -0
  124. package/dist/features/admin/components/ViewNotificationModal.d.ts +21 -0
  125. package/dist/features/admin/components/ViewNotificationModal.js +15 -0
  126. package/dist/features/admin/components/analytics/AdminPageViewsReportView.d.ts +4 -7
  127. package/dist/features/admin/components/analytics/AdminPageViewsReportView.js +56 -36
  128. package/dist/features/admin/components/index.d.ts +8 -1
  129. package/dist/features/admin/components/index.js +4 -0
  130. package/dist/features/admin/constants/filter-tabs.d.ts +49 -0
  131. package/dist/features/admin/constants/filter-tabs.js +27 -0
  132. package/dist/features/admin/hooks/useAdminListing.d.ts +6 -0
  133. package/dist/features/admin/hooks/useAdminListing.js +3 -1
  134. package/dist/features/admin/hooks/useAdminListingData.d.ts +9 -1
  135. package/dist/features/admin/hooks/useAdminListingData.js +9 -2
  136. package/dist/features/admin/repository/site-settings.repository.d.ts +5 -0
  137. package/dist/features/admin/schemas/firestore.d.ts +21 -0
  138. package/dist/features/admin/schemas/firestore.js +6 -0
  139. package/dist/features/analytics/types.d.ts +1 -1
  140. package/dist/features/analytics/types.js +8 -0
  141. package/dist/features/auctions/actions/bid-actions.js +4 -1
  142. package/dist/features/auctions/components/AuctionBottomActions.d.ts +2 -1
  143. package/dist/features/auctions/components/AuctionBottomActions.js +14 -1
  144. package/dist/features/auctions/components/AuctionDetailPageView.js +21 -9
  145. package/dist/features/auctions/components/LiveMinIncrement.d.ts +18 -0
  146. package/dist/features/auctions/components/LiveMinIncrement.js +17 -0
  147. package/dist/features/auctions/components/PlaceBidFormClient.d.ts +5 -2
  148. package/dist/features/auctions/components/PlaceBidFormClient.js +7 -3
  149. package/dist/features/auctions/schemas/index.d.ts +5 -0
  150. package/dist/features/audit-log/repository/audit-log.repository.d.ts +45 -0
  151. package/dist/features/audit-log/repository/audit-log.repository.js +30 -0
  152. package/dist/features/audit-log/schemas/firestore.d.ts +59 -0
  153. package/dist/features/audit-log/schemas/firestore.js +35 -0
  154. package/dist/features/auth/actions/index.d.ts +0 -1
  155. package/dist/features/auth/actions/index.js +0 -1
  156. package/dist/features/auth/hooks/useAuth.d.ts +8 -35
  157. package/dist/features/auth/hooks/useAuth.js +21 -37
  158. package/dist/features/auth/permissions/constants.d.ts +1 -1
  159. package/dist/features/auth/permissions/constants.js +2 -0
  160. package/dist/features/blog/schemas/index.d.ts +32 -0
  161. package/dist/features/catalogue/components/AdminCatalogueApprovalsView.js +31 -3
  162. package/dist/features/catalogue/components/CatalogueItemEditorView.js +2 -1
  163. package/dist/features/catalogue/components/PublicCatalogueItemDetailView.d.ts +11 -0
  164. package/dist/features/catalogue/components/PublicCatalogueItemDetailView.js +33 -0
  165. package/dist/features/catalogue/components/PublicCatalogueView.js +2 -1
  166. package/dist/features/catalogue/index.d.ts +2 -0
  167. package/dist/features/catalogue/index.js +1 -0
  168. package/dist/features/categories/components/BrandDetailPageView.js +14 -12
  169. package/dist/features/categories/components/BundleDetailView.d.ts +3 -1
  170. package/dist/features/categories/components/BundleDetailView.js +3 -2
  171. package/dist/features/categories/components/CategoryDetailPageView.js +7 -3
  172. package/dist/features/categories/components/CategoryHighlightsAndFaqSection.d.ts +14 -0
  173. package/dist/features/categories/components/CategoryHighlightsAndFaqSection.js +22 -0
  174. package/dist/features/categories/components/CategoryProductsView.d.ts +1 -5
  175. package/dist/features/categories/components/CategoryProductsView.js +1 -1
  176. package/dist/features/categories/components/CategorySelectorCreate.js +16 -2
  177. package/dist/features/categories/schemas/firestore.d.ts +19 -2
  178. package/dist/features/categories/schemas/index.d.ts +24 -3
  179. package/dist/features/categories/schemas/index.js +3 -1
  180. package/dist/features/categories/types/index.d.ts +7 -0
  181. package/dist/features/checkout/actions/checkout-value-otp-actions.d.ts +17 -3
  182. package/dist/features/checkout/actions/checkout-value-otp-actions.js +101 -22
  183. package/dist/features/classified/components/ClassifiedContactSellerPanel.d.ts +12 -0
  184. package/dist/features/classified/components/ClassifiedContactSellerPanel.js +49 -0
  185. package/dist/features/classified/components/ClassifiedDetailPageView.d.ts +7 -0
  186. package/dist/features/classified/components/ClassifiedDetailPageView.js +69 -0
  187. package/dist/features/contact/components/ContactForm.js +17 -4
  188. package/dist/features/contact/components/ContactPageView.js +8 -2
  189. package/dist/features/contact/email.d.ts +1 -0
  190. package/dist/features/contact/email.js +3 -0
  191. package/dist/features/digital-codes/components/DigitalCodeDetailPageView.d.ts +19 -0
  192. package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +79 -0
  193. package/dist/features/events/components/AdminEventEditorView.js +54 -2
  194. package/dist/features/events/components/AdminEventEntriesView.d.ts +2 -16
  195. package/dist/features/events/components/AdminEventEntriesView.js +56 -89
  196. package/dist/features/events/components/EventFormDrawer.js +5 -1
  197. package/dist/features/events/components/EventRaffleEntryForm.d.ts +1 -3
  198. package/dist/features/events/components/EventRaffleEntryForm.js +1 -1
  199. package/dist/features/events/schemas/index.d.ts +22 -0
  200. package/dist/features/grouped/components/GroupedListingsCarousel.d.ts +13 -0
  201. package/dist/features/grouped/components/GroupedListingsCarousel.js +31 -0
  202. package/dist/features/grouped/repository/grouped-listings.repository.d.ts +12 -0
  203. package/dist/features/grouped/repository/grouped-listings.repository.js +34 -0
  204. package/dist/features/homepage/components/CharacterHotspotForm.js +202 -187
  205. package/dist/features/homepage/components/SectionCarousel.d.ts +1 -7
  206. package/dist/features/homepage/components/SectionCarousel.js +1 -1
  207. package/dist/features/layout/BottomActions.js +4 -3
  208. package/dist/features/layout/BottomActionsContext.d.ts +10 -0
  209. package/dist/features/layout/BottomActionsContext.js +5 -1
  210. package/dist/features/layout/TitleBarLayout.d.ts +1 -1
  211. package/dist/features/layout/TitleBarLayout.js +3 -3
  212. package/dist/features/layout/hooks/useBottomActions.d.ts +2 -0
  213. package/dist/features/layout/hooks/useBottomActions.js +4 -1
  214. package/dist/features/live/components/LiveItemDetailPageView.d.ts +9 -0
  215. package/dist/features/live/components/LiveItemDetailPageView.js +74 -0
  216. package/dist/features/media/MediaImage.js +39 -3
  217. package/dist/features/media/MediaVideo.js +17 -1
  218. package/dist/features/media/types/index.d.ts +10 -0
  219. package/dist/features/media/types/index.js +1 -0
  220. package/dist/features/media/upload/MediaUploadField.d.ts +7 -1
  221. package/dist/features/media/upload/MediaUploadField.js +11 -7
  222. package/dist/features/media/upload/video-poster.d.ts +2 -0
  223. package/dist/features/media/upload/video-poster.js +16 -1
  224. package/dist/features/media/upload/video-poster.test.js +1 -1
  225. package/dist/features/orders/components/OrderStatusTimeline.d.ts +12 -0
  226. package/dist/features/orders/components/OrderStatusTimeline.js +55 -0
  227. package/dist/features/orders/components/index.d.ts +2 -0
  228. package/dist/features/orders/components/index.js +1 -0
  229. package/dist/features/orders/constants/payment-window.d.ts +25 -0
  230. package/dist/features/orders/constants/payment-window.js +25 -0
  231. package/dist/features/orders/repository/orders.repository.d.ts +32 -0
  232. package/dist/features/orders/repository/orders.repository.js +56 -0
  233. package/dist/features/orders/schemas/index.d.ts +24 -24
  234. package/dist/features/orders/types/index.d.ts +33 -0
  235. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +9 -1
  236. package/dist/features/pre-orders/schemas/index.d.ts +5 -0
  237. package/dist/features/products/components/BidHistory.js +9 -1
  238. package/dist/features/products/components/GroupSettingsPanel.js +25 -3
  239. package/dist/features/products/components/PrizeDrawDetailPageView.js +11 -1
  240. package/dist/features/products/components/PrizeDrawEntryActions.d.ts +1 -4
  241. package/dist/features/products/components/PrizeDrawEntryActions.js +1 -1
  242. package/dist/features/products/components/ProductDetailActions.d.ts +1 -2
  243. package/dist/features/products/components/ProductDetailActions.js +1 -1
  244. package/dist/features/products/components/ProductDetailPageView.js +11 -116
  245. package/dist/features/products/components/ProductGrid.js +15 -1
  246. package/dist/features/products/components/RelatedItemsSection.d.ts +16 -0
  247. package/dist/features/products/components/RelatedItemsSection.js +17 -0
  248. package/dist/features/products/constants/action-defs.d.ts +1 -0
  249. package/dist/features/products/constants/action-defs.js +1 -0
  250. package/dist/features/products/schemas/index.d.ts +5 -0
  251. package/dist/features/promotions/components/CouponsIndexListing.d.ts +1 -3
  252. package/dist/features/promotions/components/CouponsIndexListing.js +1 -1
  253. package/dist/features/search/components/SearchView.d.ts +1 -3
  254. package/dist/features/search/components/SearchView.js +1 -1
  255. package/dist/features/seller/components/QuickProductForm.js +2 -1
  256. package/dist/features/seller/components/SellerBidsView.js +66 -107
  257. package/dist/features/seller/components/SellerGoogleReviewsView.js +17 -1
  258. package/dist/features/seller/components/SellerOrdersView.d.ts +15 -3
  259. package/dist/features/seller/components/SellerOrdersView.js +134 -163
  260. package/dist/features/seller/components/SellerPayoutMethodsView.js +60 -48
  261. package/dist/features/seller/components/SellerPayoutSettingsView.js +69 -4
  262. package/dist/features/seller/components/SellerPayoutsView.d.ts +12 -0
  263. package/dist/features/seller/components/SellerPayoutsView.js +25 -5
  264. package/dist/features/seller/components/SellerProductShell.d.ts +10 -3
  265. package/dist/features/seller/components/SellerProductShell.js +90 -37
  266. package/dist/features/seller/components/SellerProductsFilterDrawer.d.ts +2 -7
  267. package/dist/features/seller/components/SellerProductsFilterDrawer.js +4 -4
  268. package/dist/features/seller/components/SellerProductsView.d.ts +2 -4
  269. package/dist/features/seller/components/SellerProductsView.js +131 -189
  270. package/dist/features/seller/components/SellerReviewsView.js +95 -133
  271. package/dist/features/seller/components/SellerShippingConfigsView.js +47 -67
  272. package/dist/features/seller/components/SellerShippingView.js +41 -4
  273. package/dist/features/seller/components/SellerStoreCategoriesView.js +51 -59
  274. package/dist/features/seller/components/SellerStorefrontView.d.ts +6 -1
  275. package/dist/features/seller/components/SellerStorefrontView.js +42 -5
  276. package/dist/features/seller/components/index.d.ts +2 -2
  277. package/dist/features/seller/components/index.js +2 -2
  278. package/dist/features/shell/FormShell.d.ts +24 -4
  279. package/dist/features/shell/FormShell.js +12 -6
  280. package/dist/features/shell/QuickFormDrawer.js +67 -12
  281. package/dist/features/shell/StepForm.d.ts +30 -1
  282. package/dist/features/shell/StepForm.js +47 -4
  283. package/dist/features/shell/index.d.ts +1 -1
  284. package/dist/features/shell/index.js +1 -1
  285. package/dist/features/shipments/components/AdminShipmentEditorView.js +2 -2
  286. package/dist/features/shipments/schemas/validation.d.ts +14 -4
  287. package/dist/features/tester/components/AdminTesterFeedbackListView.js +23 -2
  288. package/dist/features/tester/components/TesterChecklistStepRow.js +1 -1
  289. package/dist/features/tester/components/TesterHubView.js +3 -2
  290. package/dist/features/tester/seed-data/orders-tester-seed-data.js +9 -1
  291. package/dist/features/tester/seed-data/products-tester-seed-data.js +43 -32
  292. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +487 -18
  293. package/dist/index.d.ts +17 -3
  294. package/dist/index.js +23 -5
  295. package/dist/next/routing/route-map.d.ts +13 -0
  296. package/dist/next/routing/route-map.js +12 -0
  297. package/dist/providers/email-resend/provider.js +1 -0
  298. package/dist/providers/firebase-client/auth.d.ts +1 -0
  299. package/dist/providers/firebase-client/auth.js +7 -1
  300. package/dist/repositories/index.d.ts +1 -0
  301. package/dist/repositories/index.js +1 -0
  302. package/dist/schemas/registry.d.ts +61 -25
  303. package/dist/security/pii-mask.js +1 -1
  304. package/dist/seed/bids-seed-data.js +48 -3
  305. package/dist/seed/categories-seed-data.js +69 -0
  306. package/dist/seed/grouped-listings-seed-data.js +167 -0
  307. package/dist/seed/payouts-seed-data.js +4 -4
  308. package/dist/seed/products-art-seed-data.js +188 -5
  309. package/dist/seed/products-auctions-seed-data.js +226 -6
  310. package/dist/seed/products-classifieds-seed-data.js +255 -8
  311. package/dist/seed/products-digital-codes-seed-data.js +258 -19
  312. package/dist/seed/products-live-items-seed-data.js +143 -10
  313. package/dist/seed/products-preorders-seed-data.js +213 -8
  314. package/dist/seed/products-prize-draws-seed-data.js +198 -0
  315. package/dist/seed/products-standard-seed-data.js +234 -4
  316. package/dist/seed/products-stickers-seed-data.js +178 -5
  317. package/dist/seed/site-settings-seed-data.js +23 -30
  318. package/dist/seed/store-extensions-seed-data.js +2 -2
  319. package/dist/server-entry.d.ts +6 -2
  320. package/dist/server-entry.js +24 -3
  321. package/dist/server.d.ts +10 -3
  322. package/dist/server.js +11 -4
  323. package/dist/styles.css +29 -1
  324. package/dist/tailwind-utilities.css +1 -1
  325. package/dist/ui/components/Form.d.ts +11 -2
  326. package/dist/ui/components/Form.js +4 -3
  327. package/dist/ui/components/FormField.d.ts +3 -1
  328. package/dist/ui/components/FormField.js +22 -4
  329. package/dist/ui/components/ImageLightbox.js +37 -3
  330. package/dist/ui/components/ImageLightbox.style.css +28 -0
  331. package/dist/ui/components/ListingLayout.d.ts +1 -2
  332. package/dist/ui/components/ListingLayout.js +1 -1
  333. package/dist/ui/components/RecordDetailModal.d.ts +68 -0
  334. package/dist/ui/components/RecordDetailModal.js +8 -0
  335. package/dist/ui/components/SlottedListingView.js +9 -1
  336. package/dist/ui/forms/FormErrorSummary.d.ts +25 -0
  337. package/dist/ui/forms/FormErrorSummary.js +37 -0
  338. package/dist/ui/forms/FormShell.d.ts +37 -2
  339. package/dist/ui/forms/FormShell.js +37 -7
  340. package/dist/ui/forms/FormShell.style.css +17 -0
  341. package/dist/ui/forms/index.d.ts +2 -0
  342. package/dist/ui/forms/index.js +1 -0
  343. package/dist/ui/index.d.ts +4 -0
  344. package/dist/ui/index.js +5 -0
  345. package/dist/utils/media-url.d.ts +12 -1
  346. package/dist/utils/media-url.js +59 -1
  347. package/dist/validation/schemas.d.ts +4 -4
  348. package/package.json +1 -1
  349. package/dist/_internal/client/features/classified/ClassifiedDetailView.d.ts +0 -9
  350. package/dist/_internal/client/features/classified/ClassifiedDetailView.js +0 -55
  351. package/dist/_internal/client/features/digital-code/DigitalCodeDetailView.d.ts +0 -18
  352. package/dist/_internal/client/features/digital-code/DigitalCodeDetailView.js +0 -21
  353. package/dist/_internal/client/features/live/LiveItemDetailView.d.ts +0 -9
  354. package/dist/_internal/client/features/live/LiveItemDetailView.js +0 -25
  355. package/dist/_internal/server/jobs/core/prizeRevealClose.d.ts +0 -2
  356. package/dist/_internal/server/jobs/core/prizeRevealClose.js +0 -28
  357. package/dist/_internal/server/jobs/core/prizeRevealExpiry.d.ts +0 -2
  358. package/dist/_internal/server/jobs/core/prizeRevealExpiry.js +0 -61
  359. package/dist/_internal/server/jobs/core/prizeRevealOpen.d.ts +0 -2
  360. package/dist/_internal/server/jobs/core/prizeRevealOpen.js +0 -68
  361. package/dist/_internal/server/jobs/core/prizeRevealReminder.d.ts +0 -2
  362. package/dist/_internal/server/jobs/core/prizeRevealReminder.js +0 -49
  363. package/dist/_internal/server/jobs/handlers/prizeRevealClose.d.ts +0 -2
  364. package/dist/_internal/server/jobs/handlers/prizeRevealClose.js +0 -2
  365. package/dist/_internal/server/jobs/handlers/prizeRevealExpiry.d.ts +0 -2
  366. package/dist/_internal/server/jobs/handlers/prizeRevealExpiry.js +0 -2
  367. package/dist/_internal/server/jobs/handlers/prizeRevealOpen.d.ts +0 -2
  368. package/dist/_internal/server/jobs/handlers/prizeRevealOpen.js +0 -2
  369. package/dist/_internal/server/jobs/handlers/prizeRevealReminder.d.ts +0 -2
  370. package/dist/_internal/server/jobs/handlers/prizeRevealReminder.js +0 -2
  371. package/dist/features/auth/consent-otp.d.ts +0 -57
  372. package/dist/features/auth/consent-otp.js +0 -127
  373. package/dist/features/cart/components/CheckoutOtpModal.d.ts +0 -15
  374. package/dist/features/cart/components/CheckoutOtpModal.js +0 -12
  375. package/dist/features/checkout/actions/checkout-actions.d.ts +0 -31
  376. package/dist/features/checkout/actions/checkout-actions.js +0 -124
  377. package/dist/features/classified/components/ClassifiedIndexListing.d.ts +0 -5
  378. package/dist/features/classified/components/ClassifiedIndexListing.js +0 -123
  379. package/dist/features/classified/components/ClassifiedListView.d.ts +0 -6
  380. package/dist/features/classified/components/ClassifiedListView.js +0 -44
  381. package/dist/features/digital-codes/components/DigitalCodesIndexListing.d.ts +0 -5
  382. package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +0 -114
  383. package/dist/features/digital-codes/components/DigitalCodesListView.d.ts +0 -6
  384. package/dist/features/digital-codes/components/DigitalCodesListView.js +0 -38
  385. package/dist/features/live/components/LiveItemsIndexListing.d.ts +0 -5
  386. package/dist/features/live/components/LiveItemsIndexListing.js +0 -115
  387. package/dist/features/live/components/LiveItemsListView.d.ts +0 -6
  388. package/dist/features/live/components/LiveItemsListView.js +0 -44
  389. package/dist/features/seller/components/SellerTemplatesView.d.ts +0 -12
  390. package/dist/features/seller/components/SellerTemplatesView.js +0 -276
  391. package/dist/react/hooks/useVisibleItems.d.ts +0 -37
  392. package/dist/react/hooks/useVisibleItems.js +0 -59
  393. package/dist/ui/components/TabStrip.d.ts +0 -34
  394. package/dist/ui/components/TabStrip.js +0 -56
  395. package/dist/ui/components/TabStrip.style.css +0 -97
@@ -1,6 +1,5 @@
1
1
  export interface ProductDetailActionsProps {
2
2
  productId: string;
3
- productSlug: string;
4
3
  productTitle: string;
5
4
  productImage?: string;
6
5
  price?: number;
@@ -22,4 +21,4 @@ export interface ProductDetailActionsProps {
22
21
  * to the server APIs with guest-fallback. Replaces the previously-unwired
23
22
  * placeholder buttons inside ProductDetailPageView.
24
23
  */
25
- export declare function ProductDetailActions({ productId, productSlug: _productSlug, productTitle, productImage, price, currency, storeId, storeName, inStock, variant, }: ProductDetailActionsProps): import("react").JSX.Element;
24
+ export declare function ProductDetailActions({ productId, productTitle, productImage, price, currency, storeId, storeName, inStock, variant, }: ProductDetailActionsProps): import("react").JSX.Element;
@@ -19,7 +19,7 @@ import { normalizeError } from "../../../errors/normalize";
19
19
  * to the server APIs with guest-fallback. Replaces the previously-unwired
20
20
  * placeholder buttons inside ProductDetailPageView.
21
21
  */
22
- export function ProductDetailActions({ productId, productSlug: _productSlug, productTitle, productImage, price, currency, storeId, storeName, inStock, variant = "desktop", }) {
22
+ export function ProductDetailActions({ productId, productTitle, productImage, price, currency, storeId, storeName, inStock, variant = "desktop", }) {
23
23
  const router = useRouter();
24
24
  const { showToast } = useToast();
25
25
  const { requireAuth, modalOpen, modalMessage, closeModal } = useAuthGate();
@@ -1,6 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import Link from "next/link";
3
- import { SIEVE_OP, sieveAnd, sieveFilter, sortBy } from "@mohasinac/appkit";
4
3
  import { productRepository, reviewRepository } from "../../../repositories";
5
4
  const __P = {
6
5
  p3: "p-[var(--appkit-space-3)]",
@@ -32,59 +31,18 @@ import { ProductGalleryClient } from "./ProductGalleryClient";
32
31
  import { ProductTabsShell } from "./ProductTabsShell";
33
32
  import { ProductFeatureBadges } from "./ProductFeatureBadges";
34
33
  import { FeatureBadgeList } from "./FeatureBadge";
35
- import { RelatedProductsCarousel } from "./RelatedProductsCarousel";
36
34
  import { ShareButton } from "./ShareButton";
37
35
  import { CustomSectionTabContent } from "./CustomSectionTabContent";
38
36
  import { SublistingCarouselSection } from "./SublistingCarouselSection";
39
37
  import { ShowGroupSection } from "./ShowGroupSection";
40
38
  import { HistoryTracker } from "../../history/components/HistoryTracker";
39
+ import { RelatedItemsSection } from "./RelatedItemsSection";
40
+ import { computeRelatedItems, toReview } from "../../../_internal/server/features/products/data";
41
+ import { GroupedListingsCarousel } from "../../grouped/components/GroupedListingsCarousel";
42
+ import { getGroupsWithItemsForProduct } from "../../../_internal/server/features/grouped/data";
41
43
  // ---------------------------------------------------------------------------
42
44
  // Helpers
43
45
  // ---------------------------------------------------------------------------
44
- function toProductItem(doc) {
45
- return {
46
- id: String(doc.id ?? ""),
47
- title: String(doc.title ?? doc.name ?? ""),
48
- price: typeof doc.price === "number" ? doc.price : 0,
49
- originalPrice: typeof doc.originalPrice === "number" ? doc.originalPrice : undefined,
50
- mainImage: Array.isArray(doc.images)
51
- ? doc.images[0]
52
- : typeof doc.mainImage === "string"
53
- ? doc.mainImage
54
- : undefined,
55
- status: doc.status ?? "published",
56
- slug: typeof doc.slug === "string" ? doc.slug : undefined,
57
- storeName: typeof doc.storeName === "string" ? doc.storeName : undefined,
58
- rating: typeof doc.rating === "number" ? doc.rating : undefined,
59
- reviewCount: typeof doc.reviewCount === "number" ? doc.reviewCount : undefined,
60
- };
61
- }
62
- function toReview(doc) {
63
- const images = Array.isArray(doc.images) ? doc.images : undefined;
64
- const createdAt = doc.createdAt instanceof Date
65
- ? doc.createdAt.toISOString()
66
- : typeof doc.createdAt === "string"
67
- ? doc.createdAt
68
- : undefined;
69
- const rawRating = typeof doc.rating === "number" ? doc.rating : 3;
70
- const rating = Math.min(5, Math.max(1, Math.round(rawRating)));
71
- return {
72
- id: String(doc.id ?? ""),
73
- productId: String(doc.productId ?? ""),
74
- userId: String(doc.userId ?? ""),
75
- userName: String(doc.userName ?? "Anonymous"),
76
- userAvatar: typeof doc.userAvatar === "string" ? doc.userAvatar : undefined,
77
- rating,
78
- title: typeof doc.title === "string" ? doc.title : undefined,
79
- comment: typeof doc.comment === "string" ? doc.comment : undefined,
80
- images,
81
- status: doc.status ?? "approved",
82
- helpfulCount: typeof doc.helpfulCount === "number" ? doc.helpfulCount : undefined,
83
- verified: doc.verified === true,
84
- featured: doc.featured === true,
85
- createdAt,
86
- };
87
- }
88
46
  function toDescriptionHtml(raw) {
89
47
  if (!raw)
90
48
  return "";
@@ -206,74 +164,14 @@ export async function ProductDetailPageView({ slug, initialProduct, renderOfferA
206
164
  const isGroupParent = p.isGroupParent === true;
207
165
  const groupTitle = typeof p.groupTitle === "string" ? p.groupTitle : undefined;
208
166
  const storeId = typeof p.storeId === "string" ? p.storeId : null;
209
- // -- Fetch reviews + 4 related-listing signals in parallel ------------------
210
- const [reviewDocs, sameCategoryDocs, sameBrandDocs, tagOverlapDocs, sameStoreDocs] = await Promise.all([
211
- reviewRepository
212
- .findApprovedByProduct(product.id)
213
- .catch(() => []),
214
- primaryCategorySlug
215
- ? productRepository.findByCategory(primaryCategorySlug).catch(() => [])
216
- : Promise.resolve([]),
217
- brand
218
- ? productRepository
219
- .list({
220
- filters: sieveAnd(sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("brand", SIEVE_OP.EQ, brand)),
221
- sorts: sortBy("createdAt", "DESC"),
222
- page: 1,
223
- pageSize: 9,
224
- })
225
- .then((r) => r.items)
226
- .catch(() => [])
227
- : Promise.resolve([]),
228
- tags.length > 0
229
- ? productRepository.findByTagsOverlap(tags, 9).catch(() => [])
230
- : Promise.resolve([]),
231
- storeId
232
- ? productRepository
233
- .list({
234
- filters: sieveAnd(sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("storeId", SIEVE_OP.EQ, storeId)),
235
- sorts: sortBy("createdAt", "DESC"),
236
- page: 1,
237
- pageSize: 9,
238
- })
239
- .then((r) => r.items)
240
- .catch(() => [])
241
- : Promise.resolve([]),
167
+ // -- Fetch reviews + the shared 4-signal related-items computation + grouped listings in parallel --
168
+ const [reviewDocs, related, groups] = await Promise.all([
169
+ reviewRepository.findApprovedByProduct(product.id).catch(() => []),
170
+ computeRelatedItems(product),
171
+ getGroupsWithItemsForProduct(product.id),
242
172
  ]);
243
173
  const reviews = reviewDocs.map(toReview);
244
- const _now = new Date();
245
- const currentProductId = product.id;
246
- function toRelatedItems(docs) {
247
- return docs
248
- .filter((r) => {
249
- if (r.id === currentProductId)
250
- return false;
251
- const s = r.status;
252
- if (s && ["sold", "out_of_stock", "archived", "discontinued", "draft"].includes(s))
253
- return false;
254
- if (r.isSold === true)
255
- return false;
256
- if (r.availableQuantity === 0)
257
- return false;
258
- if (r.listingType === "auction" && r.auctionEndDate) {
259
- const end = r.auctionEndDate;
260
- const endDate = typeof end.toDate === "function"
261
- ? end.toDate()
262
- : end instanceof Date ? end : new Date(String(end));
263
- if (endDate <= _now)
264
- return false;
265
- }
266
- if (r.listingType === "prize-draw" && r.prizeRevealStatus === "closed")
267
- return false;
268
- return true;
269
- })
270
- .slice(0, 8)
271
- .map(toProductItem);
272
- }
273
- const relatedItems = toRelatedItems(sameCategoryDocs);
274
- const relatedByBrand = toRelatedItems(sameBrandDocs);
275
- const relatedByTags = toRelatedItems(tagOverlapDocs);
276
- const relatedByStore = toRelatedItems(sameStoreDocs);
174
+ const { relatedItems, relatedByBrand, relatedByTags, relatedByStore } = related;
277
175
  return (_jsxs(Main, { children: [_jsx(HistoryTracker, { productId: product.id, productType: "product", snapshot: {
278
176
  title: product.title,
279
177
  thumb: product.mainImage ?? product.images?.[0],
@@ -339,10 +237,7 @@ export async function ProductDetailPageView({ slug, initialProduct, renderOfferA
339
237
  content: _jsx(CustomSectionTabContent, { section: s }),
340
238
  })) })), renderBundleSection: bundleMemberships.length > 0
341
239
  ? () => (_jsxs(Div, { className: CLS_BUNDLE_BOX, children: [_jsxs(Row, { className: "mb-3", align: "center", gap: "sm", children: [_jsx(Span, { size: "base", className: CLS_BUNDLE_ICON, "aria-hidden": "true", children: "\uD83D\uDCE6" }), _jsxs(Text, { className: CLS_BUNDLE_TITLE, children: ["Part of ", bundleMemberships.length === 1 ? "a bundle" : `${bundleMemberships.length} bundles`] })] }), _jsx(Stack, { gap: "3", children: bundleMemberships.map((b) => (_jsxs(Div, { className: CLS_BUNDLE_ROW, children: [_jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { className: CLS_BUNDLE_LABEL, children: "Included in bundle" }), _jsx(Text, { className: "truncate", color: "primary", size: "sm", weight: "semibold", children: b.title })] }), _jsx(Link, { href: String(ROUTES.PUBLIC.BUNDLE_DETAIL(b.id)), className: CLS_BUNDLE_CTA, children: "View Bundle \u2192" })] }, b.id))) })] }))
342
- : undefined, renderRelated: () => relatedItems.length > 0 ||
343
- relatedByBrand.length > 0 ||
344
- relatedByTags.length > 0 ||
345
- relatedByStore.length > 0 ? (_jsxs(Stack, { gap: "xl", children: [relatedItems.length > 0 && (_jsx(RelatedProductsCarousel, { items: relatedItems, title: categoryName || category ? `More in ${categoryName || category}` : "More in this category" })), relatedByBrand.length > 0 && (_jsx(RelatedProductsCarousel, { items: relatedByBrand, title: brand ? `More by ${brand}` : "More by this brand" })), relatedByTags.length > 0 && (_jsx(RelatedProductsCarousel, { items: relatedByTags, title: "You might also like" })), relatedByStore.length > 0 && (_jsx(RelatedProductsCarousel, { items: relatedByStore, title: storeName ? `More from ${storeName}` : "More from this seller" }))] })) : null }), renderPrimaryActions
240
+ : undefined, 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 || undefined, storeLabel: storeName || undefined })] })) }), renderPrimaryActions
346
241
  ? renderPrimaryActions({
347
242
  productId: product.id,
348
243
  productSlug: product.slug ?? slug,
@@ -2,6 +2,8 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import React from "react";
4
4
  import Link from "next/link";
5
+ import { useRouter } from "next/navigation";
6
+ import { ROUTES } from "../../../next";
5
7
  import { BaseListingCard, Button, Div, Grid, PriceDisplay, Row, Span, Stack, Text } from "../../../ui";
6
8
  import { MediaImage } from "../../media/MediaImage";
7
9
  import { formatCurrency } from "../../../utils/number.formatter";
@@ -37,6 +39,7 @@ export function ProductCard({ product, href, onClick, onAddToWishlist, isWishlis
37
39
  ? Math.round(((product.originalPrice - product.price) / product.originalPrice) *
38
40
  100)
39
41
  : null;
42
+ const router = useRouter();
40
43
  const listingPlugin = pluginFor(normalizeListingType(product));
41
44
  const typeBadge = listingPlugin.badge
42
45
  ? { label: listingPlugin.badge.label, cls: listingPlugin.badge.className }
@@ -86,7 +89,18 @@ export function ProductCard({ product, href, onClick, onAddToWishlist, isWishlis
86
89
  const MAX_CHIPS = 3;
87
90
  const visible = categories.slice(0, MAX_CHIPS);
88
91
  const overflow = Math.max(0, categories.length - MAX_CHIPS);
89
- return (_jsxs(Row, { className: "mt-1", gap: "xs", wrap: true, children: [visible.map((name) => (_jsxs(Span, { padding: "pill-2xs", layout: "inline-flex", className: "gap-[0.125rem] text-[10px]", rounded: "full", surface: "subtle", color: "muted", children: [_jsx("svg", { className: "h-2.5 w-2.5 flex-shrink-0", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 7a2 2 0 012-2h14a2 2 0 012 2v10a2 2 0 01-2 2H5a2 2 0 01-2-2V7z" }) }), name] }, name))), overflow > 0 && (_jsxs(Span, { padding: "pill-2xs", layout: "inline-flex", weight: "medium", className: "text-[10px]", rounded: "full", surface: "subtle", color: "muted", title: categories.slice(MAX_CHIPS).join(", "), children: ["+", overflow] })), product.brand && (_jsxs(Span, { padding: "pill-2xs", layout: "inline-flex", gap: "2xs", className: "text-[10px]", rounded: "full", surface: "subtle", color: "muted", children: [_jsx("svg", { className: "h-2.5 w-2.5 flex-shrink-0", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" }) }), product.brand] }))] }));
92
+ return (_jsxs(Row, { className: "mt-1", gap: "xs", wrap: true, children: [visible.map((name) => (_jsxs(Span, { padding: "pill-2xs", layout: "inline-flex", className: "gap-[0.125rem] text-[10px]", rounded: "full", surface: "subtle", color: "muted", children: [_jsx("svg", { className: "h-2.5 w-2.5 flex-shrink-0", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 7a2 2 0 012-2h14a2 2 0 012 2v10a2 2 0 01-2 2H5a2 2 0 01-2-2V7z" }) }), name] }, name))), overflow > 0 && (_jsxs(Span, { padding: "pill-2xs", layout: "inline-flex", weight: "medium", className: "text-[10px]", rounded: "full", surface: "subtle", color: "muted", title: categories.slice(MAX_CHIPS).join(", "), children: ["+", overflow] })), product.brand && (_jsxs(Span, { padding: "pill-2xs", layout: "inline-flex", gap: "2xs", className: `text-[10px] ${product.brandSlug ? "cursor-pointer hover:underline" : ""}`, rounded: "full", surface: "subtle", color: "muted", ...(product.brandSlug
93
+ ? {
94
+ onClick: (e) => {
95
+ // The whole card is already wrapped in a <Link> — a nested
96
+ // <a> here would be invalid HTML, so this navigates via
97
+ // stopPropagation + router.push instead of a real Link.
98
+ e.preventDefault();
99
+ e.stopPropagation();
100
+ router.push(String(ROUTES.PUBLIC.BRAND_DETAIL(product.brandSlug)));
101
+ },
102
+ }
103
+ : {}), children: [_jsx("svg", { className: "h-2.5 w-2.5 flex-shrink-0", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" }) }), product.brand] }))] }));
90
104
  })(), (() => {
91
105
  const seller = safeDisplayName(product.storeName, "");
92
106
  return seller ? (_jsxs(Text, { className: "mt-0.5 text-[11px]", color: "faint", children: ["by ", seller] })) : null;
@@ -0,0 +1,16 @@
1
+ import type { ProductItem } from "../types";
2
+ export interface RelatedItemsSectionProps {
3
+ relatedItems: ProductItem[];
4
+ relatedByBrand: ProductItem[];
5
+ relatedByTags: ProductItem[];
6
+ relatedByStore: ProductItem[];
7
+ categoryLabel?: string;
8
+ brandLabel?: string;
9
+ storeLabel?: string;
10
+ }
11
+ /**
12
+ * The same-shape "More in category / More by brand / You might also like /
13
+ * More from store" carousel stack, shared by every listing-type detail page
14
+ * that surfaces computeRelatedItems() results.
15
+ */
16
+ export declare function RelatedItemsSection({ relatedItems, relatedByBrand, relatedByTags, relatedByStore, categoryLabel, brandLabel, storeLabel, }: RelatedItemsSectionProps): import("react").JSX.Element | null;
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Stack } from "../../../ui";
3
+ import { RelatedProductsCarousel } from "./RelatedProductsCarousel";
4
+ /**
5
+ * The same-shape "More in category / More by brand / You might also like /
6
+ * More from store" carousel stack, shared by every listing-type detail page
7
+ * that surfaces computeRelatedItems() results.
8
+ */
9
+ export function RelatedItemsSection({ relatedItems, relatedByBrand, relatedByTags, relatedByStore, categoryLabel, brandLabel, storeLabel, }) {
10
+ if (relatedItems.length === 0 &&
11
+ relatedByBrand.length === 0 &&
12
+ relatedByTags.length === 0 &&
13
+ relatedByStore.length === 0) {
14
+ return null;
15
+ }
16
+ return (_jsxs(Stack, { gap: "xl", children: [relatedItems.length > 0 && (_jsx(RelatedProductsCarousel, { items: relatedItems, title: categoryLabel ? `More in ${categoryLabel}` : "More in this category" })), relatedByBrand.length > 0 && (_jsx(RelatedProductsCarousel, { items: relatedByBrand, title: brandLabel ? `More by ${brandLabel}` : "More by this brand" })), relatedByTags.length > 0 && _jsx(RelatedProductsCarousel, { items: relatedByTags, title: "You might also like" }), relatedByStore.length > 0 && (_jsx(RelatedProductsCarousel, { items: relatedByStore, title: storeLabel ? `More from ${storeLabel}` : "More from this seller" }))] }));
17
+ }
@@ -400,4 +400,5 @@ export declare const SELLER_BULK_ACTIONS: {
400
400
  readonly storeCategories: readonly ["row-activate", "row-deactivate", "row-delete"];
401
401
  readonly groupedListings: readonly ["row-delete"];
402
402
  readonly offers: readonly ["row-approve", "row-reject"];
403
+ readonly reviews: readonly ["row-reply"];
403
404
  };
@@ -566,4 +566,5 @@ export const SELLER_BULK_ACTIONS = {
566
566
  storeCategories: [ROW_ACTION_ID.ACTIVATE, ROW_ACTION_ID.DEACTIVATE, ROW_ACTION_ID.DELETE],
567
567
  groupedListings: [ROW_ACTION_ID.DELETE],
568
568
  offers: [ROW_ACTION_ID.APPROVE, ROW_ACTION_ID.REJECT],
569
+ reviews: [ROW_ACTION_ID.REPLY],
569
570
  };
@@ -76,6 +76,7 @@ export declare const productItemSchema: z.ZodObject<{
76
76
  thumbnailUrl: z.ZodOptional<z.ZodString>;
77
77
  source: z.ZodOptional<z.ZodEnum<["upload", "youtube", "external"]>>;
78
78
  youtubeId: z.ZodOptional<z.ZodString>;
79
+ duration: z.ZodOptional<z.ZodNumber>;
79
80
  }, "strip", z.ZodTypeAny, {
80
81
  type: "video" | "image" | "file";
81
82
  url: string;
@@ -83,6 +84,7 @@ export declare const productItemSchema: z.ZodObject<{
83
84
  alt?: string | undefined;
84
85
  thumbnailUrl?: string | undefined;
85
86
  youtubeId?: string | undefined;
87
+ duration?: number | undefined;
86
88
  }, {
87
89
  type: "video" | "image" | "file";
88
90
  url: string;
@@ -90,6 +92,7 @@ export declare const productItemSchema: z.ZodObject<{
90
92
  alt?: string | undefined;
91
93
  thumbnailUrl?: string | undefined;
92
94
  youtubeId?: string | undefined;
95
+ duration?: number | undefined;
93
96
  }>, "many">>;
94
97
  video: z.ZodOptional<z.ZodObject<{
95
98
  url: z.ZodString;
@@ -445,6 +448,7 @@ export declare const productItemSchema: z.ZodObject<{
445
448
  alt?: string | undefined;
446
449
  thumbnailUrl?: string | undefined;
447
450
  youtubeId?: string | undefined;
451
+ duration?: number | undefined;
448
452
  }[] | undefined;
449
453
  inStock?: boolean | undefined;
450
454
  rating?: number | undefined;
@@ -583,6 +587,7 @@ export declare const productItemSchema: z.ZodObject<{
583
587
  alt?: string | undefined;
584
588
  thumbnailUrl?: string | undefined;
585
589
  youtubeId?: string | undefined;
590
+ duration?: number | undefined;
586
591
  }[] | undefined;
587
592
  inStock?: boolean | undefined;
588
593
  rating?: number | undefined;
@@ -2,9 +2,7 @@ import React from "react";
2
2
  export interface CouponsIndexListingProps {
3
3
  /** Pre-fetched coupons to show on first render */
4
4
  initialCoupons?: any[];
5
- /** If set, only show coupons from this store (slug, for display) */
6
- storeSlug?: string;
7
5
  /** If set, only show coupons from this store (id, for filtering) */
8
6
  storeId?: string;
9
7
  }
10
- export declare function CouponsIndexListing({ initialCoupons, storeSlug: _storeSlug, storeId, }: CouponsIndexListingProps): React.JSX.Element;
8
+ export declare function CouponsIndexListing({ initialCoupons, storeId, }: CouponsIndexListingProps): React.JSX.Element;
@@ -28,7 +28,7 @@ const COUPON_TYPES = [
28
28
  { value: COUPON_FIELDS.TYPE_VALUES.BUY_X_GET_Y, label: "Buy X Get Y" },
29
29
  ];
30
30
  const FILTER_KEYS = [TABLE_KEYS.TYPE, TABLE_KEYS.DATE_FROM, TABLE_KEYS.DATE_TO];
31
- export function CouponsIndexListing({ initialCoupons, storeSlug: _storeSlug, storeId, }) {
31
+ export function CouponsIndexListing({ initialCoupons, storeId, }) {
32
32
  const table = useUrlTable({ defaults: { pageSize: "12", sort: DEFAULT_SORT } });
33
33
  const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
34
34
  const [filterOpen, setFilterOpen] = useState(false);
@@ -4,8 +4,6 @@ export interface SearchViewProps {
4
4
  query?: string;
5
5
  /** Total result count */
6
6
  total: number;
7
- /** Whether data is loading */
8
- isLoading: boolean;
9
7
  labels?: {
10
8
  searchTitle?: string;
11
9
  resultsCount?: (count: number, query: string) => string;
@@ -26,4 +24,4 @@ export interface SearchViewProps {
26
24
  renderPagination?: () => React.ReactNode;
27
25
  className?: string;
28
26
  }
29
- export declare function SearchView({ query, total, isLoading: _isLoading, labels, renderSearchInput, renderFilters, renderActiveFilters, renderToolbar, renderResults, renderPagination, className, }: SearchViewProps): React.JSX.Element;
27
+ export declare function SearchView({ query, total, labels, renderSearchInput, renderFilters, renderActiveFilters, renderToolbar, renderResults, renderPagination, className, }: SearchViewProps): React.JSX.Element;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Div, Heading, Main, Row, Span, Stack, Text } from "../../../ui";
3
- export function SearchView({ query, total, isLoading: _isLoading, labels = {}, renderSearchInput, renderFilters, renderActiveFilters, renderToolbar, renderResults, renderPagination, className = "", }) {
3
+ export function SearchView({ query, total, labels = {}, renderSearchInput, renderFilters, renderActiveFilters, renderToolbar, renderResults, renderPagination, className = "", }) {
4
4
  const hasQuery = !!query?.trim();
5
5
  return (_jsx(Main, { className: `min-h-screen ${className}`, children: _jsxs(Stack, { padding: "y-lg", gap: "md", children: [_jsx(Div, { children: renderSearchInput() }), hasQuery && (_jsx(Div, { children: _jsx(Heading, { level: 1, size: "xl", weight: "semibold", children: labels.resultsCount
6
6
  ? labels.resultsCount(total, query)
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Row } from "@mohasinac/appkit/ui";
4
4
  import { useState } from "react";
5
5
  import { Alert, Button, Div, FormField, Stack, Text } from "../../../ui";
6
+ import { FormErrorSummary } from "../../../ui/forms";
6
7
  const __P = {
7
8
  p5: "p-[var(--appkit-space-5)]",
8
9
  };
@@ -50,5 +51,5 @@ export function QuickProductForm({ values, onChange, onPublish, onSave, onSwitch
50
51
  return (_jsxs(Stack, { gap: "lg", className: `${__P.p5}`, children: [_jsx(Div, { children: _jsx(Text, { size: "sm", color: "muted", children: "Quick add \u2014 fill the essentials and publish. You can add more details later." }) }), touched && Object.keys(errors).length > 0 && (_jsx(Alert, { variant: "error", children: "Please fix the highlighted fields before publishing." })), _jsx(FormField, { name: "title", label: "Product Name", type: "text", value: values.title ?? "", onChange: (v) => onChange({ title: v }), placeholder: "e.g. Charizard Base Set PSA 9", required: true, error: touched ? errors.title : undefined }), renderCategorySelector ? (_jsxs(Div, { children: [_jsx(Text, { className: "mb-1", color: "muted", size: "sm", weight: "medium", children: "Category" }), renderCategorySelector({
51
52
  value: values.category ?? "",
52
53
  onChange: (v) => onChange({ category: v }),
53
- }), touched && errors.category && (_jsx(Text, { className: "text-[var(--appkit-color-error)] mt-1", size: "xs", children: errors.category }))] })) : (_jsx(FormField, { name: "category", label: "Category", type: "text", value: values.category ?? "", onChange: (v) => onChange({ category: v }), placeholder: "e.g. Trading Cards", error: touched ? errors.category : undefined })), _jsx(FormField, { name: "price", label: "Price (\u20B9)", type: "number", value: toRupeesString(values.price), onChange: (v) => onChange({ price: fromRupeesString(v) }), placeholder: "e.g. 499", required: true, error: touched ? errors.price : undefined }), _jsx(FormField, { name: "mainImage", label: "Product Image", type: "image", value: values.mainImage ?? "", onChange: (v) => onChange({ mainImage: v }), onUpload: onUploadImage, required: true, error: touched ? errors.mainImage : undefined }), _jsx(FormField, { name: "description", label: "Description", type: "textarea", value: values.description ?? "", onChange: (v) => onChange({ description: v }), placeholder: "Brief description (optional)", rows: 3 }), _jsx(FormField, { name: "stockQuantity", label: "Stock Quantity", type: "number", value: String(values.stockQuantity ?? 1), onChange: (v) => onChange({ stockQuantity: Math.max(0, parseInt(v, 10) || 0) }), placeholder: "1", hint: "How many units are available" }), _jsxs(Stack, { gap: "3", padding: "t-xs", children: [_jsxs(Row, { gap: "3", children: [_jsx(Button, { variant: "primary", onClick: handlePublish, disabled: isLoading, className: "flex-1", children: isLoading ? "Publishing..." : "Publish" }), _jsx(Button, { variant: "secondary", onClick: handleSave, disabled: isLoading, children: "Save Draft" })] }), _jsx(Button, { variant: "ghost", size: "sm", textSize: "xs", onClick: onSwitchToFull, className: "self-center", children: "Show all fields (advanced)" })] })] }));
54
+ }), touched && errors.category && (_jsx(Text, { className: "text-[var(--appkit-color-error)] mt-1", size: "xs", children: errors.category }))] })) : (_jsx(FormField, { name: "category", label: "Category", type: "text", value: values.category ?? "", onChange: (v) => onChange({ category: v }), placeholder: "e.g. Trading Cards", error: touched ? errors.category : undefined })), _jsx(FormField, { name: "price", label: "Price (\u20B9)", type: "number", value: toRupeesString(values.price), onChange: (v) => onChange({ price: fromRupeesString(v) }), placeholder: "e.g. 499", required: true, error: touched ? errors.price : undefined }), _jsx(FormField, { name: "mainImage", label: "Product Image", type: "image", value: values.mainImage ?? "", onChange: (v) => onChange({ mainImage: v }), onUpload: onUploadImage, required: true, error: touched ? errors.mainImage : undefined }), _jsx(FormField, { name: "description", label: "Description", type: "textarea", value: values.description ?? "", onChange: (v) => onChange({ description: v }), placeholder: "Brief description (optional)", rows: 3 }), _jsx(FormField, { name: "stockQuantity", label: "Stock Quantity", type: "number", value: String(values.stockQuantity ?? 1), onChange: (v) => onChange({ stockQuantity: Math.max(0, parseInt(v, 10) || 0) }), placeholder: "1", hint: "How many units are available" }), _jsxs(Stack, { gap: "3", padding: "t-xs", children: [_jsx(FormErrorSummary, {}), _jsxs(Row, { gap: "3", children: [_jsx(Button, { variant: "primary", onClick: handlePublish, disabled: isLoading, className: "flex-1", children: isLoading ? "Publishing..." : "Publish" }), _jsx(Button, { variant: "secondary", onClick: handleSave, disabled: isLoading, children: "Save Draft" })] }), _jsx(Button, { variant: "ghost", size: "sm", textSize: "xs", onClick: onSwitchToFull, className: "self-center", children: "Show all fields (advanced)" })] })] }));
54
55
  }
@@ -1,24 +1,17 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { normalizeError } from "../../../errors/normalize";
4
- import { Row, SIEVE_OP, Stack, sieveFilter } from "@mohasinac/appkit/client";
4
+ import { SIEVE_OP, Stack, sieveFilter } from "@mohasinac/appkit/client";
5
5
  import { sortBy } from "@mohasinac/appkit/client";
6
- import React, { useState, useCallback } from "react";
7
- import { useUrlTable } from "../../../react/hooks/useUrlTable";
8
- import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
9
- import { Badge, Button, BulkActionBar, Div, FilterChipGroup, ListingFilterDrawer, ListingToolbar, Pagination, Span, Text, useToast, StickyToolbar } from "../../../ui";
6
+ import { useState, useCallback } from "react";
7
+ import { Badge, Button, Div, FilterChipGroup, Span, Text, useToast } from "../../../ui";
10
8
  import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
11
9
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
12
10
  import { buildBulkAction } from "../../../_internal/shared/actions/bulk-helpers";
13
11
  import { SELLER_BID_STATUS_TABS } from "../../admin/constants/filter-tabs";
14
- import { toRecordArray, toRelativeDate, toCurrency, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
12
+ import { toRecordArray, toRelativeDate, toCurrency, toStringValue } from "../hooks/useSellerListingData";
15
13
  import { DataTable } from "../../admin/components/DataTable";
16
- import { useBottomActions } from "../../layout";
17
- // ---------------------------------------------------------------------------
18
- // Config
19
- // ---------------------------------------------------------------------------
20
- const PAGE_SIZE = 25;
21
- const FILTER_KEYS = ["status"];
14
+ import { DataListingView } from "../../admin/components/DataListingView";
22
15
  const DEFAULT_SORT = "-bidDate";
23
16
  const SORT_OPTIONS = [
24
17
  { value: sortBy("bidDate", "DESC"), label: "Newest" },
@@ -35,72 +28,22 @@ const STATUS_BADGE = {
35
28
  lost: "default",
36
29
  cancelled: "danger",
37
30
  };
38
- // ---------------------------------------------------------------------------
39
- // Component
40
- // ---------------------------------------------------------------------------
41
31
  export function SellerBidsView({ endpoint = SELLER_ENDPOINTS.BIDS }) {
42
- const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
43
32
  const { showToast } = useToast();
44
- const [view, setView] = useState("table");
45
- const [searchInput, setSearchInput] = useState(table.get("q") || "");
46
- const [filterOpen, setFilterOpen] = useState(false);
47
- const [pendingFilters, setPendingFilters] = useState(() => Object.fromEntries(FILTER_KEYS.map((k) => [k, table.get(k)])));
48
- const openFilters = useCallback(() => {
49
- setPendingFilters(Object.fromEntries(FILTER_KEYS.map((k) => [k, table.get(k)])));
50
- setFilterOpen(true);
51
- }, [table]);
52
- const applyFilters = useCallback(() => {
53
- const updates = { page: "1" };
54
- for (const k of FILTER_KEYS)
55
- updates[k] = pendingFilters[k] ?? "";
56
- table.setMany(updates);
57
- setFilterOpen(false);
58
- }, [pendingFilters, table]);
59
- const clearFilters = useCallback(() => {
60
- setPendingFilters(Object.fromEntries(FILTER_KEYS.map((k) => [k, ""])));
61
- }, []);
62
- const resetAll = useCallback(() => {
63
- const updates = { q: "", sort: "" };
64
- for (const k of FILTER_KEYS)
65
- updates[k] = "";
66
- table.setMany(updates);
67
- setSearchInput("");
68
- }, [table]);
69
- const commitSearch = useCallback(() => { table.set("q", searchInput.trim()); }, [searchInput, table]);
70
- const activeFilterCount = FILTER_KEYS.filter((k) => !!table.get(k)).length;
71
- const hasActiveState = !!table.get("q") || table.get("sort") !== DEFAULT_SORT || activeFilterCount > 0;
72
- const statusRaw = table.get("status");
73
- const filters = statusRaw ? sieveFilter("status", SIEVE_OP.EQ, statusRaw) : undefined;
74
- const productIdFilter = table.get("productId") || undefined;
75
- const endpointWithProduct = productIdFilter
76
- ? `${endpoint}?productId=${encodeURIComponent(productIdFilter)}`
77
- : endpoint;
78
- const { rows, total, isLoading, errorMessage } = useSellerListingData({
79
- queryKey: ["seller", "bids", "listing"],
80
- endpoint: endpointWithProduct,
81
- page: table.getNumber("page", 1),
82
- pageSize: PAGE_SIZE,
83
- sorts: table.get("sort") || DEFAULT_SORT,
84
- filters,
85
- q: table.get("q") || undefined,
86
- mapRows: (response) => toRecordArray(response.bids).map((item, idx) => ({
87
- id: toStringValue(item.id, `bid-${idx}`),
88
- productTitle: toStringValue(item.productTitle, "Unknown auction"),
89
- productId: toStringValue(item.productId, ""),
90
- userName: toStringValue(item.userName, "—"),
91
- bidAmount: Number(item.bidAmount ?? 0),
92
- status: toStringValue(item.status, "active"),
93
- bidDate: toRelativeDate(item.bidDate ?? item.createdAt),
94
- })),
95
- getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
33
+ const [collapsedGroups, setCollapsedGroups] = useState(new Set());
34
+ const toggleGroup = (id) => setCollapsedGroups((s) => {
35
+ const next = new Set(s);
36
+ if (next.has(id))
37
+ next.delete(id);
38
+ else
39
+ next.add(id);
40
+ return next;
96
41
  });
97
- const currentPage = table.getNumber("page", 1);
98
- const totalPages = Math.ceil(total / PAGE_SIZE);
99
42
  const columns = [
100
43
  {
101
44
  key: "productTitle",
102
45
  header: "Auction",
103
- render: (row) => (_jsxs(Stack, { gap: "none", className: "", children: [_jsx(Text, { className: "line-clamp-1", color: "primary", size: "sm", weight: "medium", children: row.productTitle }), _jsx(Text, { className: "font-mono", color: "faint", size: "xs", children: row.productId })] })),
46
+ render: (row) => (_jsxs(Stack, { gap: "none", children: [_jsx(Text, { className: "line-clamp-1", color: "primary", size: "sm", weight: "medium", children: row.productTitle }), _jsx(Text, { className: "font-mono", color: "faint", size: "xs", children: row.productId })] })),
104
47
  },
105
48
  {
106
49
  key: "userName",
@@ -127,53 +70,69 @@ export function SellerBidsView({ endpoint = SELLER_ENDPOINTS.BIDS }) {
127
70
  render: (row) => _jsx(Span, { size: "xs", color: "muted", children: row.bidDate }),
128
71
  },
129
72
  ];
130
- const selection = useBulkSelection({ items: rows ?? [], keyExtractor: (r) => r.id });
131
- // S-STORE-4-B — group bids by productId (auction) with collapsible sections.
132
- const [collapsedGroups, setCollapsedGroups] = useState(new Set());
133
- const groupedRows = React.useMemo(() => {
134
- const groups = new Map();
135
- for (const row of rows ?? []) {
136
- const key = row.productId || row.productTitle;
137
- const g = groups.get(key) ?? { title: row.productTitle, bids: [] };
138
- g.bids.push(row);
139
- groups.set(key, g);
140
- }
141
- return Array.from(groups.entries()).map(([id, g]) => ({ id, ...g }));
142
- }, [rows]);
143
- const toggleGroup = (id) => setCollapsedGroups((s) => {
144
- const next = new Set(s);
145
- if (next.has(id))
146
- next.delete(id);
147
- else
148
- next.add(id);
149
- return next;
150
- });
151
- // S-STORE-4-B — bulk actions: cancel / retract.
152
- const bulkCancel = useCallback(async () => {
73
+ const bulkCancel = useCallback(async (selection) => {
153
74
  if (!selection.selectedIds.length)
154
75
  return;
155
76
  try {
156
77
  const results = await Promise.all(selection.selectedIds.map((id) => fetch(SELLER_ENDPOINTS.BID_BY_ID(id), { method: "DELETE" }).then((r) => r.ok)));
157
78
  const failed = results.filter((ok) => !ok).length;
158
- if (failed > 0) {
79
+ if (failed > 0)
159
80
  showToast(`${failed} bid(s) failed to cancel.`, "error");
160
- }
161
- else {
81
+ else
162
82
  showToast(`${results.length} bid(s) cancelled.`, "success");
163
- }
164
83
  selection.clearSelection();
165
84
  }
166
85
  catch (err) {
167
86
  void normalizeError(err);
168
87
  showToast(err instanceof Error ? err.message : "Failed to cancel bids.", "error");
169
88
  }
170
- }, [selection, showToast]);
171
- const bulkActions = [
172
- buildBulkAction(ACTIONS.SELLER["cancel-bid"], () => void bulkCancel()),
173
- ];
174
- useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: bulkActions } } : {});
175
- return (_jsxs(Div, { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search by bidder name", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), 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: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), selection.selectedIds.length > 0 && (_jsx(StickyToolbar, { offset: "header+bulk-actions", tone: "default", border: true, padding: "sm", z: "above-toolbar", children: _jsx(BulkActionBar, { selectedCount: selection.selectedIds.length, onClearSelection: selection.clearSelection, actions: bulkActions }) })), _jsxs(Div, { paddingX: "x-sm-md", padding: "y-md", children: [errorMessage && (_jsx(Div, { textSize: "sm", className: "mb-4 border border-error/20", color: "error", surface: "danger-surface", padding: "inline", rounded: "xl", children: errorMessage })), table.get("grouped") === "0" ? (_jsx(DataTable, { rows: rows, columns: columns, isLoading: isLoading, emptyLabel: "No bids found for your auctions", selectedIds: selection.selectedIdSet, onToggleSelect: selection.toggle, onToggleSelectAll: () => selection.toggleAll() })) : (_jsxs(Stack, { gap: "3", children: [groupedRows.length === 0 && !isLoading && (_jsx(Text, { size: "sm", color: "muted", children: "No bids found for your auctions." })), groupedRows.map((group) => {
176
- const collapsed = collapsedGroups.has(group.id);
177
- return (_jsxs(Div, { className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", rounded: "lg", children: [_jsxs(Button, { variant: "ghost", type: "button", onClick: () => toggleGroup(group.id), justify: "between", paddingX: "md", paddingY: "y-xs-tall", textSize: "sm", weight: "semibold", textColor: "default", className: "w-full hover:bg-[var(--appkit-color-surface-raised)]", children: [_jsxs(Span, { className: "truncate", children: [group.title, " ", _jsxs(Span, { size: "xs", weight: "normal", className: "text-[var(--appkit-color-text-muted)]", children: ["\u00B7 ", group.bids.length, " bid", group.bids.length === 1 ? "" : "s"] })] }), _jsx(Span, { "aria-hidden": true, className: "text-[var(--appkit-color-text-muted)]", children: collapsed ? "▸" : "▾" })] }), !collapsed && (_jsx(Div, { className: "border-t border-[var(--appkit-color-border)]", children: _jsx(DataTable, { rows: group.bids, columns: columns, isLoading: false, emptyLabel: "", selectedIds: selection.selectedIdSet, onToggleSelect: selection.toggle }) }))] }, group.id));
178
- })] }))] }), _jsx(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearFilters, activeCount: activeFilterCount, children: _jsx(FilterChipGroup, { label: "Bid Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })), allId: "" }) })] }));
89
+ }, [showToast]);
90
+ const config = {
91
+ portal: "seller",
92
+ title: "Bids",
93
+ searchPlaceholder: "Search by bidder name",
94
+ emptyLabel: "No bids found for your auctions",
95
+ filterKeys: ["status"],
96
+ defaultSort: DEFAULT_SORT,
97
+ queryKey: ["seller", "bids", "listing"],
98
+ endpoint,
99
+ sortOptions: SORT_OPTIONS,
100
+ initialView: "list",
101
+ columns,
102
+ mapRows: (response) => toRecordArray(response.bids).map((item, idx) => ({
103
+ id: toStringValue(item.id, `bid-${idx}`),
104
+ productTitle: toStringValue(item.productTitle, "Unknown auction"),
105
+ productId: toStringValue(item.productId, ""),
106
+ userName: toStringValue(item.userName, "—"),
107
+ bidAmount: Number(item.bidAmount ?? 0),
108
+ status: toStringValue(item.status, "active"),
109
+ bidDate: toRelativeDate(item.bidDate ?? item.createdAt),
110
+ })),
111
+ getTotal: (response, mappedRows) => (typeof response.total === "number" ? response.total : mappedRows.length),
112
+ buildFilters: (state) => (state.status ? sieveFilter("status", SIEVE_OP.EQ, state.status) : undefined),
113
+ renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsx(FilterChipGroup, { label: "Bid Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })), allId: "" })),
114
+ buildBulkActions: (selection) => [
115
+ buildBulkAction(ACTIONS.SELLER["cancel-bid"], () => void bulkCancel(selection)),
116
+ ],
117
+ // Grid/list view groups bids by auction with collapsible sections
118
+ // (S-STORE-4-B); table view shows the flat per-bid list via `columns`.
119
+ renderCards: (rows, _view, selection, isLoading) => {
120
+ const groups = new Map();
121
+ for (const row of rows) {
122
+ const key = row.productId || row.productTitle;
123
+ const g = groups.get(key) ?? { title: row.productTitle, bids: [] };
124
+ g.bids.push(row);
125
+ groups.set(key, g);
126
+ }
127
+ const groupedRows = Array.from(groups.entries()).map(([id, g]) => ({ id, ...g }));
128
+ if (groupedRows.length === 0 && !isLoading) {
129
+ return _jsx(Text, { size: "sm", color: "muted", children: "No bids found for your auctions." });
130
+ }
131
+ return (_jsx(Stack, { gap: "3", children: groupedRows.map((group) => {
132
+ const collapsed = collapsedGroups.has(group.id);
133
+ return (_jsxs(Div, { className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", rounded: "lg", children: [_jsxs(Button, { variant: "ghost", type: "button", onClick: () => toggleGroup(group.id), justify: "between", paddingX: "md", paddingY: "y-xs-tall", textSize: "sm", weight: "semibold", textColor: "default", className: "w-full hover:bg-[var(--appkit-color-surface-raised)]", children: [_jsxs(Span, { className: "truncate", children: [group.title, " ", _jsxs(Span, { size: "xs", weight: "normal", className: "text-[var(--appkit-color-text-muted)]", children: ["\u00B7 ", group.bids.length, " bid", group.bids.length === 1 ? "" : "s"] })] }), _jsx(Span, { "aria-hidden": true, className: "text-[var(--appkit-color-text-muted)]", children: collapsed ? "▸" : "▾" })] }), !collapsed && (_jsx(Div, { className: "border-t border-[var(--appkit-color-border)]", children: _jsx(DataTable, { rows: group.bids, columns: columns, isLoading: false, emptyLabel: "", selectedIds: new Set(selection.selectedIds), onToggleSelect: selection.toggleSelect }) }))] }, group.id));
134
+ }) }));
135
+ },
136
+ };
137
+ return _jsx(DataListingView, { config: config });
179
138
  }