@mohasinac/appkit 2.7.59 → 2.8.1

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 (324) hide show
  1. package/dist/_internal/client/features/filters/filter-load-options.d.ts +4 -5
  2. package/dist/_internal/server/features/auctions/og.js +8 -32
  3. package/dist/_internal/server/features/blog/og.js +10 -49
  4. package/dist/_internal/server/features/checkout/actions.js +6 -0
  5. package/dist/_internal/server/features/classified/og.js +9 -51
  6. package/dist/_internal/server/features/digital-code/actions.d.ts +11 -0
  7. package/dist/_internal/server/features/digital-code/actions.js +30 -0
  8. package/dist/_internal/server/features/digital-code/index.d.ts +1 -0
  9. package/dist/_internal/server/features/digital-code/index.js +1 -0
  10. package/dist/_internal/server/features/digital-code/og.js +9 -51
  11. package/dist/_internal/server/features/events/og.js +10 -49
  12. package/dist/_internal/server/features/item-requests/data.d.ts +17 -0
  13. package/dist/_internal/server/features/item-requests/data.js +20 -0
  14. package/dist/_internal/server/features/item-requests/index.d.ts +2 -0
  15. package/dist/_internal/server/features/item-requests/index.js +2 -0
  16. package/dist/_internal/server/features/item-requests/og.d.ts +40 -0
  17. package/dist/_internal/server/features/item-requests/og.js +136 -0
  18. package/dist/_internal/server/features/live/actions.d.ts +5 -0
  19. package/dist/_internal/server/features/live/actions.js +24 -0
  20. package/dist/_internal/server/features/live/index.d.ts +1 -0
  21. package/dist/_internal/server/features/live/index.js +1 -0
  22. package/dist/_internal/server/features/live/og.js +9 -51
  23. package/dist/_internal/server/features/media/contextGuards.js +19 -8
  24. package/dist/_internal/server/features/pre-orders/og.js +8 -32
  25. package/dist/_internal/server/features/prize-draws/data.d.ts +17 -0
  26. package/dist/_internal/server/features/prize-draws/data.js +20 -0
  27. package/dist/_internal/server/features/prize-draws/index.d.ts +2 -0
  28. package/dist/_internal/server/features/prize-draws/index.js +2 -0
  29. package/dist/_internal/server/features/prize-draws/og.d.ts +30 -0
  30. package/dist/_internal/server/features/prize-draws/og.js +50 -0
  31. package/dist/_internal/server/features/products/og.js +8 -33
  32. package/dist/_internal/server/features/seo/og-layout.d.ts +42 -0
  33. package/dist/_internal/server/features/seo/og-layout.js +69 -0
  34. package/dist/_internal/server/features/stores/og.js +8 -41
  35. package/dist/_internal/server/features/sublisting-categories/og.js +11 -42
  36. package/dist/client.d.ts +10 -6
  37. package/dist/client.js +7 -3
  38. package/dist/constants/index.d.ts +4 -0
  39. package/dist/constants/index.js +2 -0
  40. package/dist/constants/notification-types.d.ts +20 -0
  41. package/dist/constants/notification-types.js +37 -0
  42. package/dist/constants/pagination-presets.d.ts +39 -0
  43. package/dist/constants/pagination-presets.js +38 -0
  44. package/dist/errors/messages.d.ts +0 -4
  45. package/dist/errors/messages.js +0 -4
  46. package/dist/features/about/components/PublicProfileView.js +8 -8
  47. package/dist/features/account/components/UserOffersPanel.js +1 -1
  48. package/dist/features/account/components/UserSupportView.d.ts +1 -2
  49. package/dist/features/account/components/UserSupportView.js +9 -1
  50. package/dist/features/admin/actions/admin-actions.js +16 -1
  51. package/dist/features/admin/components/AdminAllEventEntriesView.d.ts +2 -3
  52. package/dist/features/admin/components/AdminAllEventEntriesView.js +50 -83
  53. package/dist/features/admin/components/AdminBidsView.d.ts +2 -3
  54. package/dist/features/admin/components/AdminBidsView.js +64 -98
  55. package/dist/features/admin/components/AdminBlogView.d.ts +3 -7
  56. package/dist/features/admin/components/AdminBlogView.js +53 -83
  57. package/dist/features/admin/components/AdminBrandsView.d.ts +2 -3
  58. package/dist/features/admin/components/AdminBrandsView.js +84 -83
  59. package/dist/features/admin/components/AdminBundlesView.js +82 -125
  60. package/dist/features/admin/components/AdminCarouselView.d.ts +2 -2
  61. package/dist/features/admin/components/AdminCarouselView.js +17 -52
  62. package/dist/features/admin/components/AdminCartsView.d.ts +2 -3
  63. package/dist/features/admin/components/AdminCartsView.js +39 -88
  64. package/dist/features/admin/components/AdminCategoriesView.d.ts +3 -3
  65. package/dist/features/admin/components/AdminCategoriesView.js +98 -92
  66. package/dist/features/admin/components/AdminCategoryEditorView.js +2 -2
  67. package/dist/features/admin/components/AdminClassifiedView.d.ts +3 -0
  68. package/dist/features/admin/components/AdminClassifiedView.js +44 -0
  69. package/dist/features/admin/components/AdminContactView.d.ts +2 -2
  70. package/dist/features/admin/components/AdminContactView.js +104 -111
  71. package/dist/features/admin/components/AdminCouponsView.d.ts +3 -6
  72. package/dist/features/admin/components/AdminCouponsView.js +66 -86
  73. package/dist/features/admin/components/AdminDigitalCodesView.d.ts +3 -0
  74. package/dist/features/admin/components/AdminDigitalCodesView.js +51 -0
  75. package/dist/features/admin/components/AdminFaqsView.d.ts +4 -4
  76. package/dist/features/admin/components/AdminFaqsView.js +77 -33
  77. package/dist/features/admin/components/AdminFeaturesView.d.ts +2 -3
  78. package/dist/features/admin/components/AdminFeaturesView.js +57 -70
  79. package/dist/features/admin/components/AdminGroupedListingsView.d.ts +3 -0
  80. package/dist/features/admin/components/AdminGroupedListingsView.js +43 -0
  81. package/dist/features/admin/components/AdminHistoryView.d.ts +2 -3
  82. package/dist/features/admin/components/AdminHistoryView.js +35 -52
  83. package/dist/features/admin/components/AdminListingScaffold.d.ts +2 -2
  84. package/dist/features/admin/components/AdminListingScaffold.js +3 -3
  85. package/dist/features/admin/components/AdminLiveView.d.ts +3 -0
  86. package/dist/features/admin/components/AdminLiveView.js +50 -0
  87. package/dist/features/admin/components/AdminNewsletterView.d.ts +2 -2
  88. package/dist/features/admin/components/AdminNewsletterView.js +67 -97
  89. package/dist/features/admin/components/AdminNotificationsView.d.ts +2 -3
  90. package/dist/features/admin/components/AdminNotificationsView.js +67 -93
  91. package/dist/features/admin/components/AdminOrderEditorView.js +10 -10
  92. package/dist/features/admin/components/AdminOrdersView.d.ts +2 -3
  93. package/dist/features/admin/components/AdminOrdersView.js +93 -107
  94. package/dist/features/admin/components/AdminPayoutsView.d.ts +2 -3
  95. package/dist/features/admin/components/AdminPayoutsView.js +51 -91
  96. package/dist/features/admin/components/AdminPrizeDrawsView.d.ts +2 -3
  97. package/dist/features/admin/components/AdminPrizeDrawsView.js +39 -76
  98. package/dist/features/admin/components/AdminProductEditorView.js +3 -3
  99. package/dist/features/admin/components/AdminProductsView.d.ts +4 -4
  100. package/dist/features/admin/components/AdminProductsView.js +167 -163
  101. package/dist/features/admin/components/AdminReturnRequestsView.d.ts +1 -1
  102. package/dist/features/admin/components/AdminReturnRequestsView.js +64 -66
  103. package/dist/features/admin/components/AdminReviewsView.d.ts +3 -7
  104. package/dist/features/admin/components/AdminReviewsView.js +94 -110
  105. package/dist/features/admin/components/AdminScammersView.d.ts +2 -3
  106. package/dist/features/admin/components/AdminScammersView.js +53 -97
  107. package/dist/features/admin/components/AdminSectionsView.js +1 -1
  108. package/dist/features/admin/components/AdminSessionsView.d.ts +2 -3
  109. package/dist/features/admin/components/AdminSessionsView.js +62 -89
  110. package/dist/features/admin/components/AdminSiteSettingsView.js +4 -5
  111. package/dist/features/admin/components/AdminStoreAddressesView.d.ts +1 -1
  112. package/dist/features/admin/components/AdminStoreAddressesView.js +39 -53
  113. package/dist/features/admin/components/AdminStoreEditorView.js +21 -8
  114. package/dist/features/admin/components/AdminStoresView.d.ts +2 -3
  115. package/dist/features/admin/components/AdminStoresView.js +67 -99
  116. package/dist/features/admin/components/AdminSublistingCategoriesView.d.ts +1 -1
  117. package/dist/features/admin/components/AdminSublistingCategoriesView.js +28 -44
  118. package/dist/features/admin/components/AdminSupportTicketDetailView.d.ts +10 -1
  119. package/dist/features/admin/components/AdminSupportTicketDetailView.js +191 -5
  120. package/dist/features/admin/components/AdminSupportTicketsView.d.ts +2 -3
  121. package/dist/features/admin/components/AdminSupportTicketsView.js +65 -96
  122. package/dist/features/admin/components/AdminTeamView.d.ts +2 -2
  123. package/dist/features/admin/components/AdminTeamView.js +40 -74
  124. package/dist/features/admin/components/AdminUserEditorView.d.ts +11 -1
  125. package/dist/features/admin/components/AdminUserEditorView.js +77 -7
  126. package/dist/features/admin/components/AdminUsersView.d.ts +2 -3
  127. package/dist/features/admin/components/AdminUsersView.js +108 -100
  128. package/dist/features/admin/components/AdminViewCards.d.ts +1 -1
  129. package/dist/features/admin/components/AdminViewCards.js +15 -15
  130. package/dist/features/admin/components/AdminWishlistsView.d.ts +2 -3
  131. package/dist/features/admin/components/AdminWishlistsView.js +36 -62
  132. package/dist/features/admin/components/DataListingView.d.ts +122 -0
  133. package/dist/features/admin/components/DataListingView.js +66 -0
  134. package/dist/features/admin/components/index.d.ts +10 -4
  135. package/dist/features/admin/components/index.js +6 -2
  136. package/dist/features/admin/constants/filter-tabs.d.ts +23 -17
  137. package/dist/features/admin/constants/filter-tabs.js +21 -17
  138. package/dist/features/admin/hooks/useAdminListing.d.ts +1 -0
  139. package/dist/features/admin/hooks/useAdminListing.js +1 -1
  140. package/dist/features/admin/schemas/firestore.js +6 -7
  141. package/dist/features/auctions/server.d.ts +0 -1
  142. package/dist/features/auctions/server.js +0 -1
  143. package/dist/features/auth/actions/realtime-token-actions.js +1 -1
  144. package/dist/features/auth/repository/user.repository.js +1 -1
  145. package/dist/features/blog/components/BlogFeaturedCard.js +1 -0
  146. package/dist/features/cart/repository/cart.repository.d.ts +4 -1
  147. package/dist/features/cart/repository/cart.repository.js +12 -0
  148. package/dist/features/checkout/hooks/useCheckoutApi.d.ts +0 -2
  149. package/dist/features/checkout/index.d.ts +1 -1
  150. package/dist/features/events/components/AdminEventEditorView.js +10 -13
  151. package/dist/features/events/components/AdminEventsView.d.ts +3 -3
  152. package/dist/features/events/components/AdminEventsView.js +50 -86
  153. package/dist/features/events/components/EventCard.js +1 -0
  154. package/dist/features/events/components/EventOfferCard.d.ts +19 -0
  155. package/dist/features/events/components/EventOfferCard.js +29 -0
  156. package/dist/features/events/components/EventRaffleEntryForm.d.ts +25 -0
  157. package/dist/features/events/components/EventRaffleEntryForm.js +37 -0
  158. package/dist/features/events/components/EventRafflesSection.d.ts +1 -4
  159. package/dist/features/events/components/EventRafflesSection.js +17 -6
  160. package/dist/features/events/components/EventSaleBanner.d.ts +21 -0
  161. package/dist/features/events/components/EventSaleBanner.js +18 -0
  162. package/dist/features/events/components/index.d.ts +6 -0
  163. package/dist/features/events/components/index.js +4 -0
  164. package/dist/features/events/repository/event-entry.repository.d.ts +5 -0
  165. package/dist/features/events/repository/event-entry.repository.js +7 -0
  166. package/dist/features/faq/components/FAQPageContent.js +1 -0
  167. package/dist/features/filters/AsyncFacetSection.d.ts +1 -1
  168. package/dist/features/homepage/components/AdvertisementBanner.js +6 -6
  169. package/dist/features/homepage/components/FAQSection.d.ts +0 -5
  170. package/dist/features/homepage/components/HomepageSkeleton.js +2 -2
  171. package/dist/features/homepage/components/WelcomeSection.js +3 -3
  172. package/dist/features/homepage/lib/live-stats.js +1 -1
  173. package/dist/features/homepage/schemas/firestore.d.ts +0 -2
  174. package/dist/features/layout/TitleBar.js +1 -0
  175. package/dist/features/layout/index.d.ts +0 -2
  176. package/dist/features/layout/index.js +0 -1
  177. package/dist/features/pre-orders/server.d.ts +0 -1
  178. package/dist/features/pre-orders/server.js +0 -1
  179. package/dist/features/products/components/GroupSettingsPanel.js +2 -2
  180. package/dist/features/products/components/PrizeDrawItemsEditor.js +2 -2
  181. package/dist/features/products/components/PrizeDrawsSection.d.ts +1 -4
  182. package/dist/features/products/components/PrizeDrawsSection.js +17 -6
  183. package/dist/features/products/components/PrizeRevealModal.js +1 -1
  184. package/dist/features/products/components/ProductCardMetadataSection.d.ts +11 -0
  185. package/dist/features/products/components/ProductCardMetadataSection.js +25 -0
  186. package/dist/features/products/components/ProductDetailPageView.js +3 -1
  187. package/dist/features/products/components/ProductFeaturesSelector.js +1 -1
  188. package/dist/features/products/components/ProductGradingTab.d.ts +13 -0
  189. package/dist/features/products/components/ProductGradingTab.js +25 -0
  190. package/dist/features/products/components/ProductGrid.js +15 -2
  191. package/dist/features/products/components/ProductTabsShell.d.ts +5 -1
  192. package/dist/features/products/components/ProductTabsShell.js +6 -1
  193. package/dist/features/products/components/index.d.ts +4 -0
  194. package/dist/features/products/components/index.js +3 -0
  195. package/dist/features/products/constants/action-defs.d.ts +5 -0
  196. package/dist/features/products/constants/action-defs.js +52 -32
  197. package/dist/features/products/constants/sieve.d.ts +24 -4
  198. package/dist/features/products/constants/sieve.js +20 -11
  199. package/dist/features/products/schemas/firestore.d.ts +17 -0
  200. package/dist/features/products/schemas/product-features.validators.d.ts +2 -2
  201. package/dist/features/products/schemas/product-templates.d.ts +2 -4
  202. package/dist/features/products/types/index.d.ts +4 -0
  203. package/dist/features/promotions/components/CouponsIndexListing.js +4 -4
  204. package/dist/features/promotions/server.d.ts +0 -1
  205. package/dist/features/promotions/server.js +0 -1
  206. package/dist/features/reviews/components/ReviewDetailShell.js +3 -3
  207. package/dist/features/search/api/route.js +44 -1
  208. package/dist/features/search/components/Search.js +2 -0
  209. package/dist/features/search/hooks/useNavSuggestions.d.ts +5 -1
  210. package/dist/features/search/hooks/useNavSuggestions.js +31 -4
  211. package/dist/features/seller/components/BrandInlineSelect.js +2 -2
  212. package/dist/features/seller/components/CategoryInlineSelect.js +2 -2
  213. package/dist/features/seller/components/SellerAddressesView.js +4 -5
  214. package/dist/features/seller/components/SellerAuctionsView.d.ts +3 -3
  215. package/dist/features/seller/components/SellerAuctionsView.js +60 -90
  216. package/dist/features/seller/components/SellerBidsView.js +1 -1
  217. package/dist/features/seller/components/SellerBundlesView.js +64 -89
  218. package/dist/features/seller/components/SellerClassifiedView.js +67 -90
  219. package/dist/features/seller/components/SellerCouponEditorView.js +1 -1
  220. package/dist/features/seller/components/SellerCouponsView.d.ts +2 -2
  221. package/dist/features/seller/components/SellerCouponsView.js +45 -84
  222. package/dist/features/seller/components/SellerDigitalCodesView.js +63 -88
  223. package/dist/features/seller/components/SellerGroupedListingsView.js +33 -49
  224. package/dist/features/seller/components/SellerLiveView.js +63 -84
  225. package/dist/features/seller/components/SellerOffersPanel.js +1 -1
  226. package/dist/features/seller/components/SellerOffersView.d.ts +2 -2
  227. package/dist/features/seller/components/SellerOffersView.js +37 -69
  228. package/dist/features/seller/components/SellerOrdersView.d.ts +2 -2
  229. package/dist/features/seller/components/SellerOrdersView.js +4 -4
  230. package/dist/features/seller/components/SellerPayoutMethodsView.js +1 -1
  231. package/dist/features/seller/components/SellerPayoutsView.d.ts +2 -2
  232. package/dist/features/seller/components/SellerPayoutsView.js +34 -68
  233. package/dist/features/seller/components/SellerPreOrdersView.d.ts +2 -2
  234. package/dist/features/seller/components/SellerPreOrdersView.js +49 -82
  235. package/dist/features/seller/components/SellerPrizeDrawsView.d.ts +2 -2
  236. package/dist/features/seller/components/SellerPrizeDrawsView.js +49 -82
  237. package/dist/features/seller/components/SellerProductShell.d.ts +1 -1
  238. package/dist/features/seller/components/SellerProductsView.d.ts +2 -2
  239. package/dist/features/seller/components/SellerProductsView.js +15 -10
  240. package/dist/features/seller/components/SellerShippingConfigsView.js +1 -1
  241. package/dist/features/seller/components/SellerSidebar.d.ts +0 -4
  242. package/dist/features/seller/components/SellerSidebar.js +0 -2
  243. package/dist/features/seller/components/SellerStoreCategoriesView.js +1 -1
  244. package/dist/features/seller/components/SellerTemplatesView.js +2 -2
  245. package/dist/features/seller/components/SellersListView.d.ts +1 -2
  246. package/dist/features/seller/components/analytics/SellerAnalyticsStats.d.ts +5 -0
  247. package/dist/features/seller/components/analytics/SellerAnalyticsStats.js +2 -8
  248. package/dist/features/seller/components/index.d.ts +0 -3
  249. package/dist/features/seller/components/index.js +0 -2
  250. package/dist/features/seller/server.d.ts +0 -1
  251. package/dist/features/seller/server.js +0 -1
  252. package/dist/features/shell/FormShell.d.ts +1 -1
  253. package/dist/features/shell/FormShell.js +7 -4
  254. package/dist/features/shell/field-groups/ImageFieldGroup.d.ts +18 -0
  255. package/dist/features/shell/field-groups/ImageFieldGroup.js +15 -0
  256. package/dist/features/shell/field-groups/SeoFieldGroup.d.ts +22 -0
  257. package/dist/features/shell/field-groups/SeoFieldGroup.js +16 -0
  258. package/dist/features/shell/field-groups/StatusFieldGroup.d.ts +35 -0
  259. package/dist/features/shell/field-groups/StatusFieldGroup.js +16 -0
  260. package/dist/features/shell/field-groups/TitleDescriptionGroup.d.ts +40 -0
  261. package/dist/features/shell/field-groups/TitleDescriptionGroup.js +16 -0
  262. package/dist/features/shell/field-groups/index.d.ts +13 -0
  263. package/dist/features/shell/field-groups/index.js +9 -0
  264. package/dist/features/shell/index.d.ts +2 -0
  265. package/dist/features/shell/index.js +1 -0
  266. package/dist/features/stores/components/StoreCapabilitiesGuideView.d.ts +1 -2
  267. package/dist/features/stores/components/StoreFinanceGuideView.d.ts +1 -2
  268. package/dist/features/stores/components/StoreHeader.js +2 -1
  269. package/dist/features/stores/components/StoreListingsGuideView.d.ts +1 -2
  270. package/dist/features/stores/components/StoreOrdersGuideView.d.ts +1 -2
  271. package/dist/features/stores/components/StoreScopedSearch.d.ts +16 -0
  272. package/dist/features/stores/components/StoreScopedSearch.js +27 -0
  273. package/dist/features/stores/components/StoreSettingsGuideView.d.ts +1 -2
  274. package/dist/features/stores/server.d.ts +0 -1
  275. package/dist/features/stores/server.js +0 -1
  276. package/dist/features/support/schemas/firestore.d.ts +22 -1
  277. package/dist/features/support/schemas/firestore.js +10 -0
  278. package/dist/features/wishlist/server.d.ts +0 -1
  279. package/dist/features/wishlist/server.js +0 -1
  280. package/dist/index.d.ts +9 -27
  281. package/dist/index.js +14 -50
  282. package/dist/next/routing/route-map.d.ts +8 -0
  283. package/dist/next/routing/route-map.js +4 -0
  284. package/dist/react/hooks/useListingTypeFlags.d.ts +32 -0
  285. package/dist/react/hooks/useListingTypeFlags.js +19 -0
  286. package/dist/security/index.d.ts +1 -1
  287. package/dist/security/index.js +1 -1
  288. package/dist/security/pii-redact.d.ts +8 -0
  289. package/dist/security/pii-redact.js +10 -1
  290. package/dist/seed/grouped-listings-seed-data.d.ts +4 -0
  291. package/dist/seed/products-preorders-seed-data.d.ts +4 -0
  292. package/dist/seed/products-prize-draws-seed-data.js +3 -0
  293. package/dist/seed/site-settings-seed-data.js +5 -5
  294. package/dist/seed/sub-listings-seed-data.d.ts +4 -0
  295. package/dist/server.d.ts +2 -0
  296. package/dist/server.js +4 -0
  297. package/dist/styles.css +54 -395
  298. package/dist/tailwind-utilities.css +1 -1
  299. package/dist/ui/components/BaseListingCard.d.ts +10 -0
  300. package/dist/ui/components/BaseListingCard.js +17 -1
  301. package/dist/ui/components/DetailPageGallery.d.ts +32 -0
  302. package/dist/ui/components/DetailPageGallery.js +47 -0
  303. package/dist/ui/components/DetailPageHero.d.ts +30 -0
  304. package/dist/ui/components/DetailPageHero.js +22 -0
  305. package/dist/ui/components/DetailPageTabs.d.ts +34 -0
  306. package/dist/ui/components/DetailPageTabs.js +38 -0
  307. package/dist/ui/components/HorizontalScroller.style.css +15 -2
  308. package/dist/ui/components/ListingLayout.d.ts +11 -2
  309. package/dist/ui/components/ListingLayout.js +12 -6
  310. package/dist/ui/components/PaginatedSelect.d.ts +66 -0
  311. package/dist/ui/components/PaginatedSelect.js +201 -0
  312. package/dist/ui/components/PaginatedSelect.style.css +254 -0
  313. package/dist/ui/components/Semantic.d.ts +0 -4
  314. package/dist/ui/components/Semantic.js +0 -2
  315. package/dist/ui/components/SettingsSection.d.ts +47 -0
  316. package/dist/ui/components/SettingsSection.js +38 -0
  317. package/dist/ui/components/index.style.css +1 -4
  318. package/dist/ui/index.d.ts +12 -14
  319. package/dist/ui/index.js +6 -7
  320. package/dist/utils/id-generators.d.ts +1 -18
  321. package/dist/utils/id-generators.js +51 -18
  322. package/dist/validation/schemas.d.ts +25 -0
  323. package/dist/validation/schemas.js +28 -0
  324. package/package.json +1 -1
@@ -1,43 +1,28 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import React, { useState, useCallback } from "react";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import React, { useState } from "react";
4
4
  import { useMutation, useQueryClient } from "@tanstack/react-query";
5
- import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
- import { usePanelUrlSync } from "../../../react/hooks/use-panel-url-sync";
7
- import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
8
- import { BulkActionBar, FilterChipGroup, ListingToolbar, Pagination, ListingViewShell, RowActionMenu, useToast, ListingFilterDrawer } from "../../../ui";
9
- import { AdminViewCards } from "./AdminViewCards";
5
+ import { FilterChipGroup, ListingLayout, RowActionMenu, useToast } from "../../../ui";
10
6
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
11
7
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
12
8
  import { ADMIN_STORE_STATUS_TABS } from "../constants/filter-tabs";
13
- import { toRecordArray, toRelativeDate, toStringValue, useAdminListingData, } from "../hooks/useAdminListingData";
9
+ import { toRecordArray, toRelativeDate, toStringValue, } from "../hooks/useAdminListingData";
10
+ import { DataListingView } from "./DataListingView";
14
11
  import { apiClient } from "../../../http";
15
- import { DataTable } from "./DataTable";
16
12
  import { AdminStoreEditorView } from "./AdminStoreEditorView";
17
- import { useBottomActions } from "../../layout";
18
- const PAGE_SIZE = 25;
19
- const FILTER_KEYS = ["status"];
20
- const DEFAULT_SORT = "-createdAt";
21
- const SORT_OPTIONS = [
22
- { value: "-createdAt", label: "Newest" },
23
- { value: "createdAt", label: "Oldest" },
24
- { value: "storeName", label: "Name A–Z" },
25
- ];
26
- const STATUS_OPTIONS = ADMIN_STORE_STATUS_TABS;
27
13
  export function AdminStoresView({ children, ...props }) {
28
- const hasChildren = React.Children.count(children) > 0;
29
- const [view, setView] = useState("table");
14
+ const [editorRow, setEditorRow] = useState(null);
30
15
  const toast = useToast();
31
16
  const queryClient = useQueryClient();
32
- const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
33
- const { openEditPanel, closePanel, isEditOpen, editId } = usePanelUrlSync();
34
17
  const verifyStore = useMutation({
35
18
  mutationFn: (storeId) => apiClient.patch(ADMIN_ENDPOINTS.STORE_BY_ID(storeId), { isVerified: true }),
36
19
  onSuccess: () => {
37
20
  toast.showToast("Store verified.", "success");
38
21
  void queryClient.invalidateQueries({ queryKey: ["admin", "stores", "listing"] });
39
22
  },
40
- onError: () => { toast.showToast("Failed to verify store.", "error"); },
23
+ onError: () => {
24
+ toast.showToast("Failed to verify store.", "error");
25
+ },
41
26
  });
42
27
  const suspendStore = useMutation({
43
28
  mutationFn: (storeId) => apiClient.patch(ADMIN_ENDPOINTS.STORE_BY_ID(storeId), { storeStatus: "suspended" }),
@@ -45,47 +30,27 @@ export function AdminStoresView({ children, ...props }) {
45
30
  toast.showToast("Store suspended.", "success");
46
31
  void queryClient.invalidateQueries({ queryKey: ["admin", "stores", "listing"] });
47
32
  },
48
- onError: () => { toast.showToast("Failed to suspend store.", "error"); },
33
+ onError: () => {
34
+ toast.showToast("Failed to suspend store.", "error");
35
+ },
49
36
  });
50
- const [searchInput, setSearchInput] = useState(table.get("q") || "");
51
- const [filterOpen, setFilterOpen] = useState(false);
52
- const [pendingFilters, setPendingFilters] = useState(() => Object.fromEntries(FILTER_KEYS.map((k) => [k, table.get(k)])));
53
- const openFilters = useCallback(() => {
54
- setPendingFilters(Object.fromEntries(FILTER_KEYS.map((k) => [k, table.get(k)])));
55
- setFilterOpen(true);
56
- }, [table]);
57
- const applyFilters = useCallback(() => {
58
- const updates = { page: "1" };
59
- for (const k of FILTER_KEYS)
60
- updates[k] = pendingFilters[k] ?? "";
61
- table.setMany(updates);
62
- setFilterOpen(false);
63
- }, [pendingFilters, table]);
64
- const clearFilters = useCallback(() => {
65
- setPendingFilters(Object.fromEntries(FILTER_KEYS.map((k) => [k, ""])));
66
- }, []);
67
- const resetAll = useCallback(() => {
68
- const updates = { q: "", sort: "" };
69
- for (const k of FILTER_KEYS)
70
- updates[k] = "";
71
- table.setMany(updates);
72
- setSearchInput("");
73
- }, [table]);
74
- const commitSearch = useCallback(() => {
75
- table.set("q", searchInput.trim());
76
- }, [searchInput, table]);
77
- const activeFilterCount = FILTER_KEYS.filter((k) => !!table.get(k)).length;
78
- const hasActiveState = !!table.get("q") || table.get("sort") !== DEFAULT_SORT || activeFilterCount > 0;
79
- const statusRaw = table.get("status");
80
- const filters = statusRaw && statusRaw !== "All" ? `status==${statusRaw}` : undefined;
81
- const { rows, total, isLoading, errorMessage } = useAdminListingData({
37
+ if (React.Children.count(children) > 0) {
38
+ return (_jsx(ListingLayout, { portal: "admin", ...props, children: children }));
39
+ }
40
+ const config = {
41
+ portal: "admin",
42
+ title: "Stores",
43
+ searchPlaceholder: "Search stores, slugs, or owner names",
44
+ emptyLabel: "No stores found",
45
+ filterKeys: ["status"],
46
+ defaultSort: "-createdAt",
82
47
  queryKey: ["admin", "stores", "listing"],
83
48
  endpoint: ADMIN_ENDPOINTS.STORES,
84
- page: table.getNumber("page", 1),
85
- pageSize: PAGE_SIZE,
86
- sorts: table.get("sort") || DEFAULT_SORT,
87
- filters,
88
- q: table.get("q") || undefined,
49
+ sortOptions: [
50
+ { value: "-createdAt", label: "Newest" },
51
+ { value: "createdAt", label: "Oldest" },
52
+ { value: "storeName", label: "Name A–Z" },
53
+ ],
89
54
  mapRows: (response) => toRecordArray(response.items).map((item, index) => ({
90
55
  id: toStringValue(item.id, `store-${index}`),
91
56
  primary: toStringValue(item.storeName, "Unnamed store"),
@@ -98,42 +63,45 @@ export function AdminStoresView({ children, ...props }) {
98
63
  _raw: item,
99
64
  })),
100
65
  getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
101
- });
102
- const currentPage = table.getNumber("page", 1);
103
- const totalPages = Math.ceil(total / PAGE_SIZE);
104
- const panelRow = editId ? (rows.find((r) => r.id === editId) ?? null) : null;
105
- const selection = useBulkSelection({ items: rows, keyExtractor: (r) => r.id });
106
- if (hasChildren) {
107
- return _jsx(ListingViewShell, { portal: "admin", ...props, children: children });
108
- }
109
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search stores, slugs, or owner names", 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 }), _jsx(BulkActionBar, { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [
110
- { id: "manage", label: ACTIONS.ADMIN["manage-store"].label, variant: "primary", onClick: () => { const id = selection.selectedIds[0]; if (id)
111
- openEditPanel(id); selection.clearSelection(); } },
112
- ] }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-error-surface px-4 py-3 text-sm text-error dark:border-red-900/60", children: errorMessage })), view === "table" ? (_jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No stores found", selectedIds: selection.selectedIdSet, onToggleSelect: selection.toggle, onToggleSelectAll: (next) => next ? selection.setSelectedIds(rows.map(r => r.id)) : selection.clearSelection(), renderRowActions: (row) => {
113
- const sr = row;
114
- const isSuspended = sr.status?.toLowerCase() === "suspended";
115
- const isVerified = Boolean(sr._raw?.isVerified);
116
- useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [
117
- { id: "manage", label: ACTIONS.ADMIN["manage-store"].label, variant: "primary", onClick: () => { const id = selection.selectedIds[0]; if (id)
118
- openEditPanel(id); selection.clearSelection(); } },
119
- ] } } : {});
120
- return (_jsx(RowActionMenu, { actions: [
121
- {
122
- label: ACTIONS.ADMIN["manage-store"].label,
123
- onClick: () => openEditPanel(sr.id),
124
- },
125
- {
126
- label: ACTIONS.ADMIN["verify-store"].label,
127
- onClick: () => verifyStore.mutate(sr.id),
128
- disabled: isVerified || verifyStore.isPending,
129
- },
130
- {
131
- label: ACTIONS.ADMIN["suspend-store"].label,
132
- onClick: () => suspendStore.mutate(sr.id),
133
- disabled: isSuspended || suspendStore.isPending,
134
- },
135
- ] }));
136
- } })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No stores found", onRowClick: (row) => openEditPanel(row.id), selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] }), _jsx(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearFilters, activeCount: activeFilterCount, children: _jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }) })] }), _jsx(AdminStoreEditorView, { open: isEditOpen, onClose: closePanel, storeId: editId ?? undefined, storeName: panelRow?.primary, currentStatus: panelRow?.status?.toLowerCase(), currentIsVerified: Boolean(panelRow?._raw?.isVerified), currentCapabilities: Array.isArray(panelRow?._raw?.capabilities)
137
- ? panelRow._raw.capabilities
66
+ buildFilters: (state) => state.status && state.status !== "All" ? `status==${state.status}` : undefined,
67
+ onRowClick: (row) => setEditorRow(row),
68
+ buildBulkActions: (selection) => [
69
+ {
70
+ id: "manage",
71
+ label: ACTIONS.ADMIN["manage-store"].label,
72
+ variant: "primary",
73
+ onClick: () => {
74
+ const id = selection.selectedIds[0];
75
+ const row = selection.rows.find((r) => r.id === id) ?? null;
76
+ if (row)
77
+ setEditorRow(row);
78
+ selection.clearSelection();
79
+ },
80
+ },
81
+ ],
82
+ renderRowActions: (row) => {
83
+ const isSuspended = row.status?.toLowerCase() === "suspended";
84
+ const isVerified = Boolean(row._raw?.isVerified);
85
+ return (_jsx(RowActionMenu, { actions: [
86
+ {
87
+ label: ACTIONS.ADMIN["manage-store"].label,
88
+ onClick: () => setEditorRow(row),
89
+ },
90
+ {
91
+ label: ACTIONS.ADMIN["verify-store"].label,
92
+ onClick: () => verifyStore.mutate(row.id),
93
+ disabled: isVerified || verifyStore.isPending,
94
+ },
95
+ {
96
+ label: ACTIONS.ADMIN["suspend-store"].label,
97
+ onClick: () => suspendStore.mutate(row.id),
98
+ disabled: isSuspended || suspendStore.isPending,
99
+ },
100
+ ] }));
101
+ },
102
+ renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsx(FilterChipGroup, { label: "Status", tabs: ADMIN_STORE_STATUS_TABS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) })),
103
+ };
104
+ return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(AdminStoreEditorView, { open: Boolean(editorRow), onClose: () => setEditorRow(null), storeId: editorRow?.id, storeName: editorRow?.primary, currentStatus: editorRow?.status?.toLowerCase(), currentIsVerified: Boolean(editorRow?._raw?.isVerified), currentCapabilities: Array.isArray(editorRow?._raw?.capabilities)
105
+ ? editorRow._raw.capabilities
138
106
  : undefined })] }));
139
107
  }
@@ -1,5 +1,5 @@
1
1
  interface AdminSublistingCategoriesViewProps {
2
2
  onBulkDelete?: (ids: string[]) => Promise<void>;
3
3
  }
4
- export declare function AdminSublistingCategoriesView({ onBulkDelete }: AdminSublistingCategoriesViewProps): import("react/jsx-runtime").JSX.Element;
4
+ export declare function AdminSublistingCategoriesView({ onBulkDelete, }: AdminSublistingCategoriesViewProps): import("react/jsx-runtime").JSX.Element;
5
5
  export {};
@@ -1,42 +1,26 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useState, useCallback } from "react";
4
- import { useUrlTable } from "../../../react/hooks/useUrlTable";
5
- import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
6
- import { BulkActionBar, ListingToolbar, Pagination } from "../../../ui";
7
- import { useBottomActions } from "../../layout";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
8
3
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
9
4
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
10
5
  import { buildBulkAction } from "../../../_internal/shared/actions/bulk-helpers";
11
- import { toRecordArray, toRelativeDate, toStringValue, useAdminListingData, } from "../hooks/useAdminListingData";
12
- import { DataTable } from "./DataTable";
13
- const PAGE_SIZE = 25;
14
- const DEFAULT_SORT = "name";
15
- const SORT_OPTIONS = [
16
- { value: "name", label: "Name A–Z" },
17
- { value: "-name", label: "Name Z–A" },
18
- { value: "-productCount", label: "Most listings" },
19
- { value: "-createdAt", label: "Newest" },
20
- ];
21
- export function AdminSublistingCategoriesView({ onBulkDelete }) {
22
- const [view, setView] = useState("table");
23
- const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
24
- const [searchInput, setSearchInput] = useState(table.get("q") || "");
25
- const commitSearch = useCallback(() => {
26
- table.set("q", searchInput.trim());
27
- }, [searchInput, table]);
28
- const resetAll = useCallback(() => {
29
- table.setMany({ q: "", sort: "" });
30
- setSearchInput("");
31
- }, [table]);
32
- const hasActiveState = !!table.get("q") || table.get("sort") !== DEFAULT_SORT;
33
- const { rows, total, isLoading, errorMessage } = useAdminListingData({
6
+ import { toRecordArray, toRelativeDate, toStringValue, } from "../hooks/useAdminListingData";
7
+ import { DataListingView } from "./DataListingView";
8
+ export function AdminSublistingCategoriesView({ onBulkDelete, }) {
9
+ const config = {
10
+ portal: "admin",
11
+ title: "Sub-listing Categories",
12
+ searchPlaceholder: "Search sub-listing categories…",
13
+ emptyLabel: "No sub-listing categories found",
14
+ filterKeys: [],
15
+ defaultSort: "name",
34
16
  queryKey: ["admin", "sublisting-categories", "listing"],
35
17
  endpoint: ADMIN_ENDPOINTS.SUBLISTING_CATEGORIES,
36
- page: table.getNumber("page", 1),
37
- pageSize: PAGE_SIZE,
38
- sorts: table.get("sort") || DEFAULT_SORT,
39
- q: table.get("q") || undefined,
18
+ sortOptions: [
19
+ { value: "name", label: "Name A–Z" },
20
+ { value: "-name", label: "Name Z–A" },
21
+ { value: "-productCount", label: "Most listings" },
22
+ { value: "-createdAt", label: "Newest" },
23
+ ],
40
24
  mapRows: (response) => toRecordArray(response.items).map((item, index) => ({
41
25
  id: toStringValue(item.id, `sc-${index}`),
42
26
  primary: toStringValue(item.name, "Untitled"),
@@ -50,15 +34,15 @@ export function AdminSublistingCategoriesView({ onBulkDelete }) {
50
34
  updatedAt: toRelativeDate(item.updatedAt ?? item.createdAt),
51
35
  })),
52
36
  getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
53
- });
54
- const currentPage = table.getNumber("page", 1);
55
- const totalPages = Math.ceil(total / PAGE_SIZE);
56
- const selection = useBulkSelection({ items: rows ?? [], keyExtractor: (r) => r.id });
57
- const bulkActions = [
58
- ...(onBulkDelete ? [buildBulkAction(ACTIONS.ADMIN["delete-sublisting-category"], async () => { await onBulkDelete(selection.selectedIds); selection.clearSelection(); })] : []),
59
- ];
60
- useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: bulkActions } } : {});
61
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { searchValue: searchInput, searchPlaceholder: "Search sub-listing categories\u2026", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => {
62
- table.set("sort", v);
63
- }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), selection.selectedCount > 0 && bulkActions.length > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-error-surface px-4 py-3 text-sm text-error dark:border-red-900/60", children: errorMessage })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No sub-listing categories found" })] })] }));
37
+ buildFilters: () => undefined,
38
+ buildBulkActions: onBulkDelete
39
+ ? (selection) => [
40
+ buildBulkAction(ACTIONS.ADMIN["delete-sublisting-category"], async () => {
41
+ await onBulkDelete(selection.selectedIds);
42
+ selection.clearSelection();
43
+ }),
44
+ ]
45
+ : undefined,
46
+ };
47
+ return _jsx(DataListingView, { config: config });
64
48
  }
@@ -5,6 +5,13 @@ interface TicketMessageClient {
5
5
  body?: string;
6
6
  createdAt?: string;
7
7
  }
8
+ interface RelatedPartiesClient {
9
+ userId?: string;
10
+ storeId?: string;
11
+ orderId?: string;
12
+ productId?: string;
13
+ bidId?: string;
14
+ }
8
15
  export interface AdminSupportTicketDetailViewProps {
9
16
  open: boolean;
10
17
  onClose: () => void;
@@ -18,6 +25,8 @@ export interface AdminSupportTicketDetailViewProps {
18
25
  messages?: TicketMessageClient[];
19
26
  internalNotes?: string;
20
27
  orderId?: string;
28
+ /** ST-6 — current relatedParties snapshot from the ticket document. */
29
+ relatedParties?: RelatedPartiesClient;
21
30
  }
22
- export declare function AdminSupportTicketDetailView({ open, onClose, ticketId, subject, userDisplayName, category, currentStatus, currentPriority, description, messages, internalNotes, orderId, }: AdminSupportTicketDetailViewProps): import("react/jsx-runtime").JSX.Element;
31
+ export declare function AdminSupportTicketDetailView({ open, onClose, ticketId, subject, userDisplayName, category, currentStatus, currentPriority, description, messages, internalNotes, orderId, relatedParties, }: AdminSupportTicketDetailViewProps): import("react/jsx-runtime").JSX.Element;
23
32
  export {};
@@ -1,8 +1,8 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import React from "react";
4
4
  import { useMutation, useQueryClient } from "@tanstack/react-query";
5
- import { Button, Div, FormActions, Select, SideDrawer, Text, useToast, } from "../../../ui";
5
+ import { Button, Div, FormActions, Input, Row, Select, SideDrawer, Text, Toggle, useToast, } from "../../../ui";
6
6
  import { apiClient } from "../../../http";
7
7
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
8
8
  const STATUS_OPTIONS = [
@@ -30,28 +30,46 @@ const ROLE_LABEL = {
30
30
  support: "Support",
31
31
  admin: "Admin",
32
32
  };
33
- export function AdminSupportTicketDetailView({ open, onClose, ticketId, subject, userDisplayName, category, currentStatus, currentPriority, description, messages = [], internalNotes, orderId, }) {
33
+ export function AdminSupportTicketDetailView({ open, onClose, ticketId, subject, userDisplayName, category, currentStatus, currentPriority, description, messages = [], internalNotes, orderId, relatedParties, }) {
34
34
  const queryClient = useQueryClient();
35
35
  const { showToast } = useToast();
36
36
  const [status, setStatus] = React.useState(currentStatus ?? "open");
37
37
  const [priority, setPriority] = React.useState(currentPriority ?? "normal");
38
38
  const [notes, setNotes] = React.useState(internalNotes ?? "");
39
39
  const [replyBody, setReplyBody] = React.useState("");
40
+ // ST-6 — local edits for the linked-parties panel
41
+ const [parties, setParties] = React.useState(relatedParties ?? {});
40
42
  React.useEffect(() => {
41
43
  if (open) {
42
44
  setStatus(currentStatus ?? "open");
43
45
  setPriority(currentPriority ?? "normal");
44
46
  setNotes(internalNotes ?? "");
45
47
  setReplyBody("");
48
+ setParties(relatedParties ?? {});
46
49
  }
47
- }, [open, currentStatus, currentPriority, internalNotes]);
50
+ }, [open, currentStatus, currentPriority, internalNotes, relatedParties]);
48
51
  const invalidate = () => queryClient.invalidateQueries({ queryKey: ["admin", "support-tickets"] });
52
+ const cleanedParties = React.useMemo(() => {
53
+ const out = {};
54
+ if (parties.userId?.trim())
55
+ out.userId = parties.userId.trim();
56
+ if (parties.storeId?.trim())
57
+ out.storeId = parties.storeId.trim();
58
+ if (parties.orderId?.trim())
59
+ out.orderId = parties.orderId.trim();
60
+ if (parties.productId?.trim())
61
+ out.productId = parties.productId.trim();
62
+ if (parties.bidId?.trim())
63
+ out.bidId = parties.bidId.trim();
64
+ return out;
65
+ }, [parties]);
49
66
  const updateMutation = useMutation({
50
67
  mutationFn: async () => {
51
68
  await apiClient.patch(ADMIN_ENDPOINTS.SUPPORT_TICKET_BY_ID(ticketId), {
52
69
  status,
53
70
  priority,
54
71
  internalNotes: notes || undefined,
72
+ relatedParties: Object.keys(cleanedParties).length > 0 ? cleanedParties : undefined,
55
73
  });
56
74
  },
57
75
  onSuccess: () => {
@@ -77,7 +95,175 @@ export function AdminSupportTicketDetailView({ open, onClose, ticketId, subject,
77
95
  showToast(err?.message ?? "Failed to send reply.", "error");
78
96
  },
79
97
  });
98
+ // ST-4 — Apply Store Change action (only relevant for store_change_request)
99
+ const [storeStatus, setStoreStatus] = React.useState("active");
100
+ const [storeIsVerified, setStoreIsVerified] = React.useState(false);
101
+ const [storeIsFeatured, setStoreIsFeatured] = React.useState(false);
102
+ const linkedStoreId = parties.storeId?.trim();
103
+ const isStoreChangeRequest = category === "store_change_request";
104
+ const applyStoreChange = useMutation({
105
+ mutationFn: async () => {
106
+ if (!linkedStoreId)
107
+ throw new Error("No linked store on this ticket.");
108
+ await apiClient.patch(ADMIN_ENDPOINTS.STORE_BY_ID(linkedStoreId), {
109
+ storeStatus,
110
+ isVerified: storeIsVerified,
111
+ isFeatured: storeIsFeatured,
112
+ });
113
+ },
114
+ onSuccess: () => {
115
+ showToast("Store change applied.", "success");
116
+ // Append an internal note marking the action; non-fatal if it fails.
117
+ apiClient
118
+ .patch(ADMIN_ENDPOINTS.SUPPORT_TICKET_BY_ID(ticketId), {
119
+ internalNotes: (notes ? notes + "\n" : "") +
120
+ `[${new Date().toISOString()}] Applied store change to ${linkedStoreId}: status=${storeStatus}, verified=${storeIsVerified}, featured=${storeIsFeatured}`,
121
+ })
122
+ .catch(() => { });
123
+ invalidate();
124
+ },
125
+ onError: (err) => {
126
+ showToast(err?.message ?? "Failed to apply store change.", "error");
127
+ },
128
+ });
129
+ // ST-3 — Modify Order Items panel (fetches current items on demand, lets
130
+ // admin edit quantity per line + remove lines, then PATCHes the order).
131
+ const [orderItemsOpen, setOrderItemsOpen] = React.useState(false);
132
+ const [orderItems, setOrderItems] = React.useState([]);
133
+ const linkedOrderId = parties.orderId?.trim() || orderId;
134
+ const isOrderModificationRequest = category === "order_modification_request" || category === "order_issue";
135
+ const loadOrderItems = useMutation({
136
+ mutationFn: async () => {
137
+ if (!linkedOrderId)
138
+ throw new Error("No linked order on this ticket.");
139
+ const res = await apiClient.get(ADMIN_ENDPOINTS.ORDER_BY_ID(linkedOrderId));
140
+ const items = Array.isArray(res?.items) ? res.items : [];
141
+ setOrderItems(items.map((it) => ({
142
+ productId: String(it.productId ?? ""),
143
+ productTitle: String(it.productTitle ?? ""),
144
+ quantity: Number(it.quantity ?? 0),
145
+ unitPrice: Number(it.unitPrice ?? 0),
146
+ totalPrice: Number(it.totalPrice ?? 0),
147
+ })));
148
+ setOrderItemsOpen(true);
149
+ },
150
+ onError: (err) => {
151
+ showToast(err?.message ?? "Failed to load order.", "error");
152
+ },
153
+ });
154
+ // ST-5 — Lift Ban actions for unban_request tickets
155
+ const linkedUserId = parties.userId?.trim();
156
+ const isUnbanRequest = category === "unban_request";
157
+ const liftHardBan = useMutation({
158
+ mutationFn: async () => {
159
+ if (!linkedUserId)
160
+ throw new Error("No linked user on this ticket.");
161
+ await apiClient.post(ADMIN_ENDPOINTS.USER_UNBAN(linkedUserId), {});
162
+ },
163
+ onSuccess: () => {
164
+ showToast("Hard ban lifted.", "success");
165
+ apiClient
166
+ .patch(ADMIN_ENDPOINTS.SUPPORT_TICKET_BY_ID(ticketId), {
167
+ internalNotes: (notes ? notes + "\n" : "") +
168
+ `[${new Date().toISOString()}] Lifted hard ban for ${linkedUserId}`,
169
+ status: "resolved",
170
+ })
171
+ .catch(() => { });
172
+ invalidate();
173
+ },
174
+ onError: (err) => {
175
+ showToast(err?.message ?? "Failed to lift hard ban.", "error");
176
+ },
177
+ });
178
+ const liftSoftBanTickets = useMutation({
179
+ mutationFn: async () => {
180
+ if (!linkedUserId)
181
+ throw new Error("No linked user on this ticket.");
182
+ await apiClient.delete(ADMIN_ENDPOINTS.USER_SOFT_BAN_LIFT(linkedUserId, "create_support_tickets"));
183
+ },
184
+ onSuccess: () => {
185
+ showToast("Ticket-creation soft ban lifted.", "success");
186
+ apiClient
187
+ .patch(ADMIN_ENDPOINTS.SUPPORT_TICKET_BY_ID(ticketId), {
188
+ internalNotes: (notes ? notes + "\n" : "") +
189
+ `[${new Date().toISOString()}] Lifted create_support_tickets soft ban for ${linkedUserId}`,
190
+ status: "resolved",
191
+ })
192
+ .catch(() => { });
193
+ invalidate();
194
+ },
195
+ onError: (err) => {
196
+ showToast(err?.message ?? "Failed to lift soft ban.", "error");
197
+ },
198
+ });
199
+ const applyOrderItems = useMutation({
200
+ mutationFn: async () => {
201
+ if (!linkedOrderId)
202
+ throw new Error("No linked order on this ticket.");
203
+ // Recalculate totalPrice per line from quantity × unitPrice so qty edits
204
+ // flow through. Lines with quantity 0 are dropped.
205
+ const items = orderItems
206
+ .filter((it) => it.quantity > 0)
207
+ .map((it) => ({
208
+ productId: it.productId,
209
+ productTitle: it.productTitle,
210
+ quantity: it.quantity,
211
+ unitPrice: it.unitPrice,
212
+ totalPrice: it.quantity * it.unitPrice,
213
+ }));
214
+ await apiClient.patch(ADMIN_ENDPOINTS.ORDER_BY_ID(linkedOrderId), {
215
+ items,
216
+ });
217
+ },
218
+ onSuccess: () => {
219
+ showToast("Order items updated.", "success");
220
+ apiClient
221
+ .patch(ADMIN_ENDPOINTS.SUPPORT_TICKET_BY_ID(ticketId), {
222
+ internalNotes: (notes ? notes + "\n" : "") +
223
+ `[${new Date().toISOString()}] Modified order ${linkedOrderId} items: ${orderItems
224
+ .filter((it) => it.quantity > 0)
225
+ .map((it) => `${it.productId}x${it.quantity}`)
226
+ .join(", ")}`,
227
+ })
228
+ .catch(() => { });
229
+ invalidate();
230
+ setOrderItemsOpen(false);
231
+ },
232
+ onError: (err) => {
233
+ showToast(err?.message ?? "Failed to update order items.", "error");
234
+ },
235
+ });
80
236
  return (_jsx(SideDrawer, { isOpen: open, onClose: onClose, title: subject ?? "Support Ticket", children: _jsxs(Div, { className: "flex flex-col gap-4 p-4", children: [_jsxs(Div, { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: `inline-flex rounded-full px-2.5 py-1 text-xs font-medium ${STATUS_COLOR[currentStatus ?? "open"] ?? STATUS_COLOR.open}`, children: (currentStatus ?? "open").replace(/_/g, " ") }), _jsx("span", { className: "rounded-full bg-zinc-100 px-2.5 py-1 text-xs text-zinc-600 dark:bg-zinc-800 dark:text-zinc-300", children: category }), orderId && (_jsxs("span", { className: "rounded-full bg-zinc-100 px-2.5 py-1 text-xs text-zinc-600 dark:bg-zinc-800 dark:text-zinc-300", children: ["Order: ", orderId] }))] }), _jsxs(Div, { className: "text-sm text-zinc-500 dark:text-zinc-400", children: ["From: ", _jsx("span", { className: "font-medium text-zinc-700 dark:text-zinc-200", children: userDisplayName })] }), description && (_jsxs(Div, { className: "rounded-lg border border-zinc-200 bg-zinc-50 p-3 dark:border-zinc-700 dark:bg-zinc-900/40", children: [_jsx(Text, { className: "mb-1 text-xs font-semibold text-zinc-500 dark:text-zinc-400 uppercase tracking-wide", children: "Description" }), _jsx(Text, { className: "whitespace-pre-wrap text-sm text-zinc-700 dark:text-zinc-200", children: description })] })), messages.length > 0 && (_jsxs(Div, { className: "space-y-2", children: [_jsxs(Text, { className: "text-xs font-semibold text-zinc-500 dark:text-zinc-400 uppercase tracking-wide", children: ["Messages (", messages.length, ")"] }), _jsx("div", { className: "space-y-2 max-h-64 overflow-y-auto", children: messages.map((msg, i) => (_jsxs("div", { className: `rounded-lg p-3 text-sm ${msg.authorRole === "user"
81
237
  ? "bg-zinc-50 border border-zinc-200 dark:bg-zinc-900/40 dark:border-zinc-700"
82
- : "bg-info-surface border border-blue-200 dark:border-blue-800"}`, children: [_jsxs("div", { className: "mb-1 flex items-center gap-2 text-xs text-zinc-400 dark:text-zinc-400", children: [_jsx("span", { className: "font-medium text-zinc-600 dark:text-zinc-300", children: ROLE_LABEL[msg.authorRole ?? "user"] ?? msg.authorRole }), msg.createdAt && (_jsx("span", { children: new Date(msg.createdAt).toLocaleString() }))] }), _jsx(Text, { className: "whitespace-pre-wrap text-zinc-700 dark:text-zinc-200", children: msg.body })] }, msg.id ?? i))) })] })), _jsxs(Div, { className: "flex flex-col gap-1", children: [_jsx("label", { className: "text-xs font-semibold text-zinc-500 dark:text-zinc-400 uppercase tracking-wide", children: "Reply to user" }), _jsx("textarea", { value: replyBody, onChange: (e) => setReplyBody(e.target.value), rows: 3, placeholder: "Type a reply\u2026", className: "w-full rounded-lg border border-zinc-300 dark:border-zinc-700 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-900 dark:text-zinc-100 placeholder-zinc-400 focus:outline-none focus:ring-2 focus:ring-primary-500" }), _jsx(Button, { type: "button", variant: "primary", size: "sm", isLoading: replyMutation.isPending, disabled: !replyBody.trim() || !ticketId || replyMutation.isPending, onClick: () => replyMutation.mutate(), children: "Send reply" })] }), _jsx("hr", { className: "border-zinc-200 dark:border-zinc-700" }), _jsx(Select, { label: "Status", options: STATUS_OPTIONS, value: status, onValueChange: setStatus }), _jsx(Select, { label: "Priority", options: PRIORITY_OPTIONS, value: priority, onValueChange: setPriority }), _jsxs(Div, { className: "flex flex-col gap-1", children: [_jsx("label", { className: "text-xs font-semibold text-zinc-500 dark:text-zinc-400 uppercase tracking-wide", children: "Internal notes (staff only)" }), _jsx("textarea", { value: notes, onChange: (e) => setNotes(e.target.value), rows: 3, placeholder: "Notes visible only to admins and employees\u2026", className: "w-full rounded-lg border border-zinc-300 dark:border-zinc-700 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-900 dark:text-zinc-100 placeholder-zinc-400 focus:outline-none focus:ring-2 focus:ring-primary-500" })] }), _jsxs(FormActions, { align: "right", children: [_jsx(Button, { type: "button", variant: "secondary", onClick: onClose, children: "Cancel" }), _jsx(Button, { type: "button", isLoading: updateMutation.isPending, disabled: !ticketId || updateMutation.isPending, onClick: () => updateMutation.mutate(), children: "Save changes" })] })] }) }));
238
+ : "bg-info-surface border border-blue-200 dark:border-blue-800"}`, children: [_jsxs("div", { className: "mb-1 flex items-center gap-2 text-xs text-zinc-400 dark:text-zinc-400", children: [_jsx("span", { className: "font-medium text-zinc-600 dark:text-zinc-300", children: ROLE_LABEL[msg.authorRole ?? "user"] ?? msg.authorRole }), msg.createdAt && (_jsx("span", { children: new Date(msg.createdAt).toLocaleString() }))] }), _jsx(Text, { className: "whitespace-pre-wrap text-zinc-700 dark:text-zinc-200", children: msg.body })] }, msg.id ?? i))) })] })), _jsxs(Div, { className: "flex flex-col gap-1", children: [_jsx("label", { className: "text-xs font-semibold text-zinc-500 dark:text-zinc-400 uppercase tracking-wide", children: "Reply to user" }), _jsx("textarea", { value: replyBody, onChange: (e) => setReplyBody(e.target.value), rows: 3, placeholder: "Type a reply\u2026", className: "w-full rounded-lg border border-zinc-300 dark:border-zinc-700 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-900 dark:text-zinc-100 placeholder-zinc-400 focus:outline-none focus:ring-2 focus:ring-primary-500" }), _jsx(Button, { type: "button", variant: "primary", size: "sm", isLoading: replyMutation.isPending, disabled: !replyBody.trim() || !ticketId || replyMutation.isPending, onClick: () => replyMutation.mutate(), children: "Send reply" })] }), _jsx("hr", { className: "border-zinc-200 dark:border-zinc-700" }), _jsx(Select, { label: "Status", options: STATUS_OPTIONS, value: status, onValueChange: setStatus }), _jsx(Select, { label: "Priority", options: PRIORITY_OPTIONS, value: priority, onValueChange: setPriority }), _jsxs(Div, { className: "flex flex-col gap-1", children: [_jsx("label", { className: "text-xs font-semibold text-zinc-500 dark:text-zinc-400 uppercase tracking-wide", children: "Internal notes (staff only)" }), _jsx("textarea", { value: notes, onChange: (e) => setNotes(e.target.value), rows: 3, placeholder: "Notes visible only to admins and employees\u2026", className: "w-full rounded-lg border border-zinc-300 dark:border-zinc-700 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-900 dark:text-zinc-100 placeholder-zinc-400 focus:outline-none focus:ring-2 focus:ring-primary-500" })] }), _jsxs(Div, { padding: "sm", className: "flex flex-col gap-2 rounded-lg border border-zinc-200 dark:border-zinc-700", children: [_jsx(Text, { className: "text-xs font-semibold text-zinc-500 dark:text-zinc-400 uppercase tracking-wide", children: "Linked parties" }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Tag the buyer / store / order / product / bid this ticket concerns." }), [
239
+ ["userId", "User slug"],
240
+ ["storeId", "Store slug"],
241
+ ["orderId", "Order ID"],
242
+ ["productId", "Product slug"],
243
+ ["bidId", "Bid ID"],
244
+ ].map(([key, label]) => (_jsx(Input, { label: label, type: "text", value: parties[key] ?? "", onChange: (e) => setParties((p) => ({ ...p, [key]: e.target.value })), placeholder: label }, key)))] }), isOrderModificationRequest && (_jsx(OrderItemsPanel, { linkedOrderId: linkedOrderId, orderItemsOpen: orderItemsOpen, setOrderItemsOpen: setOrderItemsOpen, orderItems: orderItems, setOrderItems: setOrderItems, loadOrderItems: loadOrderItems, applyOrderItems: applyOrderItems })), isStoreChangeRequest && (_jsx(StoreChangePanel, { linkedStoreId: linkedStoreId, storeStatus: storeStatus, setStoreStatus: setStoreStatus, storeIsVerified: storeIsVerified, setStoreIsVerified: setStoreIsVerified, storeIsFeatured: storeIsFeatured, setStoreIsFeatured: setStoreIsFeatured, applyStoreChange: applyStoreChange })), isUnbanRequest && (_jsx(UnbanRequestPanel, { linkedUserId: linkedUserId, liftHardBan: liftHardBan, liftSoftBanTickets: liftSoftBanTickets })), _jsxs(FormActions, { align: "right", children: [_jsx(Button, { type: "button", variant: "secondary", onClick: onClose, children: "Cancel" }), _jsx(Button, { type: "button", isLoading: updateMutation.isPending, disabled: !ticketId || updateMutation.isPending, onClick: () => updateMutation.mutate(), children: "Save changes" })] })] }) }));
245
+ }
246
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
247
+ function OrderItemsPanel(props) {
248
+ const { linkedOrderId, orderItemsOpen, setOrderItemsOpen, orderItems, setOrderItems, loadOrderItems, applyOrderItems, } = props;
249
+ const updateQty = (idx, raw) => {
250
+ const q = Math.max(0, parseInt(raw, 10) || 0);
251
+ setOrderItems((prev) => prev.map((p, i) => (i === idx ? { ...p, quantity: q } : p)));
252
+ };
253
+ return (_jsxs(Div, { padding: "sm", className: "flex flex-col gap-2 rounded-lg border border-info/40 bg-info-surface/40", children: [_jsx(Text, { className: "text-xs font-semibold text-info uppercase tracking-wide", children: "Modify order items" }), linkedOrderId ? (_jsxs(_Fragment, { children: [_jsxs(Text, { className: "text-xs text-zinc-600 dark:text-zinc-300", children: ["Editing order: ", _jsx("code", { className: "font-mono", children: linkedOrderId })] }), !orderItemsOpen ? (_jsx(Button, { type: "button", variant: "secondary", size: "sm", isLoading: loadOrderItems.isPending, disabled: loadOrderItems.isPending, onClick: () => loadOrderItems.mutate(), children: "Load current items" })) : (_jsxs(_Fragment, { children: [orderItems.length === 0 ? (_jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Order has no items." })) : (_jsx(Div, { className: "flex flex-col gap-2", children: orderItems.map((it, idx) => (_jsxs(Div, { className: "flex items-center gap-2 rounded border border-zinc-200 dark:border-zinc-700 px-2 py-1", children: [_jsxs(Div, { className: "flex-1 min-w-0", children: [_jsx(Text, { className: "text-xs font-medium truncate", children: it.productTitle }), _jsxs(Text, { size: "xs", color: "muted", children: [it.productId, " \u00B7 \u20B9", (it.unitPrice / 100).toFixed(2), "/ea"] })] }), _jsx("input", { type: "number", min: "0", value: it.quantity, onChange: (e) => updateQty(idx, e.target.value), className: "w-16 rounded border border-zinc-300 dark:border-zinc-700 bg-white dark:bg-zinc-800 px-2 py-1 text-xs" })] }, `${it.productId}-${idx}`))) })), _jsxs(Row, { gap: "sm", children: [_jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: () => setOrderItemsOpen(false), children: "Cancel" }), _jsx(Button, { type: "button", variant: "primary", size: "sm", isLoading: applyOrderItems.isPending, disabled: applyOrderItems.isPending, onClick: () => applyOrderItems.mutate(), children: "Apply changes" })] })] }))] })) : (_jsxs(Text, { className: "text-xs text-zinc-600 dark:text-zinc-300", children: ["Set the", " ", _jsx(Text, { as: "span", weight: "semibold", children: "Order ID" }), " ", "field in the Linked parties panel above to enable this action."] }))] }));
254
+ }
255
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
256
+ function StoreChangePanel(props) {
257
+ const { linkedStoreId, storeStatus, setStoreStatus, storeIsVerified, setStoreIsVerified, storeIsFeatured, setStoreIsFeatured, applyStoreChange, } = props;
258
+ return (_jsxs(Div, { padding: "sm", className: "flex flex-col gap-2 rounded-lg border border-warning/40 bg-warning-surface/40", children: [_jsx(Text, { className: "text-xs font-semibold text-warning uppercase tracking-wide", children: "Apply store change" }), linkedStoreId ? (_jsxs(_Fragment, { children: [_jsxs(Text, { className: "text-xs text-zinc-600 dark:text-zinc-300", children: ["Editing store: ", _jsx("code", { className: "font-mono", children: linkedStoreId })] }), _jsx(Select, { label: "Store status", options: [
259
+ { label: "Active", value: "active" },
260
+ { label: "Pending", value: "pending" },
261
+ { label: "Suspended", value: "suspended" },
262
+ { label: "Rejected", value: "rejected" },
263
+ ], value: storeStatus, onValueChange: setStoreStatus }), _jsx(Toggle, { label: "Verified badge", checked: storeIsVerified, onChange: setStoreIsVerified }), _jsx(Toggle, { label: "Featured store", checked: storeIsFeatured, onChange: setStoreIsFeatured }), _jsx(Button, { type: "button", variant: "primary", size: "sm", isLoading: applyStoreChange.isPending, disabled: applyStoreChange.isPending, onClick: () => applyStoreChange.mutate(), children: "Apply store change" })] })) : (_jsxs(Text, { className: "text-xs text-zinc-600 dark:text-zinc-300", children: ["Set the", " ", _jsx(Text, { as: "span", weight: "semibold", children: "Store slug" }), " ", "field in the Linked parties panel above to enable this action."] }))] }));
264
+ }
265
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
266
+ function UnbanRequestPanel(props) {
267
+ const { linkedUserId, liftHardBan, liftSoftBanTickets } = props;
268
+ return (_jsxs(Div, { padding: "sm", className: "flex flex-col gap-2 rounded-lg border border-error/40 bg-error-surface/40", children: [_jsx(Text, { className: "text-xs font-semibold text-error uppercase tracking-wide", children: "Lift account ban" }), linkedUserId ? (_jsxs(_Fragment, { children: [_jsxs(Text, { className: "text-xs text-zinc-600 dark:text-zinc-300", children: ["Appellant: ", _jsx("code", { className: "font-mono", children: linkedUserId })] }), _jsx(Text, { size: "xs", color: "muted", children: "Resolves the ticket and appends an audit note on success." }), _jsxs(Row, { gap: "sm", children: [_jsx(Button, { type: "button", variant: "primary", size: "sm", isLoading: liftHardBan.isPending, disabled: liftHardBan.isPending, onClick: () => liftHardBan.mutate(), children: "Lift hard ban" }), _jsx(Button, { type: "button", variant: "secondary", size: "sm", isLoading: liftSoftBanTickets.isPending, disabled: liftSoftBanTickets.isPending, onClick: () => liftSoftBanTickets.mutate(), children: "Lift ticket soft ban" })] })] })) : (_jsxs(Text, { className: "text-xs text-zinc-600 dark:text-zinc-300", children: ["Set the", " ", _jsx(Text, { as: "span", weight: "semibold", children: "User slug" }), " ", "field in the Linked parties panel above to enable these actions."] }))] }));
83
269
  }
@@ -1,4 +1,3 @@
1
- import type { ListingViewShellProps } from "../../../ui";
2
- export interface AdminSupportTicketsViewProps extends ListingViewShellProps {
3
- }
1
+ import type { ListingLayoutProps } from "../../../ui";
2
+ export type AdminSupportTicketsViewProps = ListingLayoutProps;
4
3
  export declare function AdminSupportTicketsView({ children, ...props }: AdminSupportTicketsViewProps): import("react/jsx-runtime").JSX.Element;