@mohasinac/appkit 4.59.0 → 4.60.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 (531) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +62 -5
  3. package/dist/_internal/client/features/maintenance/views/MaintenanceDashboardView.js +2 -2
  4. package/dist/_internal/server/features/brands/actions.js +78 -4
  5. package/dist/_internal/server/features/checkout/actions.d.ts +36 -13
  6. package/dist/_internal/server/features/checkout/actions.js +668 -183
  7. package/dist/_internal/server/features/checkout/supplier-identity.js +18 -1
  8. package/dist/_internal/server/features/gateway-events/index.d.ts +10 -0
  9. package/dist/_internal/server/features/gateway-events/index.js +10 -0
  10. package/dist/_internal/server/features/gateway-events/ingest.d.ts +127 -0
  11. package/dist/_internal/server/features/gateway-events/ingest.js +188 -0
  12. package/dist/_internal/server/features/gateway-events/redact.d.ts +66 -0
  13. package/dist/_internal/server/features/gateway-events/redact.js +151 -0
  14. package/dist/_internal/server/features/grievance/actions.d.ts +63 -0
  15. package/dist/_internal/server/features/grievance/actions.js +173 -0
  16. package/dist/_internal/server/features/grievance/index.d.ts +8 -0
  17. package/dist/_internal/server/features/grievance/index.js +8 -0
  18. package/dist/_internal/server/features/grouped/data.js +28 -3
  19. package/dist/_internal/server/features/lottery/actions.js +99 -4
  20. package/dist/_internal/server/features/order-completion/actions.d.ts +92 -0
  21. package/dist/_internal/server/features/order-completion/actions.js +336 -0
  22. package/dist/_internal/server/features/order-completion/index.d.ts +7 -0
  23. package/dist/_internal/server/features/order-completion/index.js +7 -0
  24. package/dist/_internal/server/features/orders/actions.d.ts +13 -0
  25. package/dist/_internal/server/features/orders/actions.js +56 -2
  26. package/dist/_internal/server/features/orders/adapters.js +26 -0
  27. package/dist/_internal/server/features/orders/cancellation-refund.d.ts +116 -0
  28. package/dist/_internal/server/features/orders/cancellation-refund.js +466 -0
  29. package/dist/_internal/server/features/orders/index.d.ts +2 -1
  30. package/dist/_internal/server/features/orders/index.js +1 -1
  31. package/dist/_internal/server/features/orders/service.d.ts +60 -0
  32. package/dist/_internal/server/features/orders/service.js +74 -0
  33. package/dist/_internal/server/features/payment-cases/disputes.d.ts +76 -0
  34. package/dist/_internal/server/features/payment-cases/disputes.js +241 -0
  35. package/dist/_internal/server/features/payment-cases/index.d.ts +9 -0
  36. package/dist/_internal/server/features/payment-cases/index.js +9 -0
  37. package/dist/_internal/server/features/payouts/actions.d.ts +28 -3
  38. package/dist/_internal/server/features/payouts/actions.js +84 -10
  39. package/dist/_internal/server/features/points/adjust.d.ts +61 -0
  40. package/dist/_internal/server/features/points/adjust.js +121 -0
  41. package/dist/_internal/server/features/points/award.d.ts +65 -0
  42. package/dist/_internal/server/features/points/award.js +145 -0
  43. package/dist/_internal/server/features/price-index/market.d.ts +33 -0
  44. package/dist/_internal/server/features/price-index/market.js +54 -1
  45. package/dist/_internal/server/features/products/data.js +40 -22
  46. package/dist/_internal/server/features/protection-claims/actions.d.ts +72 -0
  47. package/dist/_internal/server/features/protection-claims/actions.js +228 -0
  48. package/dist/_internal/server/features/protection-claims/index.d.ts +8 -0
  49. package/dist/_internal/server/features/protection-claims/index.js +8 -0
  50. package/dist/_internal/server/features/refunds/actions.d.ts +20 -0
  51. package/dist/_internal/server/features/refunds/actions.js +259 -17
  52. package/dist/_internal/server/features/refunds/capacity.d.ts +29 -0
  53. package/dist/_internal/server/features/refunds/capacity.js +37 -0
  54. package/dist/_internal/server/features/reviews/actions.js +3 -2
  55. package/dist/_internal/server/features/search/index-build/sources.js +20 -1
  56. package/dist/_internal/server/features/shipping/reconcile.d.ts +10 -1
  57. package/dist/_internal/server/features/shipping/reconcile.js +34 -3
  58. package/dist/_internal/server/features/shipping/reimbursement.d.ts +117 -0
  59. package/dist/_internal/server/features/shipping/reimbursement.js +223 -0
  60. package/dist/_internal/server/features/stores/tabs.d.ts +19 -4
  61. package/dist/_internal/server/features/stores/tabs.js +24 -4
  62. package/dist/_internal/server/functions/https.d.ts +31 -1
  63. package/dist/_internal/server/functions/https.js +52 -1
  64. package/dist/_internal/server/functions/scheduled.d.ts +72 -1
  65. package/dist/_internal/server/functions/scheduled.js +124 -1
  66. package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +62 -16
  67. package/dist/_internal/server/jobs/core/boxRollupReconcile.d.ts +46 -0
  68. package/dist/_internal/server/jobs/core/boxRollupReconcile.js +142 -0
  69. package/dist/_internal/server/jobs/core/dailyDataCleanup.js +149 -1
  70. package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +14 -0
  71. package/dist/_internal/server/jobs/core/dailyStatusDigest.js +79 -1
  72. package/dist/_internal/server/jobs/core/index.d.ts +2 -0
  73. package/dist/_internal/server/jobs/core/index.js +2 -0
  74. package/dist/_internal/server/jobs/core/marketPriceRollup.d.ts +64 -0
  75. package/dist/_internal/server/jobs/core/marketPriceRollup.js +153 -0
  76. package/dist/_internal/server/jobs/core/obligationSweep.d.ts +36 -0
  77. package/dist/_internal/server/jobs/core/obligationSweep.js +503 -0
  78. package/dist/_internal/server/jobs/core/paymentReconcile.d.ts +79 -0
  79. package/dist/_internal/server/jobs/core/paymentReconcile.js +614 -0
  80. package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +34 -0
  81. package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +35 -4
  82. package/dist/_internal/server/jobs/handlers/boxRollupReconcile.d.ts +2 -0
  83. package/dist/_internal/server/jobs/handlers/boxRollupReconcile.js +15 -0
  84. package/dist/_internal/server/jobs/handlers/countersReconcileNow.d.ts +65 -0
  85. package/dist/_internal/server/jobs/handlers/countersReconcileNow.js +89 -0
  86. package/dist/_internal/server/jobs/handlers/index.d.ts +5 -0
  87. package/dist/_internal/server/jobs/handlers/index.js +5 -0
  88. package/dist/_internal/server/jobs/handlers/marketPriceRollup.d.ts +2 -0
  89. package/dist/_internal/server/jobs/handlers/marketPriceRollup.js +2 -0
  90. package/dist/_internal/server/jobs/handlers/obligationSweep.d.ts +2 -0
  91. package/dist/_internal/server/jobs/handlers/obligationSweep.js +15 -0
  92. package/dist/_internal/server/jobs/handlers/onShipmentAllocationSync.js +30 -1
  93. package/dist/_internal/server/jobs/handlers/paymentReconcile.d.ts +2 -0
  94. package/dist/_internal/server/jobs/handlers/paymentReconcile.js +6 -0
  95. package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
  96. package/dist/_internal/shared/actions/action-registry.js +71 -0
  97. package/dist/_internal/shared/checkout/coupon-discount.d.ts +73 -0
  98. package/dist/_internal/shared/checkout/coupon-discount.js +103 -0
  99. package/dist/_internal/shared/checkout/lanes.d.ts +42 -0
  100. package/dist/_internal/shared/checkout/lanes.js +46 -0
  101. package/dist/_internal/shared/checkout/order-math.d.ts +149 -1
  102. package/dist/_internal/shared/checkout/order-math.js +251 -3
  103. package/dist/_internal/shared/checkout/refundable-base.d.ts +116 -0
  104. package/dist/_internal/shared/checkout/refundable-base.js +122 -0
  105. package/dist/_internal/shared/features/auctions/config.d.ts +14 -1
  106. package/dist/_internal/shared/features/auctions/config.js +30 -1
  107. package/dist/_internal/shared/features/brands/schema.d.ts +42 -0
  108. package/dist/_internal/shared/features/brands/schema.js +18 -0
  109. package/dist/_internal/shared/features/orders/refund-copy.d.ts +22 -0
  110. package/dist/_internal/shared/features/orders/refund-copy.js +34 -0
  111. package/dist/_internal/shared/features/print/label-profiles.d.ts +198 -0
  112. package/dist/_internal/shared/features/print/label-profiles.js +350 -0
  113. package/dist/_internal/shared/features/products/to-product-item.js +33 -5
  114. package/dist/_internal/shared/fees/calculator.d.ts +31 -2
  115. package/dist/_internal/shared/fees/calculator.js +103 -5
  116. package/dist/_internal/shared/fees/india-states.d.ts +195 -0
  117. package/dist/_internal/shared/fees/india-states.js +190 -0
  118. package/dist/_internal/shared/fees/payout-hold.d.ts +80 -0
  119. package/dist/_internal/shared/fees/payout-hold.js +74 -0
  120. package/dist/_internal/shared/obligations/deadlines.d.ts +94 -0
  121. package/dist/_internal/shared/obligations/deadlines.js +155 -0
  122. package/dist/_internal/shared/shipping/quote.d.ts +96 -0
  123. package/dist/_internal/shared/shipping/quote.js +67 -0
  124. package/dist/_internal/shared/time/business-days.d.ts +91 -0
  125. package/dist/_internal/shared/time/business-days.js +185 -0
  126. package/dist/cli/index.js +0 -2
  127. package/dist/client.d.ts +9 -4
  128. package/dist/client.js +26 -3
  129. package/dist/configs/tailwind.d.ts +0 -12
  130. package/dist/configs/tailwind.js +28 -15
  131. package/dist/constants/api-endpoints.d.ts +51 -9
  132. package/dist/constants/api-endpoints.js +23 -7
  133. package/dist/constants/index.d.ts +1 -1
  134. package/dist/constants/index.js +1 -1
  135. package/dist/contracts/index.d.ts +1 -1
  136. package/dist/contracts/payment.d.ts +131 -0
  137. package/dist/features/about/components/AboutView.js +1 -1
  138. package/dist/features/about/components/DeveloperView.js +5 -2
  139. package/dist/features/about/components/FAQPageView.js +2 -1
  140. package/dist/features/about/components/FeesView.js +2 -1
  141. package/dist/features/about/components/HelpPageView.js +2 -1
  142. package/dist/features/about/components/HowAuctionsWorkView.js +2 -1
  143. package/dist/features/about/components/HowCheckoutWorksView.js +2 -1
  144. package/dist/features/about/components/HowEmiWorksView.js +2 -1
  145. package/dist/features/about/components/HowOffersWorkView.js +2 -1
  146. package/dist/features/about/components/HowOrdersWorkView.js +2 -1
  147. package/dist/features/about/components/HowPayoutsWorkView.js +2 -1
  148. package/dist/features/about/components/HowPreOrdersWorkView.js +2 -1
  149. package/dist/features/about/components/HowReviewsWorkView.js +2 -1
  150. package/dist/features/about/components/PolicyPageView.js +2 -1
  151. package/dist/features/about/components/ProseHero.d.ts +73 -0
  152. package/dist/features/about/components/ProseHero.js +18 -0
  153. package/dist/features/about/components/SecurityPrivacyView.js +2 -1
  154. package/dist/features/about/components/ShippingPolicyView.js +2 -1
  155. package/dist/features/about/components/TrackOrderView.js +2 -1
  156. package/dist/features/about/components/UnauthorizedView.js +1 -1
  157. package/dist/features/about/index.d.ts +2 -0
  158. package/dist/features/about/index.js +5 -0
  159. package/dist/features/account/actions/address-actions.d.ts +26 -2
  160. package/dist/features/account/actions/address-actions.js +25 -1
  161. package/dist/features/account/components/BuyerShoppingGuideView.js +1 -1
  162. package/dist/features/account/components/NotificationPreferencesPanel.js +1 -1
  163. package/dist/features/account/components/UserOrdersView.js +17 -0
  164. package/dist/features/account/components/UserSidebar.js +1 -1
  165. package/dist/features/account/hooks/useNotifications.js +29 -0
  166. package/dist/features/admin/actions/admin-coupon-actions.js +36 -0
  167. package/dist/features/admin/components/AdminBeysView.js +2 -2
  168. package/dist/features/admin/components/AdminBlogEditorView.js +2 -2
  169. package/dist/features/admin/components/AdminBrandEditorView.js +32 -2
  170. package/dist/features/admin/components/AdminBundleEditorView.js +1 -1
  171. package/dist/features/admin/components/AdminCarouselEditorView.js +1 -1
  172. package/dist/features/admin/components/AdminCategoriesView.js +1 -1
  173. package/dist/features/admin/components/AdminCategoryEditorView.js +73 -17
  174. package/dist/features/admin/components/AdminContactEditorView.js +1 -1
  175. package/dist/features/admin/components/AdminCouponEditorView.js +26 -1
  176. package/dist/features/admin/components/AdminFaqEditorView.js +1 -1
  177. package/dist/features/admin/components/AdminFaqsView.js +2 -2
  178. package/dist/features/admin/components/AdminGatewayEventsView.d.ts +54 -0
  179. package/dist/features/admin/components/AdminGatewayEventsView.js +209 -0
  180. package/dist/features/admin/components/AdminGuideHubView.js +1 -1
  181. package/dist/features/admin/components/AdminMoneyCasesView.d.ts +60 -0
  182. package/dist/features/admin/components/AdminMoneyCasesView.js +287 -0
  183. package/dist/features/admin/components/AdminPartsView.js +2 -2
  184. package/dist/features/admin/components/AdminProductsView.js +75 -4
  185. package/dist/features/admin/components/AdminSidebar.js +2 -2
  186. package/dist/features/admin/components/AdminSiteSettingsView.js +65 -7
  187. package/dist/features/admin/components/AdminSublistingCategoriesView.js +2 -0
  188. package/dist/features/admin/components/AdminSupportTicketDetailView.js +1 -1
  189. package/dist/features/admin/components/AdminSupportTicketsView.js +2 -2
  190. package/dist/features/admin/components/AdminTesterChecklistView.js +2 -2
  191. package/dist/features/admin/components/AdminUsersView.js +72 -1
  192. package/dist/features/admin/components/AdminViewCards.d.ts +3 -1
  193. package/dist/features/admin/components/AdminViewCards.js +4 -4
  194. package/dist/features/admin/components/DataListingView.d.ts +28 -0
  195. package/dist/features/admin/components/DataListingView.js +175 -14
  196. package/dist/features/admin/components/DataTable.d.ts +12 -1
  197. package/dist/features/admin/components/DataTable.js +3 -3
  198. package/dist/features/admin/components/OwnerQuickActions.d.ts +1 -1
  199. package/dist/features/admin/components/OwnerQuickActions.js +60 -2
  200. package/dist/features/admin/components/RecordOwnerQuickActions.d.ts +1 -1
  201. package/dist/features/admin/components/RecordOwnerQuickActions.js +61 -14
  202. package/dist/features/admin/components/analytics/AdminStatCard.d.ts +35 -1
  203. package/dist/features/admin/components/analytics/AdminStatCard.js +77 -2
  204. package/dist/features/admin/components/index.d.ts +4 -0
  205. package/dist/features/admin/components/index.js +6 -0
  206. package/dist/features/admin/constants/filter-tabs.d.ts +156 -0
  207. package/dist/features/admin/constants/filter-tabs.js +106 -0
  208. package/dist/features/admin/repository/site-settings.repository.d.ts +22 -0
  209. package/dist/features/admin/repository/site-settings.repository.js +82 -1
  210. package/dist/features/admin/schemas/admin-editor-forms.d.ts +21 -0
  211. package/dist/features/admin/schemas/admin-editor-forms.js +44 -0
  212. package/dist/features/admin/schemas/firestore.js +5 -1
  213. package/dist/features/admin/schemas/site-settings-form.js +30 -1
  214. package/dist/features/auctions/actions/bid-actions.js +13 -1
  215. package/dist/features/auctions/components/AuctionBottomActions.js +2 -2
  216. package/dist/features/auctions/components/AuctionDetailPageView.js +3 -1
  217. package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +11 -0
  218. package/dist/features/auctions/components/MarketplaceAuctionCard.js +5 -3
  219. package/dist/features/auctions/components/PlaceBidFormClient.d.ts +8 -1
  220. package/dist/features/auctions/components/PlaceBidFormClient.js +2 -2
  221. package/dist/features/audit-log/schemas/firestore.d.ts +28 -0
  222. package/dist/features/audit-log/schemas/firestore.js +14 -0
  223. package/dist/features/auth/permissions/constants.d.ts +17 -1
  224. package/dist/features/auth/permissions/constants.js +18 -0
  225. package/dist/features/blog/components/BlogPostView.js +1 -1
  226. package/dist/features/catalogue/components/AdminCatalogueApprovalsView.js +1 -1
  227. package/dist/features/categories/api/[id]/description-template/route.js +107 -1
  228. package/dist/features/categories/components/BrandDetailPageView.js +2 -2
  229. package/dist/features/categories/components/BreadcrumbTrail.js +7 -1
  230. package/dist/features/categories/components/BundleDetailView.js +1 -1
  231. package/dist/features/categories/components/CategoryDetailPageView.js +2 -2
  232. package/dist/features/categories/components/CategoryForm.js +12 -1
  233. package/dist/features/categories/components/CategoryTemplatePicker.js +38 -5
  234. package/dist/features/categories/repository/market-price-index.repository.d.ts +123 -0
  235. package/dist/features/categories/repository/market-price-index.repository.js +105 -0
  236. package/dist/features/categories/repository/price-observation.repository.d.ts +166 -0
  237. package/dist/features/categories/repository/price-observation.repository.js +132 -0
  238. package/dist/features/events/components/EventSaleBanner.js +1 -1
  239. package/dist/features/events/components/EventStatusBadge.js +1 -1
  240. package/dist/features/faq/components/FAQAccordion.js +2 -1
  241. package/dist/features/faq/components/FAQCategorySidebar.js +2 -2
  242. package/dist/features/faq/components/FAQHelpfulButtons.js +4 -4
  243. package/dist/features/faq/components/RelatedFAQs.js +1 -1
  244. package/dist/features/filters/FilterFacetSection.js +1 -1
  245. package/dist/features/filters/SwitchFilter.js +1 -1
  246. package/dist/features/gateway-events/repository/gateway-events.repository.d.ts +117 -0
  247. package/dist/features/gateway-events/repository/gateway-events.repository.js +274 -0
  248. package/dist/features/gateway-events/schemas/firestore.d.ts +217 -0
  249. package/dist/features/gateway-events/schemas/firestore.js +125 -0
  250. package/dist/features/gateway-events/schemas/index.d.ts +81 -0
  251. package/dist/features/gateway-events/schemas/index.js +79 -0
  252. package/dist/features/grouped/components/GroupedListingDetailView.js +1 -1
  253. package/dist/features/homepage/components/AnnouncementBar.js +37 -1
  254. package/dist/features/homepage/components/AnnouncementBar.style.css +30 -0
  255. package/dist/features/homepage/components/BrandsSection.js +1 -1
  256. package/dist/features/homepage/components/CTABannerSection.js +1 -1
  257. package/dist/features/homepage/components/FeaturedBundlesSection.js +14 -24
  258. package/dist/features/homepage/components/HeroCarousel.js +2 -2
  259. package/dist/features/homepage/components/SocialPostCard.js +1 -1
  260. package/dist/features/inventory/components/AdminMoveLedgerView.d.ts +7 -0
  261. package/dist/features/inventory/components/AdminMoveLedgerView.js +157 -0
  262. package/dist/features/inventory/components/AdminStorageBoxesView.d.ts +11 -0
  263. package/dist/features/inventory/components/AdminStorageBoxesView.js +168 -0
  264. package/dist/features/inventory/components/ReceiveStationView.d.ts +39 -0
  265. package/dist/features/inventory/components/ReceiveStationView.js +413 -0
  266. package/dist/features/inventory/components/operator-message.d.ts +29 -0
  267. package/dist/features/inventory/components/operator-message.js +41 -0
  268. package/dist/features/inventory/index.d.ts +13 -0
  269. package/dist/features/inventory/index.js +28 -0
  270. package/dist/features/inventory/repository/inventory-movements.repository.d.ts +97 -0
  271. package/dist/features/inventory/repository/inventory-movements.repository.js +186 -0
  272. package/dist/features/inventory/repository/inventory-placements.repository.d.ts +179 -0
  273. package/dist/features/inventory/repository/inventory-placements.repository.js +345 -0
  274. package/dist/features/inventory/repository/storage-boxes.repository.d.ts +83 -0
  275. package/dist/features/inventory/repository/storage-boxes.repository.js +127 -0
  276. package/dist/features/inventory/schemas/firestore.d.ts +197 -0
  277. package/dist/features/inventory/schemas/firestore.js +159 -0
  278. package/dist/features/layout/AppLayoutShell.d.ts +12 -1
  279. package/dist/features/layout/AppLayoutShell.js +25 -12
  280. package/dist/features/layout/AutoBreadcrumbs.js +162 -3
  281. package/dist/features/layout/AutoBreadcrumbs.style.css +45 -0
  282. package/dist/features/layout/BottomNavbar.d.ts +1 -1
  283. package/dist/features/layout/BottomNavbar.js +2 -2
  284. package/dist/features/media/MediaAvatar.js +1 -1
  285. package/dist/features/media/MediaImage.d.ts +24 -4
  286. package/dist/features/media/MediaImage.js +44 -4
  287. package/dist/features/media/MediaLightbox.js +1 -1
  288. package/dist/features/media/modals/ImageCropModal.js +1 -1
  289. package/dist/features/media/modals/ImageEditor.js +1 -1
  290. package/dist/features/media/upload/MediaUploadField.js +91 -3
  291. package/dist/features/obligations/constants/policies.d.ts +92 -0
  292. package/dist/features/obligations/constants/policies.js +378 -0
  293. package/dist/features/obligations/repository/obligations.repository.d.ts +68 -0
  294. package/dist/features/obligations/repository/obligations.repository.js +158 -0
  295. package/dist/features/obligations/schemas/firestore.d.ts +160 -0
  296. package/dist/features/obligations/schemas/firestore.js +87 -0
  297. package/dist/features/orders/actions/order-actions.d.ts +43 -4
  298. package/dist/features/orders/actions/order-actions.js +60 -3
  299. package/dist/features/orders/actions/refund-actions.js +70 -10
  300. package/dist/features/orders/components/OrderCompletionPanel.d.ts +27 -0
  301. package/dist/features/orders/components/OrderCompletionPanel.js +192 -0
  302. package/dist/features/orders/components/OrdersList.js +2 -2
  303. package/dist/features/orders/components/RefundHistoryTable.js +3 -1
  304. package/dist/features/orders/components/index.d.ts +2 -0
  305. package/dist/features/orders/components/index.js +6 -0
  306. package/dist/features/orders/constants/transitions.d.ts +59 -0
  307. package/dist/features/orders/constants/transitions.js +104 -0
  308. package/dist/features/orders/repository/orders.repository.d.ts +109 -6
  309. package/dist/features/orders/repository/orders.repository.js +464 -21
  310. package/dist/features/orders/schemas/firestore.d.ts +270 -0
  311. package/dist/features/orders/schemas/firestore.js +24 -0
  312. package/dist/features/orders/schemas/index.d.ts +61 -0
  313. package/dist/features/orders/schemas/index.js +22 -0
  314. package/dist/features/orders/types/index.d.ts +79 -0
  315. package/dist/features/parts/components/PartsIndexPageView.js +8 -1
  316. package/dist/features/payment-cases/repository/payment-cases.repository.d.ts +170 -0
  317. package/dist/features/payment-cases/repository/payment-cases.repository.js +342 -0
  318. package/dist/features/payment-cases/schemas/firestore.d.ts +229 -0
  319. package/dist/features/payment-cases/schemas/firestore.js +105 -0
  320. package/dist/features/payment-cases/schemas/resolve-form.d.ts +97 -0
  321. package/dist/features/payment-cases/schemas/resolve-form.js +114 -0
  322. package/dist/features/payments/repository/payout.repository.d.ts +0 -1
  323. package/dist/features/payments/repository/payout.repository.js +0 -1
  324. package/dist/features/points/repository/points.repository.d.ts +122 -0
  325. package/dist/features/points/repository/points.repository.js +304 -1
  326. package/dist/features/points/schemas/adjust-form.d.ts +58 -0
  327. package/dist/features/points/schemas/adjust-form.js +63 -0
  328. package/dist/features/points/schemas/firestore.d.ts +108 -1
  329. package/dist/features/points/schemas/firestore.js +84 -0
  330. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +3 -3
  331. package/dist/features/pre-orders/components/PreOrderBadge.js +1 -1
  332. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +1 -1
  333. package/dist/features/price-index/components/PriceIndexToolView.d.ts +23 -4
  334. package/dist/features/price-index/components/PriceIndexToolView.js +71 -6
  335. package/dist/features/price-index/market-stats.d.ts +82 -0
  336. package/dist/features/price-index/market-stats.js +230 -0
  337. package/dist/features/print/components/BoxLabelPrintView.d.ts +25 -0
  338. package/dist/features/print/components/BoxLabelPrintView.js +66 -0
  339. package/dist/features/print/components/LabelProfilePicker.d.ts +13 -0
  340. package/dist/features/print/components/LabelProfilePicker.js +38 -0
  341. package/dist/features/print/components/labels.d.ts +117 -0
  342. package/dist/features/print/components/labels.js +258 -0
  343. package/dist/features/print/components/labels.style.css +46 -0
  344. package/dist/features/print/index.d.ts +6 -0
  345. package/dist/features/print/index.js +16 -0
  346. package/dist/features/products/columns/productTableColumns.js +5 -4
  347. package/dist/features/products/components/MarketplaceBundleCard.js +2 -2
  348. package/dist/features/products/components/MarketplacePrizeDrawCard.js +6 -6
  349. package/dist/features/products/components/PrizeDrawCollage.js +1 -1
  350. package/dist/features/products/components/PrizeDrawItemsEditor.js +1 -1
  351. package/dist/features/products/components/PrizeRevealModal.js +2 -2
  352. package/dist/features/products/components/ProductDetailPageView.js +18 -4
  353. package/dist/features/products/components/ProductForm.js +34 -23
  354. package/dist/features/products/components/ProductGrid.js +86 -62
  355. package/dist/features/products/constants/card-badges.d.ts +97 -0
  356. package/dist/features/products/constants/card-badges.js +100 -0
  357. package/dist/features/products/repository/products.repository.js +34 -1
  358. package/dist/features/products/schemas/firestore.d.ts +46 -3
  359. package/dist/features/products/schemas/firestore.js +21 -0
  360. package/dist/features/promotions/components/PromotionsView.js +1 -1
  361. package/dist/features/promotions/repository/claimed-coupons.repository.d.ts +32 -0
  362. package/dist/features/promotions/repository/claimed-coupons.repository.js +58 -0
  363. package/dist/features/promotions/schemas/firestore.js +30 -3
  364. package/dist/features/promotions/schemas/index.d.ts +6 -6
  365. package/dist/features/protection-claims/repository/protection-claims.repository.d.ts +54 -0
  366. package/dist/features/protection-claims/repository/protection-claims.repository.js +174 -0
  367. package/dist/features/protection-claims/schemas/firestore.d.ts +168 -0
  368. package/dist/features/protection-claims/schemas/firestore.js +130 -0
  369. package/dist/features/reviews/actions/review-actions.js +3 -2
  370. package/dist/features/reviews/components/ReviewModal.js +1 -1
  371. package/dist/features/reviews/components/ReviewsList.js +1 -1
  372. package/dist/features/reviews/schemas/firestore.d.ts +20 -1
  373. package/dist/features/scams/constants/scam-types.d.ts +2 -0
  374. package/dist/features/scams/constants/scam-types.js +18 -0
  375. package/dist/features/scams/schemas/report-form.d.ts +3 -3
  376. package/dist/features/scams/schemas/report-form.js +26 -1
  377. package/dist/features/search/components/Search.js +9 -9
  378. package/dist/features/search/components/SearchResultsClient.js +18 -3
  379. package/dist/features/search/components/SearchResultsPageView.d.ts +1 -6
  380. package/dist/features/search/components/SearchResultsPageView.js +2 -2
  381. package/dist/features/seller/actions/offer-actions.js +16 -1
  382. package/dist/features/seller/actions/seller-actions.js +14 -3
  383. package/dist/features/seller/components/CategoryInlineSelect.js +75 -11
  384. package/dist/features/seller/components/PrintCenterView.d.ts +5 -0
  385. package/dist/features/seller/components/PrintCenterView.js +41 -30
  386. package/dist/features/seller/components/SellerOrdersView.js +1 -1
  387. package/dist/features/seller/components/SellerPayoutRequestView.js +16 -5
  388. package/dist/features/seller/components/SellerPayoutSettingsView.js +1 -1
  389. package/dist/features/seller/components/SellerProductShell.d.ts +16 -0
  390. package/dist/features/seller/components/SellerProductShell.js +123 -13
  391. package/dist/features/seller/components/SellerReviewsView.js +4 -2
  392. package/dist/features/seller/components/SellerSidebar.js +1 -1
  393. package/dist/features/seller/schemas/coupon-form.d.ts +26 -0
  394. package/dist/features/seller/schemas/coupon-form.js +27 -0
  395. package/dist/features/seller/schemas/product-form.d.ts +3 -0
  396. package/dist/features/seller/schemas/product-form.js +5 -0
  397. package/dist/features/shell/FormShell.js +2 -2
  398. package/dist/features/shell/QuickFormDrawer.js +14 -0
  399. package/dist/features/shell/SectionForm.d.ts +19 -0
  400. package/dist/features/shell/SectionForm.js +133 -9
  401. package/dist/features/shell/SectionForm.style.css +54 -0
  402. package/dist/features/shipments/components/AdminShipmentsView.js +16 -1
  403. package/dist/features/shipments/repository/shipment-items.repository.d.ts +9 -0
  404. package/dist/features/shipments/repository/shipment-items.repository.js +14 -0
  405. package/dist/features/site-settings/components/ActionPermissionsManager.js +1 -1
  406. package/dist/features/sticker-trace/components/StickerCommitPanel.js +1 -1
  407. package/dist/features/store-extensions/schemas/report-review-form.d.ts +8 -8
  408. package/dist/features/stores/components/StoreGuideHubView.js +1 -1
  409. package/dist/features/stores/components/StoreHeader.js +1 -1
  410. package/dist/features/support/schemas/firestore.d.ts +73 -2
  411. package/dist/features/support/schemas/firestore.js +59 -0
  412. package/dist/index.d.ts +16 -24
  413. package/dist/index.js +38 -47
  414. package/dist/next/ErrorBoundary.js +1 -1
  415. package/dist/next/routing/route-map.d.ts +24 -0
  416. package/dist/next/routing/route-map.js +40 -0
  417. package/dist/providers/payment-manual/index.d.ts +15 -1
  418. package/dist/providers/payment-manual/index.js +37 -0
  419. package/dist/providers/payment-phonepe/index.d.ts +14 -1
  420. package/dist/providers/payment-phonepe/index.js +36 -0
  421. package/dist/providers/payment-razorpay/index.d.ts +44 -1
  422. package/dist/providers/payment-razorpay/index.js +99 -0
  423. package/dist/providers/shipping-shiprocket/index.d.ts +18 -0
  424. package/dist/providers/shipping-shiprocket/index.js +18 -0
  425. package/dist/schemas/registry.d.ts +44 -11
  426. package/dist/server-entry.d.ts +2 -0
  427. package/dist/server-entry.js +27 -0
  428. package/dist/server.d.ts +42 -0
  429. package/dist/server.js +93 -0
  430. package/dist/styles.css +418 -149
  431. package/dist/tailwind-utilities.css +1 -1
  432. package/dist/tokens/themes/default-dark.js +15 -12
  433. package/dist/tokens/themes/default-light.js +14 -11
  434. package/dist/tokens/tokens.css +106 -23
  435. package/dist/ui/DataTable.style.css +4 -4
  436. package/dist/ui/columns/cell-renderers.d.ts +20 -0
  437. package/dist/ui/columns/cell-renderers.js +26 -1
  438. package/dist/ui/columns/index.d.ts +1 -1
  439. package/dist/ui/columns/index.js +4 -1
  440. package/dist/ui/components/Badge.style.css +1 -1
  441. package/dist/ui/components/Breadcrumb.js +19 -1
  442. package/dist/ui/components/BulkActionBar.style.css +4 -4
  443. package/dist/ui/components/Button.style.css +1 -1
  444. package/dist/ui/components/Checkbox.style.css +1 -1
  445. package/dist/ui/components/FallbackShell.js +1 -1
  446. package/dist/ui/components/Form.d.ts +14 -1
  447. package/dist/ui/components/Form.js +2 -2
  448. package/dist/ui/components/FormField.js +18 -4
  449. package/dist/ui/components/FormField.style.css +43 -3
  450. package/dist/ui/components/GatedPrice.style.css +1 -1
  451. package/dist/ui/components/IconButton.style.css +1 -1
  452. package/dist/ui/components/Input.js +22 -1
  453. package/dist/ui/components/Input.style.css +38 -22
  454. package/dist/ui/components/ListingFilterDrawer.js +1 -1
  455. package/dist/ui/components/ListingToolbar.js +1 -1
  456. package/dist/ui/components/PaginatedSelect.js +0 -0
  457. package/dist/ui/components/Radio.style.css +1 -1
  458. package/dist/ui/components/Repeater.d.ts +53 -0
  459. package/dist/ui/components/Repeater.js +7 -0
  460. package/dist/ui/components/RichTextEditor.d.ts +20 -1
  461. package/dist/ui/components/RichTextEditor.js +23 -2
  462. package/dist/ui/components/Select.style.css +7 -21
  463. package/dist/ui/components/Semantic.js +27 -3
  464. package/dist/ui/components/TagInput.style.css +4 -9
  465. package/dist/ui/components/Textarea.style.css +4 -18
  466. package/dist/ui/components/Toggle.style.css +1 -1
  467. package/dist/ui/components/Typography.d.ts +3 -3
  468. package/dist/ui/components/Typography.js +15 -15
  469. package/dist/ui/components/ViewToggle.style.css +4 -4
  470. package/dist/ui/forms/AddAnotherToggle.d.ts +16 -0
  471. package/dist/ui/forms/AddAnotherToggle.js +56 -0
  472. package/dist/ui/forms/ColorPickerField.js +15 -2
  473. package/dist/ui/forms/FieldCheckbox.js +15 -2
  474. package/dist/ui/forms/FieldInput.d.ts +22 -1
  475. package/dist/ui/forms/FieldInput.js +19 -5
  476. package/dist/ui/forms/FieldLabel.d.ts +35 -0
  477. package/dist/ui/forms/FieldLabel.js +70 -0
  478. package/dist/ui/forms/FieldSelect.d.ts +4 -1
  479. package/dist/ui/forms/FieldSelect.js +27 -5
  480. package/dist/ui/forms/FieldTextarea.d.ts +4 -1
  481. package/dist/ui/forms/FieldTextarea.js +22 -5
  482. package/dist/ui/forms/FormShell.d.ts +17 -1
  483. package/dist/ui/forms/FormShell.js +36 -2
  484. package/dist/ui/forms/FormShell.style.css +41 -33
  485. package/dist/ui/forms/index.d.ts +5 -1
  486. package/dist/ui/forms/index.js +2 -0
  487. package/dist/ui/icons/icon-registry.d.ts +1 -0
  488. package/dist/ui/icons/icon-registry.js +17 -1
  489. package/dist/utils/id-generators.d.ts +80 -0
  490. package/dist/utils/id-generators.js +93 -0
  491. package/dist/utils/search-txt-builders.d.ts +12 -0
  492. package/dist/utils/search-txt-builders.js +17 -0
  493. package/package.json +1 -1
  494. package/scripts/seed-cli.mjs +106 -5
  495. package/dist/features/loyalty/api/admin/loyalty/grant/route.d.ts +0 -12
  496. package/dist/features/loyalty/api/admin/loyalty/grant/route.js +0 -38
  497. package/dist/features/loyalty/api/balance/route.d.ts +0 -12
  498. package/dist/features/loyalty/api/balance/route.js +0 -41
  499. package/dist/features/loyalty/api/earn/route.d.ts +0 -12
  500. package/dist/features/loyalty/api/earn/route.js +0 -38
  501. package/dist/features/loyalty/api/history/route.d.ts +0 -12
  502. package/dist/features/loyalty/api/history/route.js +0 -58
  503. package/dist/features/loyalty/api/redeem/route.d.ts +0 -12
  504. package/dist/features/loyalty/api/redeem/route.js +0 -38
  505. package/dist/features/loyalty/columns/index.d.ts +0 -17
  506. package/dist/features/loyalty/columns/index.js +0 -40
  507. package/dist/features/loyalty/components/CoinsDisplay.d.ts +0 -12
  508. package/dist/features/loyalty/components/CoinsDisplay.js +0 -10
  509. package/dist/features/loyalty/components/index.d.ts +0 -1
  510. package/dist/features/loyalty/components/index.js +0 -1
  511. package/dist/features/loyalty/hooks/useLoyaltyBalance.d.ts +0 -4
  512. package/dist/features/loyalty/hooks/useLoyaltyBalance.js +0 -25
  513. package/dist/features/loyalty/index.d.ts +0 -6
  514. package/dist/features/loyalty/index.js +0 -6
  515. package/dist/features/loyalty/manifest.d.ts +0 -2
  516. package/dist/features/loyalty/manifest.js +0 -16
  517. package/dist/features/loyalty/messages/en.json +0 -19
  518. package/dist/features/loyalty/repository/loyalty.repository.d.ts +0 -8
  519. package/dist/features/loyalty/repository/loyalty.repository.js +0 -22
  520. package/dist/features/loyalty/schemas/index.d.ts +0 -85
  521. package/dist/features/loyalty/schemas/index.js +0 -40
  522. package/dist/features/loyalty/server.d.ts +0 -6
  523. package/dist/features/loyalty/server.js +0 -6
  524. package/dist/features/loyalty/types/index.d.ts +0 -31
  525. package/dist/features/loyalty/types/index.js +0 -1
  526. package/dist/features/loyalty/types/loyalty-config.d.ts +0 -7
  527. package/dist/features/loyalty/types/loyalty-config.js +0 -1
  528. package/dist/features/loyalty/types/loyalty-math.d.ts +0 -9
  529. package/dist/features/loyalty/types/loyalty-math.js +0 -27
  530. package/dist/features/products/components/ProductOwnerQuickActions.d.ts +0 -11
  531. package/dist/features/products/components/ProductOwnerQuickActions.js +0 -120
@@ -0,0 +1,54 @@
1
+ /**
2
+ * AdminGatewayEventsView — the webhook inbox, readable for the first time.
3
+ *
4
+ * ## What this is for
5
+ *
6
+ * `gatewayEvents` records every delivery verbatim, including event types we are
7
+ * subscribed to but do not implement — which is the whole reason the inbox
8
+ * exists rather than a logger line. Before it, a `payment.dispute.created`
9
+ * arriving ahead of the dispute handler would simply have vanished.
10
+ *
11
+ * This page answers three operator questions: did it arrive, what did we do
12
+ * with it, and can it be made to arrive again.
13
+ *
14
+ * ## 🛑 "Reopen for redelivery" is NOT "reprocess", and the UI must not imply it
15
+ *
16
+ * Nothing here can replay an event. R1's own header explains why: dispatching
17
+ * from anywhere but the webhook route would duplicate that route's whole switch
18
+ * and its RTDB signalling in a second place (Root Cause #75). The action only
19
+ * stops the inbox from refusing the NEXT delivery as a duplicate — the operator
20
+ * still presses Resend in the gateway dashboard.
21
+ *
22
+ * So the button says what it does, and the confirmation says what is left to
23
+ * do. A button labelled "Reprocess" doing only this would be the worst kind of
24
+ * half-truth: it would look like the work had happened.
25
+ *
26
+ * ## 🛑 Two statuses that look like failures and are not
27
+ *
28
+ * `ignored` means an event type we do not implement was recorded verbatim —
29
+ * healthy, and the inbox's purpose. `conflict` means a LATE event would have
30
+ * regressed an order's status, so it was recorded and not applied; the ack was
31
+ * 200 because the event is not wrong, it is out of date. Labelling either as an
32
+ * error would send operators chasing non-problems, which is how a queue stops
33
+ * being read.
34
+ *
35
+ * ## 🛑 No search box, and no sort on `status`
36
+ *
37
+ * `searchPlaceholder` is omitted because the endpoint does not read `q`;
38
+ * declaring it is what makes a dead box exist. And `status` is `canSort: false`
39
+ * in `SIEVE_FIELDS`, so a sort on it would be DROPPED silently by sievejs
40
+ * (Root Cause #63) — the status FILTER is the control, and it is in the panel.
41
+ *
42
+ * EXPORTS: AdminGatewayEventsView, type AdminGatewayEventsViewProps
43
+ *
44
+ * @tag domain:gateway-events
45
+ * @tag layer:component
46
+ * @tag pattern:listing
47
+ * @tag access:client
48
+ * @tag consumers:admin/maintenance/gateway-events
49
+ * @tag sideEffects:network
50
+ */
51
+ import React from "react";
52
+ import type { ListingLayoutProps } from "../../../ui";
53
+ export type AdminGatewayEventsViewProps = ListingLayoutProps;
54
+ export declare function AdminGatewayEventsView({ children, ...props }: AdminGatewayEventsViewProps): React.JSX.Element;
@@ -0,0 +1,209 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ /**
4
+ * AdminGatewayEventsView — the webhook inbox, readable for the first time.
5
+ *
6
+ * ## What this is for
7
+ *
8
+ * `gatewayEvents` records every delivery verbatim, including event types we are
9
+ * subscribed to but do not implement — which is the whole reason the inbox
10
+ * exists rather than a logger line. Before it, a `payment.dispute.created`
11
+ * arriving ahead of the dispute handler would simply have vanished.
12
+ *
13
+ * This page answers three operator questions: did it arrive, what did we do
14
+ * with it, and can it be made to arrive again.
15
+ *
16
+ * ## 🛑 "Reopen for redelivery" is NOT "reprocess", and the UI must not imply it
17
+ *
18
+ * Nothing here can replay an event. R1's own header explains why: dispatching
19
+ * from anywhere but the webhook route would duplicate that route's whole switch
20
+ * and its RTDB signalling in a second place (Root Cause #75). The action only
21
+ * stops the inbox from refusing the NEXT delivery as a duplicate — the operator
22
+ * still presses Resend in the gateway dashboard.
23
+ *
24
+ * So the button says what it does, and the confirmation says what is left to
25
+ * do. A button labelled "Reprocess" doing only this would be the worst kind of
26
+ * half-truth: it would look like the work had happened.
27
+ *
28
+ * ## 🛑 Two statuses that look like failures and are not
29
+ *
30
+ * `ignored` means an event type we do not implement was recorded verbatim —
31
+ * healthy, and the inbox's purpose. `conflict` means a LATE event would have
32
+ * regressed an order's status, so it was recorded and not applied; the ack was
33
+ * 200 because the event is not wrong, it is out of date. Labelling either as an
34
+ * error would send operators chasing non-problems, which is how a queue stops
35
+ * being read.
36
+ *
37
+ * ## 🛑 No search box, and no sort on `status`
38
+ *
39
+ * `searchPlaceholder` is omitted because the endpoint does not read `q`;
40
+ * declaring it is what makes a dead box exist. And `status` is `canSort: false`
41
+ * in `SIEVE_FIELDS`, so a sort on it would be DROPPED silently by sievejs
42
+ * (Root Cause #63) — the status FILTER is the control, and it is in the panel.
43
+ *
44
+ * EXPORTS: AdminGatewayEventsView, type AdminGatewayEventsViewProps
45
+ *
46
+ * @tag domain:gateway-events
47
+ * @tag layer:component
48
+ * @tag pattern:listing
49
+ * @tag access:client
50
+ * @tag consumers:admin/maintenance/gateway-events
51
+ * @tag sideEffects:network
52
+ */
53
+ import React, { useState } from "react";
54
+ import { sieveFilter, SIEVE_OP, sortBy, } from "@mohasinac/appkit/client";
55
+ import { FilterChipGroup, ListingLayout, Modal, RecordDetailModal, Row, RowActionMenu, Stack, Text, Button, } from "../../../ui/index.js";
56
+ import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints.js";
57
+ import { ADMIN_GATEWAY_EVENT_KIND_TABS, ADMIN_GATEWAY_EVENT_STATUS_TABS, } from "../constants/filter-tabs.js";
58
+ import { toRecordArray, toRelativeDate, toStringValue, } from "../hooks/useAdminListingData.js";
59
+ import { DataListingView } from "./DataListingView.js";
60
+ /** Operator-facing status names — see the 🛑 about `ignored` and `conflict`. */
61
+ const STATUS_LABEL = {
62
+ received: "Received, not yet settled",
63
+ processing: "Being processed",
64
+ processed: "Processed",
65
+ failed: "Failed",
66
+ conflict: "Arrived late — recorded, not applied",
67
+ ignored: "Recorded, no handler for this type",
68
+ };
69
+ export function AdminGatewayEventsView({ children, ...props }) {
70
+ const [detail, setDetail] = useState(null);
71
+ const [reopenId, setReopenId] = useState(null);
72
+ const [busy, setBusy] = useState(false);
73
+ const [revision, setRevision] = useState(0);
74
+ if (React.Children.count(children) > 0) {
75
+ return (_jsx(ListingLayout, { portal: "admin", ...props, children: children }));
76
+ }
77
+ const reopen = async (id) => {
78
+ setBusy(true);
79
+ try {
80
+ const res = await fetch(ADMIN_ENDPOINTS.MAINTENANCE_GATEWAY_EVENTS, {
81
+ method: "PATCH",
82
+ headers: { "Content-Type": "application/json" },
83
+ body: JSON.stringify({ id }),
84
+ });
85
+ if (!res.ok)
86
+ throw new Error(`Could not reopen that event (${res.status})`);
87
+ setRevision((r) => r + 1);
88
+ setReopenId(null);
89
+ setDetail(null);
90
+ }
91
+ finally {
92
+ setBusy(false);
93
+ }
94
+ };
95
+ const config = {
96
+ portal: "admin",
97
+ title: "Gateway events",
98
+ subtitle: "Every webhook delivery, recorded verbatim — including event types we have no handler for. Read-only apart from reopening one for redelivery.",
99
+ emptyLabel: "No gateway events recorded",
100
+ // 🛑 No `searchPlaceholder` — the endpoint does not read `q`.
101
+ filterKeys: ["status", "kind"],
102
+ /*
103
+ * `receivedAt`, which every row has. 🛑 NOT `status`, which is
104
+ * `canSort: false` in SIEVE_FIELDS and would therefore be dropped by
105
+ * sievejs with no error (Root Cause #63); and not `processedAt`, which is
106
+ * optional — a Firestore `orderBy` excludes documents lacking the field, so
107
+ * it would hide every unsettled event, i.e. exactly the ones worth seeing
108
+ * (Root Cause #100).
109
+ */
110
+ defaultSort: sortBy("receivedAt", "DESC"),
111
+ queryKey: ["admin", "gateway-events", "listing", String(revision)],
112
+ endpoint: ADMIN_ENDPOINTS.MAINTENANCE_GATEWAY_EVENTS,
113
+ /*
114
+ * 🛑 ONLY `receivedAt`, and the omission is an index-weight decision rather
115
+ * than a shortfall.
116
+ *
117
+ * `attempts` is `canSort: true`, so "Most attempts" would work — but each
118
+ * filter+sort combination needs its own composite index, and a sort on a
119
+ * second field triples them: `(status, attempts)`, `(kind, attempts)`,
120
+ * `(status, kind, attempts)` on top of the three `receivedAt` ones.
121
+ *
122
+ * `gatewayEvents` takes a row for every webhook delivery, which makes it
123
+ * the highest-write collection in this subsystem — and a composite index is
124
+ * a write multiplier on EVERY document, forever, not a read-time cost. Six
125
+ * indexes to rank a rarely-opened diagnostic by a number the `failed` status
126
+ * filter already finds is the wrong trade.
127
+ *
128
+ * Two indexes are added for the filter combinations that remain:
129
+ * `(status, receivedAt desc)` and `(status, kind, receivedAt desc)`.
130
+ * `(kind, receivedAt desc)` already existed.
131
+ */
132
+ sortOptions: [
133
+ { value: sortBy("receivedAt", "DESC"), label: "Newest" },
134
+ { value: sortBy("receivedAt", "ASC"), label: "Oldest" },
135
+ ],
136
+ mapRows: (response) => toRecordArray(response.items).map((item, index) => {
137
+ const status = toStringValue(item.status, "received");
138
+ const attempts = typeof item.attempts === "number" ? item.attempts : 0;
139
+ return {
140
+ id: toStringValue(item.id, `event-${index}`),
141
+ primary: `${toStringValue(item.gateway, "?")} · ${toStringValue(item.kind, "other")}`,
142
+ secondary: [
143
+ STATUS_LABEL[status] ?? status,
144
+ toStringValue(item.gatewayOrderId, "") || null,
145
+ toStringValue(item.gatewayPaymentId, "") || null,
146
+ // Only when informative — "1 attempt" is the normal case and noise.
147
+ attempts > 1 ? `${attempts} attempts` : null,
148
+ item.terminal === true ? "terminal" : null,
149
+ ]
150
+ .filter(Boolean)
151
+ .join(" · "),
152
+ status,
153
+ updatedAt: toRelativeDate(item.receivedAt),
154
+ _raw: item,
155
+ };
156
+ }),
157
+ getTotal: (response, mappedRows) => typeof response.meta?.total === "number" ? response.meta.total : mappedRows.length,
158
+ onRowClick: (row) => setDetail(row._raw),
159
+ buildFilters: (state) => {
160
+ const parts = [];
161
+ if (state.status && state.status !== "All")
162
+ parts.push(sieveFilter("status", SIEVE_OP.EQ, state.status));
163
+ if (state.kind && state.kind !== "All")
164
+ parts.push(sieveFilter("kind", SIEVE_OP.EQ, state.kind));
165
+ return parts.length > 0 ? parts.join(",") : undefined;
166
+ },
167
+ renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
168
+ { label: "View details", onClick: () => setDetail(row._raw) },
169
+ { label: "Reopen for redelivery", onClick: () => setReopenId(row.id) },
170
+ ] })),
171
+ renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(Stack, { gap: "md", children: [_jsx(FilterChipGroup, { label: "Status", tabs: ADMIN_GATEWAY_EVENT_STATUS_TABS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }), _jsx(FilterChipGroup, { label: "Kind", tabs: ADMIN_GATEWAY_EVENT_KIND_TABS, value: pendingFilters.kind ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, kind: id })) })] })),
172
+ };
173
+ const detailStatus = detail ? toStringValue(detail.status, "") : "";
174
+ return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(RecordDetailModal, { isOpen: detail !== null, onClose: () => setDetail(null), title: detail
175
+ ? `${toStringValue(detail.gateway, "?")} · ${toStringValue(detail.kind, "other")}`
176
+ : "Gateway event", badges: detail
177
+ ? [
178
+ { label: STATUS_LABEL[detailStatus] ?? detailStatus },
179
+ ...(detail.terminal === true
180
+ ? [{ label: "terminal", variant: "warning" }]
181
+ : []),
182
+ ]
183
+ : undefined, fields: detail
184
+ ? [
185
+ { label: "Event id", value: toStringValue(detail.id, "") },
186
+ { label: "Provider event id", value: toStringValue(detail.providerEventId, "") || "— (deduped on the body digest instead)" },
187
+ { label: "Body SHA-256", value: toStringValue(detail.bodySha256, "") },
188
+ { label: "Gateway order", value: toStringValue(detail.gatewayOrderId, "") || "—" },
189
+ { label: "Gateway payment", value: toStringValue(detail.gatewayPaymentId, "") || "—" },
190
+ { label: "Amount", value: typeof detail.amount === "number" ? `₹${detail.amount.toFixed(2)}` : "—" },
191
+ { label: "Orders placed", value: Array.isArray(detail.orderIds) ? detail.orderIds.join(", ") : "—" },
192
+ { label: "Received", value: toStringValue(detail.receivedAt, "") },
193
+ { label: "Settled", value: toStringValue(detail.processedAt, "") || "— not settled" },
194
+ { label: "Attempts", value: String(detail.attempts ?? 0) },
195
+ { label: "Lease expires", value: toStringValue(detail.leaseExpiresAt, "") },
196
+ { label: "Last error", value: toStringValue(detail.lastError, "") || "—" },
197
+ { label: "Retention expiry", value: toStringValue(detail.expiresAt, "") },
198
+ ]
199
+ : undefined,
200
+ /*
201
+ * `payload` is the REDACTED projection, never the raw body — Razorpay's
202
+ * payment entity carries email, contact, card.last4, vpa and bank, and
203
+ * `redactGatewayPayload` strips them recursively. `bodySha256` above
204
+ * preserves integrity regardless, which is what makes redaction safe.
205
+ */
206
+ metadata: detail && detail.payload && typeof detail.payload === "object"
207
+ ? detail.payload
208
+ : undefined, footer: detail ? (_jsx(Button, { variant: "outline", size: "sm", onClick: () => setReopenId(toStringValue(detail.id, "")), children: "Reopen for redelivery" })) : undefined }), _jsx(Modal, { isOpen: reopenId !== null, onClose: () => setReopenId(null), title: "Reopen this event for redelivery", size: "sm", children: _jsxs(Stack, { gap: "md", children: [_jsxs(Text, { size: "sm", children: ["This clears the terminal flag and the attempt count so the inbox will ", _jsx("strong", { children: "accept" }), " the next delivery of this event instead of refusing it as a duplicate."] }), _jsx(Row, { surface: "warning-surface", padding: "sm", rounded: "default", children: _jsxs(Text, { size: "sm", color: "warning", children: ["It does not reprocess anything by itself. Nothing outside the webhook route knows how to handle an event, so after this you still need to press ", _jsx("strong", { children: "Resend" }), " on this delivery in the gateway dashboard \u2014 or wait for the gateway\u2019s own retry."] }) }), _jsxs(Row, { justify: "end", gap: "sm", children: [_jsx(Button, { variant: "ghost", onClick: () => setReopenId(null), disabled: busy, children: "Cancel" }), _jsx(Button, { variant: "primary", isLoading: busy, disabled: busy, onClick: () => reopen(reopenId), children: "Reopen" })] })] }) })] }));
209
+ }
@@ -81,5 +81,5 @@ export function AdminGuideHubView({ permissions = [], isFullAdmin = false }) {
81
81
  const hasPermission = (perm) => isFullAdmin || permissions.includes(perm);
82
82
  const visibleCards = GUIDE_CARDS.filter((c) => hasPermission(c.permission));
83
83
  const hasAny = visibleCards.length > 0;
84
- return (_jsxs(Stack, { gap: "xl", padding: "b-2xl", children: [_jsx(Section, { overflow: "hidden", className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", rounded: "2xl", shadow: "sm", children: _jsxs(Div, { paddingX: "x-md-xl", paddingY: "y-xl", className: "[background:linear-gradient(135deg,var(--appkit-color-primary-700)_0%,var(--appkit-color-cobalt)_60%,var(--appkit-color-secondary-400)_100%)]", children: [_jsxs(Row, { className: "mb-3", align: "center", gap: "3", children: [_jsx(Row, { className: "flex-shrink-0 w-10 h-10", surface: "default", align: "center", justify: "center", rounded: "xl", children: _jsx(BookOpen, { className: "w-5 h-5 text-white" }) }), _jsx(Text, { color: "inverse", className: "/80 tracking-widest", size: "sm", weight: "semibold", transform: "uppercase", children: "Admin & Employee Guide" })] }), _jsx(Heading, { color: "inverse", level: 1, className: "mb-2", mdSize: "3xl", size: "2xl", weight: "bold", children: "LetItRip Internal Guide" }), _jsx(Text, { color: "inverse", className: "/80", size: "base", children: "Everything you need to operate and manage LetItRip \u2014 India's largest collectibles marketplace." })] }) }), _jsx(Alert, { variant: "info", compact: true, children: "These guides describe expected platform behaviour. Real access to each section is enforced independently by the permission system \u2014 this page is reference only." }), !hasAny && (_jsx(Alert, { variant: "info", title: "Limited access", children: "Your permission set doesn't include read access to any admin sections yet. Contact your admin to request the permissions you need." })), hasAny && (_jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "text-[var(--appkit-color-text)] mb-4", size: "lg", weight: "semibold", children: "Guides" }), _jsx(Grid, { cols: "cards", gap: "md", children: visibleCards.map(({ Icon, title, description, href }) => (_jsxs(TextLink, { variant: "bare", href: href, rounded: "xl", layout: "flex-col", gap: "md", paddingX: "lg", paddingY: "lg", shadow: "hover-md", className: "group border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] hover:border-[var(--appkit-color-primary)] transition-all", children: [_jsxs(Row, { align: "center", gap: "3", children: [_jsx(Row, { className: "flex-shrink-0 w-9 h-9 [background:linear-gradient(135deg,var(--appkit-color-primary-700)_0%,var(--appkit-color-cobalt)_100%)]", align: "center", justify: "center", rounded: "lg", children: _jsx(Icon, { className: "w-4 h-4 text-white" }) }), _jsx(Text, { className: "text-[var(--appkit-color-text)] group-hover:text-[var(--appkit-color-primary)] transition-colors", weight: "semibold", children: title })] }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)] leading-relaxed", size: "sm", children: description }), _jsx(Text, { className: "text-[var(--appkit-color-primary)] mt-auto", size: "xs", weight: "medium", children: "Read guide \u2192" })] }, title))) })] })), _jsx(Section, { className: CLS_WARN_PANEL, children: _jsxs(Row, { align: "start", gap: "3", children: [_jsx(AlertTriangle, { className: "w-5 h-5 text-warning flex-shrink-0 mt-0.5" }), _jsxs(Div, { children: [_jsx(Text, { className: CLS_WARN_HEAD, children: "Remember: with great access comes responsibility" }), _jsx(Text, { className: CLS_WARN_BODY, children: "Admin actions are logged. Never access user PII (email, phone) without a legitimate support reason. Never grant capabilities or permissions without documented approval. When in doubt, escalate to a senior admin." })] })] }) })] }));
84
+ return (_jsxs(Stack, { gap: "xl", padding: "b-2xl", children: [_jsx(Section, { overflow: "hidden", className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", rounded: "2xl", shadow: "sm", children: _jsxs(Div, { paddingX: "x-md-xl", paddingY: "y-xl", className: "[background:linear-gradient(135deg,var(--appkit-color-primary-700)_0%,var(--appkit-color-cobalt)_60%,var(--appkit-color-secondary-400)_100%)]", children: [_jsxs(Row, { className: "mb-3", align: "center", gap: "3", children: [_jsx(Row, { className: "flex-shrink-0 w-10 h-10", surface: "default", align: "center", justify: "center", rounded: "xl", children: _jsx(BookOpen, { className: "w-5 h-5 text-white" }) }), _jsx(Text, { color: "inverse-muted", className: "tracking-widest", size: "sm", weight: "semibold", transform: "uppercase", children: "Admin & Employee Guide" })] }), _jsx(Heading, { color: "inverse", level: 1, className: "mb-2", mdSize: "3xl", size: "2xl", weight: "bold", children: "LetItRip Internal Guide" }), _jsx(Text, { color: "inverse-muted", size: "base", children: "Everything you need to operate and manage LetItRip \u2014 India's largest collectibles marketplace." })] }) }), _jsx(Alert, { variant: "info", compact: true, children: "These guides describe expected platform behaviour. Real access to each section is enforced independently by the permission system \u2014 this page is reference only." }), !hasAny && (_jsx(Alert, { variant: "info", title: "Limited access", children: "Your permission set doesn't include read access to any admin sections yet. Contact your admin to request the permissions you need." })), hasAny && (_jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "text-[var(--appkit-color-text)] mb-4", size: "lg", weight: "semibold", children: "Guides" }), _jsx(Grid, { cols: "cards", gap: "md", children: visibleCards.map(({ Icon, title, description, href }) => (_jsxs(TextLink, { variant: "bare", href: href, rounded: "xl", layout: "flex-col", gap: "md", paddingX: "lg", paddingY: "lg", shadow: "hover-md", className: "group border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] hover:border-[var(--appkit-color-primary)] transition-all", children: [_jsxs(Row, { align: "center", gap: "3", children: [_jsx(Row, { className: "flex-shrink-0 w-9 h-9 [background:linear-gradient(135deg,var(--appkit-color-primary-700)_0%,var(--appkit-color-cobalt)_100%)]", align: "center", justify: "center", rounded: "lg", children: _jsx(Icon, { className: "w-4 h-4 text-white" }) }), _jsx(Text, { className: "text-[var(--appkit-color-text)] group-hover:text-[var(--appkit-color-primary)] transition-colors", weight: "semibold", children: title })] }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)] leading-relaxed", size: "sm", children: description }), _jsx(Text, { className: "text-[var(--appkit-color-primary)] mt-auto", size: "xs", weight: "medium", children: "Read guide \u2192" })] }, title))) })] })), _jsx(Section, { className: CLS_WARN_PANEL, children: _jsxs(Row, { align: "start", gap: "3", children: [_jsx(AlertTriangle, { className: "w-5 h-5 text-warning flex-shrink-0 mt-0.5" }), _jsxs(Div, { children: [_jsx(Text, { className: CLS_WARN_HEAD, children: "Remember: with great access comes responsibility" }), _jsx(Text, { className: CLS_WARN_BODY, children: "Admin actions are logged. Never access user PII (email, phone) without a legitimate support reason. Never grant capabilities or permissions without documented approval. When in doubt, escalate to a senior admin." })] })] }) })] }));
85
85
  }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * AdminMoneyCasesView — the operator queue for everything where money is at
3
+ * risk, and the FIRST surface `paymentCases` has ever had.
4
+ *
5
+ * ## Why this page is the point of the whole payment-protection spine
6
+ *
7
+ * The event inbox, the four reconcilers, the obligation sweep, the dispute
8
+ * ingest, the protection claims and the grievance intake all converge on one
9
+ * collection — and until this view existed, **nothing could read it.** Thirty-six
10
+ * commits of detection wrote rows into a queue with no screen. That is Root
11
+ * Cause #56 at the scale of a subsystem: *a feature is built, one of its
12
+ * surfaces is missing, and nothing notices.*
13
+ *
14
+ * The daily digest was the only consumer, and it was built first for exactly
15
+ * that reason — it PUSHES, so the queue had one reader from day one. This is
16
+ * the pull side.
17
+ *
18
+ * ## 🛑 It is NOT under `/admin/maintenance/`
19
+ *
20
+ * Maintenance means "something broke, look when you can" and is granted to
21
+ * `maintenance_employee`. A case here can carry a gateway's own `respond_by` —
22
+ * miss it and the chargeback is lost by default irrespective of who was right —
23
+ * and an `amountAtRisk` in real rupees. Hence its own section and
24
+ * `admin:payment-cases:read|write`, admin only.
25
+ *
26
+ * ## 🛑 NO SEARCH BOX, and that is a decision
27
+ *
28
+ * `ListingViewConfig.searchPlaceholder` is optional and *"declaring it is what
29
+ * makes the box exist"*. `/api/admin/payment-cases` does not read `q`, and
30
+ * ~39 views in this codebase already render a box whose endpoint ignores the
31
+ * term — the user types, the request carries it, nothing changes, no error.
32
+ * Omitting it is the fix; a placeholder describing a capability the endpoint
33
+ * lacks is the defect.
34
+ *
35
+ * ## 🛑 The default sort cannot be `dueAt`
36
+ *
37
+ * `dueAt` is OPTIONAL and most cases have none — only a dispute and a grievance
38
+ * carry an external clock. A Firestore `orderBy` on an optional field silently
39
+ * EXCLUDES every document that lacks it (Root Cause #100), so sorting by
40
+ * deadline would hide the great majority of the queue while looking like it had
41
+ * simply ordered it. `lastObservedAt` is written by `openOrObserve` on every
42
+ * case, every time, so it is the only safe default — and it happens to be the
43
+ * right one: "what has been seen most recently".
44
+ *
45
+ * Deadline pressure is surfaced instead by the `dueAt` row text and by R4,
46
+ * which escalates and re-notifies at T-72h and T-24h.
47
+ *
48
+ * EXPORTS: AdminMoneyCasesView, type AdminMoneyCasesViewProps
49
+ *
50
+ * @tag domain:payment-cases
51
+ * @tag layer:component
52
+ * @tag pattern:listing
53
+ * @tag access:client
54
+ * @tag consumers:admin/money-cases
55
+ * @tag sideEffects:network
56
+ */
57
+ import React from "react";
58
+ import type { ListingLayoutProps } from "../../../ui";
59
+ export type AdminMoneyCasesViewProps = ListingLayoutProps;
60
+ export declare function AdminMoneyCasesView({ children, ...props }: AdminMoneyCasesViewProps): React.JSX.Element;
@@ -0,0 +1,287 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ /**
4
+ * AdminMoneyCasesView — the operator queue for everything where money is at
5
+ * risk, and the FIRST surface `paymentCases` has ever had.
6
+ *
7
+ * ## Why this page is the point of the whole payment-protection spine
8
+ *
9
+ * The event inbox, the four reconcilers, the obligation sweep, the dispute
10
+ * ingest, the protection claims and the grievance intake all converge on one
11
+ * collection — and until this view existed, **nothing could read it.** Thirty-six
12
+ * commits of detection wrote rows into a queue with no screen. That is Root
13
+ * Cause #56 at the scale of a subsystem: *a feature is built, one of its
14
+ * surfaces is missing, and nothing notices.*
15
+ *
16
+ * The daily digest was the only consumer, and it was built first for exactly
17
+ * that reason — it PUSHES, so the queue had one reader from day one. This is
18
+ * the pull side.
19
+ *
20
+ * ## 🛑 It is NOT under `/admin/maintenance/`
21
+ *
22
+ * Maintenance means "something broke, look when you can" and is granted to
23
+ * `maintenance_employee`. A case here can carry a gateway's own `respond_by` —
24
+ * miss it and the chargeback is lost by default irrespective of who was right —
25
+ * and an `amountAtRisk` in real rupees. Hence its own section and
26
+ * `admin:payment-cases:read|write`, admin only.
27
+ *
28
+ * ## 🛑 NO SEARCH BOX, and that is a decision
29
+ *
30
+ * `ListingViewConfig.searchPlaceholder` is optional and *"declaring it is what
31
+ * makes the box exist"*. `/api/admin/payment-cases` does not read `q`, and
32
+ * ~39 views in this codebase already render a box whose endpoint ignores the
33
+ * term — the user types, the request carries it, nothing changes, no error.
34
+ * Omitting it is the fix; a placeholder describing a capability the endpoint
35
+ * lacks is the defect.
36
+ *
37
+ * ## 🛑 The default sort cannot be `dueAt`
38
+ *
39
+ * `dueAt` is OPTIONAL and most cases have none — only a dispute and a grievance
40
+ * carry an external clock. A Firestore `orderBy` on an optional field silently
41
+ * EXCLUDES every document that lacks it (Root Cause #100), so sorting by
42
+ * deadline would hide the great majority of the queue while looking like it had
43
+ * simply ordered it. `lastObservedAt` is written by `openOrObserve` on every
44
+ * case, every time, so it is the only safe default — and it happens to be the
45
+ * right one: "what has been seen most recently".
46
+ *
47
+ * Deadline pressure is surfaced instead by the `dueAt` row text and by R4,
48
+ * which escalates and re-notifies at T-72h and T-24h.
49
+ *
50
+ * EXPORTS: AdminMoneyCasesView, type AdminMoneyCasesViewProps
51
+ *
52
+ * @tag domain:payment-cases
53
+ * @tag layer:component
54
+ * @tag pattern:listing
55
+ * @tag access:client
56
+ * @tag consumers:admin/money-cases
57
+ * @tag sideEffects:network
58
+ */
59
+ import React, { useState } from "react";
60
+ import { sieveFilter, SIEVE_OP, sortBy, } from "@mohasinac/appkit/client";
61
+ import { Button, FilterChipGroup, ListingLayout, RecordDetailModal, Row, RowActionMenu, Stack, Text, } from "../../../ui/index.js";
62
+ import { RecordStatusTimeline } from "../../status-history/components/RecordStatusTimeline.js";
63
+ import { ReviewDecisionModal } from "../../store-extensions/components/ReviewDecisionModal.js";
64
+ import { paymentCaseResolveFormSchema, } from "../../payment-cases/schemas/resolve-form.js";
65
+ import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints.js";
66
+ import { ADMIN_PAYMENT_CASE_KIND_TABS, ADMIN_PAYMENT_CASE_SEVERITY_TABS, ADMIN_PAYMENT_CASE_STATUS_TABS, } from "../constants/filter-tabs.js";
67
+ import { toRecordArray, toRelativeDate, toStringValue, } from "../hooks/useAdminListingData.js";
68
+ import { DataListingView } from "./DataListingView.js";
69
+ /**
70
+ * Operator-facing names. Deliberately describe the PROBLEM rather than echo
71
+ * the field value — `missing_order` is "Captured, no order", which is what has
72
+ * actually happened and what the next action depends on.
73
+ *
74
+ * Kept beside the chip labels rather than shared with them: the chips are terse
75
+ * because they sit in a grid, these head a row and can afford a clause.
76
+ */
77
+ const KIND_LABEL = {
78
+ missing_order: "Captured payment with no order",
79
+ unprocessed_event: "Gateway event never processed",
80
+ status_conflict: "Late event would have regressed an order",
81
+ dispute: "Chargeback",
82
+ refund_mismatch: "Refund totals disagree with the gateway",
83
+ amount_mismatch: "Captured amount ≠ recorded total",
84
+ dead_job: "Job exhausted its retries",
85
+ grievance: "Statutory grievance",
86
+ shipping_unpriced: "Store shipping could not be priced",
87
+ protection_claim: "Protection claim",
88
+ manual_refund_due: "Refund owed, no automatic rail",
89
+ };
90
+ /** Rupees, for a row. Plain `toFixed` — these are already decimal rupees. */
91
+ function money(value) {
92
+ return typeof value === "number" ? `₹${value.toFixed(2)}` : null;
93
+ }
94
+ /**
95
+ * Narrow a JSON value to status-history entries.
96
+ *
97
+ * 🛑 A FUNCTION, NOT A CAST. This was `detail.statusHistory as
98
+ * StatusChangeEntry[] | undefined`, which `tsc` rejects as insufficiently
99
+ * overlapping — and the suggested `as unknown as` is the double cast this
100
+ * repo bans outright, because it has zero runtime effect and silences the one
101
+ * type-level signal there was.
102
+ *
103
+ * `detail` is a `JsonObject` off the wire, so narrowing is genuinely needed;
104
+ * the file already does exactly this for scalars via `toStringValue`. An
105
+ * array whose members are not objects returns undefined rather than being
106
+ * waved through — the timeline renders nothing, which is the honest outcome
107
+ * for data it cannot read.
108
+ */
109
+ function toStatusHistory(value) {
110
+ if (!Array.isArray(value))
111
+ return undefined;
112
+ const ok = value.every((e) => typeof e === "object" && e !== null);
113
+ return ok ? value : undefined;
114
+ }
115
+ export function AdminMoneyCasesView({ children, ...props }) {
116
+ const [detail, setDetail] = useState(null);
117
+ const [resolveTargetId, setResolveTargetId] = useState(null);
118
+ const [dismissTargetId, setDismissTargetId] = useState(null);
119
+ /*
120
+ * Bumped after every mutation. `DataListingView` keys its react-query cache
121
+ * on `queryKey`, so changing the key is what forces a refetch — the reports
122
+ * page calls its own `load()` because it owns its fetch; this one does not.
123
+ */
124
+ const [revision, setRevision] = useState(0);
125
+ if (React.Children.count(children) > 0) {
126
+ return (_jsx(ListingLayout, { portal: "admin", ...props, children: children }));
127
+ }
128
+ const patch = async (id, body) => {
129
+ const res = await fetch(ADMIN_ENDPOINTS.PAYMENT_CASE_BY_ID(id), {
130
+ method: "PATCH",
131
+ headers: { "Content-Type": "application/json" },
132
+ body: JSON.stringify(body),
133
+ });
134
+ if (!res.ok) {
135
+ /*
136
+ * Thrown so `ReviewDecisionModal` stays OPEN and keeps the note the
137
+ * operator just typed. Its catch shows a toast and leaves the dialog up —
138
+ * a decision that did not save must not look like one that did.
139
+ */
140
+ throw new Error(`Could not update this case (${res.status})`);
141
+ }
142
+ setRevision((r) => r + 1);
143
+ setDetail(null);
144
+ };
145
+ const config = {
146
+ portal: "admin",
147
+ title: "Money cases",
148
+ subtitle: "Everything where money is at risk — chargebacks, captured payments with no order, refunds owed, protection claims and grievances. Opened automatically; only a human can close one.",
149
+ emptyLabel: "No open money cases",
150
+ // 🛑 No `searchPlaceholder` / `search` — the endpoint does not read `q`.
151
+ filterKeys: ["status", "kind", "severity"],
152
+ defaultSort: sortBy("lastObservedAt", "DESC"),
153
+ queryKey: ["admin", "payment-cases", "listing", String(revision)],
154
+ endpoint: ADMIN_ENDPOINTS.PAYMENT_CASES,
155
+ /*
156
+ * ── Two traps avoided here, both measured rather than assumed ──────────
157
+ *
158
+ * 🛑 THERE IS NO "SORT BY SEVERITY" OPTION, even though `severity` is
159
+ * `canSort: true` and the option is the obvious one to offer. It stores the
160
+ * STRINGS `error` / `warning` / `info`, so Firestore orders them
161
+ * alphabetically — and `DESC` therefore yields **warning, info, error**,
162
+ * putting the most urgent cases LAST. A sort that silently inverts the
163
+ * thing it claims to rank is worse than no sort (Root Cause #63), and it
164
+ * would be believed. `PAYMENT_CASE_SEVERITY_RANK` exists in TypeScript but
165
+ * is not a stored field, so there is nothing to order by; the severity
166
+ * FILTER is the correct control and it is in the panel.
167
+ *
168
+ * 🛑 The two optional-field sorts NAME their own exclusion. `dueAt` and
169
+ * `amountAtRisk` are both optional, and a Firestore `orderBy` excludes
170
+ * every document that LACKS the field (Root Cause #100) — so these sorts
171
+ * genuinely do shrink the list. For these two that is the right semantics
172
+ * ("soonest deadline" is a question about dated cases), but the shrinking
173
+ * must be stated: an unexplained shorter list is how someone concludes the
174
+ * queue is empty when it is not.
175
+ */
176
+ sortOptions: [
177
+ { value: sortBy("lastObservedAt", "DESC"), label: "Most recently seen" },
178
+ { value: sortBy("lastObservedAt", "ASC"), label: "Longest unseen" },
179
+ { value: sortBy("dueAt", "ASC"), label: "Soonest deadline (dated cases only)" },
180
+ { value: sortBy("amountAtRisk", "DESC"), label: "Largest amount (money cases only)" },
181
+ { value: sortBy("observedCount", "DESC"), label: "Most often re-seen" },
182
+ { value: sortBy("createdAt", "DESC"), label: "Newest" },
183
+ { value: sortBy("createdAt", "ASC"), label: "Oldest" },
184
+ ],
185
+ mapRows: (response) => toRecordArray(response.items).map((item, index) => {
186
+ const kind = toStringValue(item.kind, "unknown");
187
+ const observed = typeof item.observedCount === "number" ? item.observedCount : 1;
188
+ const amount = money(item.amountAtRisk);
189
+ const due = toStringValue(item.dueAt, "");
190
+ return {
191
+ id: toStringValue(item.id, `case-${index}`),
192
+ primary: toStringValue(item.title, KIND_LABEL[kind] ?? kind),
193
+ secondary: [
194
+ KIND_LABEL[kind] ?? kind,
195
+ amount ? `${amount} at risk` : null,
196
+ // An external deadline is the one thing worth putting in a row.
197
+ due ? `due ${new Date(due).toLocaleString()}` : null,
198
+ // Only mentioned when it is informative — "seen once" is noise.
199
+ observed > 1 ? `seen ${observed}×` : null,
200
+ ]
201
+ .filter(Boolean)
202
+ .join(" · "),
203
+ status: toStringValue(item.status, "open"),
204
+ updatedAt: toRelativeDate(item.lastObservedAt ?? item.createdAt),
205
+ _raw: item,
206
+ };
207
+ }),
208
+ getTotal: (response, mappedRows) => typeof response.meta?.total === "number" ? response.meta.total : mappedRows.length,
209
+ onRowClick: (row) => setDetail(row._raw),
210
+ buildFilters: (state) => {
211
+ const parts = [];
212
+ if (state.status && state.status !== "All")
213
+ parts.push(sieveFilter("status", SIEVE_OP.EQ, state.status));
214
+ if (state.kind && state.kind !== "All")
215
+ parts.push(sieveFilter("kind", SIEVE_OP.EQ, state.kind));
216
+ if (state.severity && state.severity !== "All")
217
+ parts.push(sieveFilter("severity", SIEVE_OP.EQ, state.severity));
218
+ return parts.length > 0 ? parts.join(",") : undefined;
219
+ },
220
+ renderRowActions: (row) => {
221
+ const status = row.status;
222
+ const closed = status === "actioned" || status === "dismissed";
223
+ return (_jsx(RowActionMenu, { actions: [
224
+ { label: "View details", onClick: () => setDetail(row._raw) },
225
+ /*
226
+ * "Take" needs no note — it records that someone is looking, which
227
+ * the schema's own `superRefine` exempts from the resolution floor.
228
+ * Hidden once closed: re-opening a closed case is not a thing this
229
+ * surface offers, because `resolve()` is one-way by design.
230
+ */
231
+ ...(closed
232
+ ? []
233
+ : [
234
+ {
235
+ label: status === "under-review" ? "Already taken" : "Take",
236
+ onClick: () => patch(row.id, { status: "under-review" }),
237
+ disabled: status === "under-review",
238
+ },
239
+ { label: "Resolve", onClick: () => setResolveTargetId(row.id) },
240
+ { label: "Dismiss", onClick: () => setDismissTargetId(row.id) },
241
+ ]),
242
+ ] }));
243
+ },
244
+ renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(Stack, { gap: "md", children: [_jsx(FilterChipGroup, { label: "Status", tabs: ADMIN_PAYMENT_CASE_STATUS_TABS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }), _jsx(FilterChipGroup, { label: "Severity", tabs: ADMIN_PAYMENT_CASE_SEVERITY_TABS, value: pendingFilters.severity ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, severity: id })) }), _jsx(FilterChipGroup, { label: "Kind", tabs: ADMIN_PAYMENT_CASE_KIND_TABS, value: pendingFilters.kind ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, kind: id })) })] })),
245
+ };
246
+ const detailKind = detail ? toStringValue(detail.kind, "") : "";
247
+ const detailStatus = detail ? toStringValue(detail.status, "") : "";
248
+ const selfHealed = detail ? toStringValue(detail.selfHealedAt, "") : "";
249
+ return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(RecordDetailModal, { isOpen: detail !== null, onClose: () => setDetail(null), title: detail ? toStringValue(detail.title, "Money case") : "Money case", badges: detail
250
+ ? [
251
+ { label: detailStatus || "open" },
252
+ { label: KIND_LABEL[detailKind] ?? detailKind },
253
+ { label: toStringValue(detail.severity, "info") },
254
+ ]
255
+ : undefined, description: detail ? toStringValue(detail.detail, "") : undefined, fields: detail
256
+ ? [
257
+ { label: "Case id", value: toStringValue(detail.id, "") },
258
+ { label: "Subject", value: `${toStringValue(detail.entityType, "")} ${toStringValue(detail.entityId, "")}` },
259
+ { label: "Amount at risk", value: money(detail.amountAtRisk) ?? "—" },
260
+ {
261
+ label: "External deadline",
262
+ value: toStringValue(detail.dueAt, "") || "none — this case has no clock",
263
+ },
264
+ {
265
+ label: "Times observed",
266
+ value: String(detail.observedCount ?? 1),
267
+ },
268
+ { label: "Last seen", value: toStringValue(detail.lastObservedAt, "") },
269
+ { label: "Assigned to", value: toStringValue(detail.assignedTo, "") || "—" },
270
+ { label: "Gateway payment", value: toStringValue(detail.gatewayPaymentId, "") || "—" },
271
+ { label: "Resolution", value: toStringValue(detail.resolution, "") || "—" },
272
+ ]
273
+ : undefined,
274
+ /*
275
+ * 🛑 `selfHealedAt` is rendered as a QUESTION, never as a resolution.
276
+ *
277
+ * A reconciler that stops observing a problem writes this field and
278
+ * nothing else — the case stays `open` on purpose. "The symptom went
279
+ * away" and "a human understands why" are different facts, and on money
280
+ * only the second one closes anything: a self-healed `missing_order`
281
+ * might mean the retry worked, or might mean somebody refunded it by
282
+ * hand and the order will never exist.
283
+ */
284
+ extra: detail ? (_jsxs(Stack, { gap: "md", children: [selfHealed ? (_jsx(Row, { surface: "info-surface", padding: "sm", rounded: "default", children: _jsxs(Text, { size: "sm", color: "info", children: ["A reconciler no longer sees this problem (as of", " ", new Date(selfHealed).toLocaleString(), "). That is not a resolution \u2014 confirm what happened, then resolve or dismiss it."] }) })) : null, _jsx(RecordStatusTimeline, { entries: toStatusHistory(detail.statusHistory), truncatedCount: typeof detail.statusHistoryTruncated === "number"
285
+ ? detail.statusHistoryTruncated
286
+ : undefined, emptyLabel: "Opened automatically; nothing has happened to it yet" })] })) : undefined, footer: detail && detailStatus !== "actioned" && detailStatus !== "dismissed" ? (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", size: "sm", onClick: () => setResolveTargetId(toStringValue(detail.id, "")), children: "Resolve" }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => setDismissTargetId(toStringValue(detail.id, "")), children: "Dismiss" })] })) : undefined }), _jsx(ReviewDecisionModal, { isOpen: resolveTargetId !== null, onClose: () => setResolveTargetId(null), title: "Resolve this case", schema: paymentCaseResolveFormSchema, status: "actioned", noteField: "resolution", noteLabel: "What did you do?", noteHelp: "Required. The next person reading this case has only what you write here.", notePlaceholder: "e.g. Refunded \u20B92,511.80 to the buyer from the Razorpay dashboard; the order could not be placed because the address was missing.", confirmLabel: "Resolve case", onConfirm: (values) => patch(resolveTargetId, values) }), _jsx(ReviewDecisionModal, { isOpen: dismissTargetId !== null, onClose: () => setDismissTargetId(null), title: "Dismiss this case", schema: paymentCaseResolveFormSchema, status: "dismissed", noteField: "resolution", noteLabel: "Why is nothing wrong here?", noteHelp: "Required. A dismissed case with no reason reads identically to one nobody looked at.", notePlaceholder: "e.g. Duplicate of the event two rows above \u2014 same payment id, already refunded.", confirmLabel: "Dismiss case", onConfirm: (values) => patch(dismissTargetId, values) })] }));
287
+ }