@mohasinac/appkit 2.7.59 → 2.8.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 (311) 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/account/components/UserOffersPanel.js +1 -1
  47. package/dist/features/account/components/UserSupportView.d.ts +1 -2
  48. package/dist/features/account/components/UserSupportView.js +9 -1
  49. package/dist/features/admin/actions/admin-actions.js +16 -1
  50. package/dist/features/admin/components/AdminAllEventEntriesView.d.ts +2 -3
  51. package/dist/features/admin/components/AdminAllEventEntriesView.js +50 -83
  52. package/dist/features/admin/components/AdminBidsView.d.ts +2 -3
  53. package/dist/features/admin/components/AdminBidsView.js +64 -98
  54. package/dist/features/admin/components/AdminBlogView.d.ts +3 -7
  55. package/dist/features/admin/components/AdminBlogView.js +53 -83
  56. package/dist/features/admin/components/AdminBrandsView.d.ts +2 -3
  57. package/dist/features/admin/components/AdminBrandsView.js +84 -83
  58. package/dist/features/admin/components/AdminBundlesView.js +82 -125
  59. package/dist/features/admin/components/AdminCarouselView.d.ts +2 -2
  60. package/dist/features/admin/components/AdminCarouselView.js +17 -52
  61. package/dist/features/admin/components/AdminCartsView.d.ts +2 -3
  62. package/dist/features/admin/components/AdminCartsView.js +39 -88
  63. package/dist/features/admin/components/AdminCategoriesView.d.ts +3 -3
  64. package/dist/features/admin/components/AdminCategoriesView.js +98 -92
  65. package/dist/features/admin/components/AdminCategoryEditorView.js +2 -2
  66. package/dist/features/admin/components/AdminClassifiedView.d.ts +3 -0
  67. package/dist/features/admin/components/AdminClassifiedView.js +44 -0
  68. package/dist/features/admin/components/AdminContactView.d.ts +2 -2
  69. package/dist/features/admin/components/AdminContactView.js +104 -111
  70. package/dist/features/admin/components/AdminCouponsView.d.ts +3 -6
  71. package/dist/features/admin/components/AdminCouponsView.js +66 -86
  72. package/dist/features/admin/components/AdminDigitalCodesView.d.ts +3 -0
  73. package/dist/features/admin/components/AdminDigitalCodesView.js +51 -0
  74. package/dist/features/admin/components/AdminFaqsView.d.ts +4 -4
  75. package/dist/features/admin/components/AdminFaqsView.js +77 -33
  76. package/dist/features/admin/components/AdminFeaturesView.d.ts +2 -3
  77. package/dist/features/admin/components/AdminFeaturesView.js +57 -70
  78. package/dist/features/admin/components/AdminGroupedListingsView.d.ts +3 -0
  79. package/dist/features/admin/components/AdminGroupedListingsView.js +43 -0
  80. package/dist/features/admin/components/AdminHistoryView.d.ts +2 -3
  81. package/dist/features/admin/components/AdminHistoryView.js +35 -52
  82. package/dist/features/admin/components/AdminListingScaffold.d.ts +2 -2
  83. package/dist/features/admin/components/AdminListingScaffold.js +3 -3
  84. package/dist/features/admin/components/AdminLiveView.d.ts +3 -0
  85. package/dist/features/admin/components/AdminLiveView.js +50 -0
  86. package/dist/features/admin/components/AdminNewsletterView.d.ts +2 -2
  87. package/dist/features/admin/components/AdminNewsletterView.js +67 -97
  88. package/dist/features/admin/components/AdminNotificationsView.d.ts +2 -3
  89. package/dist/features/admin/components/AdminNotificationsView.js +67 -93
  90. package/dist/features/admin/components/AdminOrderEditorView.js +10 -10
  91. package/dist/features/admin/components/AdminOrdersView.d.ts +2 -3
  92. package/dist/features/admin/components/AdminOrdersView.js +93 -107
  93. package/dist/features/admin/components/AdminPayoutsView.d.ts +2 -3
  94. package/dist/features/admin/components/AdminPayoutsView.js +51 -91
  95. package/dist/features/admin/components/AdminPrizeDrawsView.d.ts +2 -3
  96. package/dist/features/admin/components/AdminPrizeDrawsView.js +39 -76
  97. package/dist/features/admin/components/AdminProductEditorView.js +3 -3
  98. package/dist/features/admin/components/AdminProductsView.d.ts +4 -4
  99. package/dist/features/admin/components/AdminProductsView.js +167 -163
  100. package/dist/features/admin/components/AdminReturnRequestsView.d.ts +1 -1
  101. package/dist/features/admin/components/AdminReturnRequestsView.js +64 -66
  102. package/dist/features/admin/components/AdminReviewsView.d.ts +3 -7
  103. package/dist/features/admin/components/AdminReviewsView.js +94 -110
  104. package/dist/features/admin/components/AdminScammersView.d.ts +2 -3
  105. package/dist/features/admin/components/AdminScammersView.js +53 -97
  106. package/dist/features/admin/components/AdminSectionsView.js +1 -1
  107. package/dist/features/admin/components/AdminSessionsView.d.ts +2 -3
  108. package/dist/features/admin/components/AdminSessionsView.js +62 -89
  109. package/dist/features/admin/components/AdminStoreAddressesView.d.ts +1 -1
  110. package/dist/features/admin/components/AdminStoreAddressesView.js +39 -53
  111. package/dist/features/admin/components/AdminStoreEditorView.js +21 -8
  112. package/dist/features/admin/components/AdminStoresView.d.ts +2 -3
  113. package/dist/features/admin/components/AdminStoresView.js +67 -99
  114. package/dist/features/admin/components/AdminSublistingCategoriesView.d.ts +1 -1
  115. package/dist/features/admin/components/AdminSublistingCategoriesView.js +28 -44
  116. package/dist/features/admin/components/AdminSupportTicketDetailView.d.ts +10 -1
  117. package/dist/features/admin/components/AdminSupportTicketDetailView.js +191 -5
  118. package/dist/features/admin/components/AdminSupportTicketsView.d.ts +2 -3
  119. package/dist/features/admin/components/AdminSupportTicketsView.js +65 -96
  120. package/dist/features/admin/components/AdminTeamView.d.ts +2 -2
  121. package/dist/features/admin/components/AdminTeamView.js +40 -74
  122. package/dist/features/admin/components/AdminUserEditorView.d.ts +11 -1
  123. package/dist/features/admin/components/AdminUserEditorView.js +80 -6
  124. package/dist/features/admin/components/AdminUsersView.d.ts +2 -3
  125. package/dist/features/admin/components/AdminUsersView.js +108 -100
  126. package/dist/features/admin/components/AdminViewCards.d.ts +1 -1
  127. package/dist/features/admin/components/AdminWishlistsView.d.ts +2 -3
  128. package/dist/features/admin/components/AdminWishlistsView.js +36 -62
  129. package/dist/features/admin/components/DataListingView.d.ts +122 -0
  130. package/dist/features/admin/components/DataListingView.js +66 -0
  131. package/dist/features/admin/components/index.d.ts +10 -4
  132. package/dist/features/admin/components/index.js +6 -2
  133. package/dist/features/admin/constants/filter-tabs.d.ts +23 -17
  134. package/dist/features/admin/constants/filter-tabs.js +21 -17
  135. package/dist/features/admin/hooks/useAdminListing.d.ts +1 -0
  136. package/dist/features/admin/hooks/useAdminListing.js +1 -1
  137. package/dist/features/admin/schemas/firestore.js +6 -7
  138. package/dist/features/auctions/server.d.ts +0 -1
  139. package/dist/features/auctions/server.js +0 -1
  140. package/dist/features/auth/actions/realtime-token-actions.js +1 -1
  141. package/dist/features/auth/repository/user.repository.js +1 -1
  142. package/dist/features/cart/repository/cart.repository.d.ts +4 -1
  143. package/dist/features/cart/repository/cart.repository.js +12 -0
  144. package/dist/features/checkout/hooks/useCheckoutApi.d.ts +0 -2
  145. package/dist/features/checkout/index.d.ts +1 -1
  146. package/dist/features/events/components/AdminEventsView.d.ts +3 -3
  147. package/dist/features/events/components/AdminEventsView.js +50 -86
  148. package/dist/features/events/components/EventOfferCard.d.ts +19 -0
  149. package/dist/features/events/components/EventOfferCard.js +29 -0
  150. package/dist/features/events/components/EventRaffleEntryForm.d.ts +25 -0
  151. package/dist/features/events/components/EventRaffleEntryForm.js +37 -0
  152. package/dist/features/events/components/EventRafflesSection.d.ts +1 -4
  153. package/dist/features/events/components/EventRafflesSection.js +17 -6
  154. package/dist/features/events/components/EventSaleBanner.d.ts +21 -0
  155. package/dist/features/events/components/EventSaleBanner.js +18 -0
  156. package/dist/features/events/components/index.d.ts +6 -0
  157. package/dist/features/events/components/index.js +4 -0
  158. package/dist/features/events/repository/event-entry.repository.d.ts +5 -0
  159. package/dist/features/events/repository/event-entry.repository.js +7 -0
  160. package/dist/features/filters/AsyncFacetSection.d.ts +1 -1
  161. package/dist/features/homepage/components/FAQSection.d.ts +0 -5
  162. package/dist/features/homepage/lib/live-stats.js +1 -1
  163. package/dist/features/homepage/schemas/firestore.d.ts +0 -2
  164. package/dist/features/layout/index.d.ts +0 -2
  165. package/dist/features/layout/index.js +0 -1
  166. package/dist/features/pre-orders/server.d.ts +0 -1
  167. package/dist/features/pre-orders/server.js +0 -1
  168. package/dist/features/products/components/GroupSettingsPanel.js +2 -2
  169. package/dist/features/products/components/PrizeDrawItemsEditor.js +2 -2
  170. package/dist/features/products/components/PrizeDrawsSection.d.ts +1 -4
  171. package/dist/features/products/components/PrizeDrawsSection.js +17 -6
  172. package/dist/features/products/components/PrizeRevealModal.js +1 -1
  173. package/dist/features/products/components/ProductCardMetadataSection.d.ts +11 -0
  174. package/dist/features/products/components/ProductCardMetadataSection.js +25 -0
  175. package/dist/features/products/components/ProductDetailPageView.js +3 -1
  176. package/dist/features/products/components/ProductFeaturesSelector.js +1 -1
  177. package/dist/features/products/components/ProductGradingTab.d.ts +13 -0
  178. package/dist/features/products/components/ProductGradingTab.js +25 -0
  179. package/dist/features/products/components/ProductGrid.js +14 -2
  180. package/dist/features/products/components/ProductTabsShell.d.ts +5 -1
  181. package/dist/features/products/components/ProductTabsShell.js +6 -1
  182. package/dist/features/products/components/index.d.ts +4 -0
  183. package/dist/features/products/components/index.js +3 -0
  184. package/dist/features/products/constants/action-defs.d.ts +5 -0
  185. package/dist/features/products/constants/action-defs.js +52 -32
  186. package/dist/features/products/constants/sieve.d.ts +24 -4
  187. package/dist/features/products/constants/sieve.js +20 -11
  188. package/dist/features/products/schemas/firestore.d.ts +17 -0
  189. package/dist/features/products/schemas/product-features.validators.d.ts +2 -2
  190. package/dist/features/products/schemas/product-templates.d.ts +2 -4
  191. package/dist/features/products/types/index.d.ts +4 -0
  192. package/dist/features/promotions/server.d.ts +0 -1
  193. package/dist/features/promotions/server.js +0 -1
  194. package/dist/features/search/api/route.js +44 -1
  195. package/dist/features/search/components/Search.js +2 -0
  196. package/dist/features/search/hooks/useNavSuggestions.d.ts +5 -1
  197. package/dist/features/search/hooks/useNavSuggestions.js +31 -4
  198. package/dist/features/seller/components/BrandInlineSelect.js +2 -2
  199. package/dist/features/seller/components/CategoryInlineSelect.js +2 -2
  200. package/dist/features/seller/components/SellerAddressesView.js +1 -1
  201. package/dist/features/seller/components/SellerAuctionsView.d.ts +3 -3
  202. package/dist/features/seller/components/SellerAuctionsView.js +60 -90
  203. package/dist/features/seller/components/SellerBidsView.js +1 -1
  204. package/dist/features/seller/components/SellerBundlesView.js +64 -89
  205. package/dist/features/seller/components/SellerClassifiedView.js +67 -90
  206. package/dist/features/seller/components/SellerCouponEditorView.js +1 -1
  207. package/dist/features/seller/components/SellerCouponsView.d.ts +2 -2
  208. package/dist/features/seller/components/SellerCouponsView.js +45 -84
  209. package/dist/features/seller/components/SellerDigitalCodesView.js +63 -88
  210. package/dist/features/seller/components/SellerGroupedListingsView.js +33 -49
  211. package/dist/features/seller/components/SellerLiveView.js +63 -84
  212. package/dist/features/seller/components/SellerOffersPanel.js +1 -1
  213. package/dist/features/seller/components/SellerOffersView.d.ts +2 -2
  214. package/dist/features/seller/components/SellerOffersView.js +37 -69
  215. package/dist/features/seller/components/SellerOrdersView.d.ts +2 -2
  216. package/dist/features/seller/components/SellerOrdersView.js +4 -4
  217. package/dist/features/seller/components/SellerPayoutMethodsView.js +1 -1
  218. package/dist/features/seller/components/SellerPayoutsView.d.ts +2 -2
  219. package/dist/features/seller/components/SellerPayoutsView.js +34 -68
  220. package/dist/features/seller/components/SellerPreOrdersView.d.ts +2 -2
  221. package/dist/features/seller/components/SellerPreOrdersView.js +49 -82
  222. package/dist/features/seller/components/SellerPrizeDrawsView.d.ts +2 -2
  223. package/dist/features/seller/components/SellerPrizeDrawsView.js +49 -82
  224. package/dist/features/seller/components/SellerProductShell.d.ts +1 -1
  225. package/dist/features/seller/components/SellerProductsView.d.ts +2 -2
  226. package/dist/features/seller/components/SellerProductsView.js +15 -10
  227. package/dist/features/seller/components/SellerShippingConfigsView.js +1 -1
  228. package/dist/features/seller/components/SellerSidebar.d.ts +0 -4
  229. package/dist/features/seller/components/SellerSidebar.js +0 -2
  230. package/dist/features/seller/components/SellerStoreCategoriesView.js +1 -1
  231. package/dist/features/seller/components/SellerTemplatesView.js +2 -2
  232. package/dist/features/seller/components/SellersListView.d.ts +1 -2
  233. package/dist/features/seller/components/analytics/SellerAnalyticsStats.d.ts +5 -0
  234. package/dist/features/seller/components/analytics/SellerAnalyticsStats.js +2 -8
  235. package/dist/features/seller/components/index.d.ts +0 -3
  236. package/dist/features/seller/components/index.js +0 -2
  237. package/dist/features/seller/server.d.ts +0 -1
  238. package/dist/features/seller/server.js +0 -1
  239. package/dist/features/shell/FormShell.d.ts +1 -1
  240. package/dist/features/shell/FormShell.js +4 -1
  241. package/dist/features/shell/field-groups/ImageFieldGroup.d.ts +18 -0
  242. package/dist/features/shell/field-groups/ImageFieldGroup.js +15 -0
  243. package/dist/features/shell/field-groups/SeoFieldGroup.d.ts +22 -0
  244. package/dist/features/shell/field-groups/SeoFieldGroup.js +16 -0
  245. package/dist/features/shell/field-groups/StatusFieldGroup.d.ts +35 -0
  246. package/dist/features/shell/field-groups/StatusFieldGroup.js +16 -0
  247. package/dist/features/shell/field-groups/TitleDescriptionGroup.d.ts +40 -0
  248. package/dist/features/shell/field-groups/TitleDescriptionGroup.js +16 -0
  249. package/dist/features/shell/field-groups/index.d.ts +13 -0
  250. package/dist/features/shell/field-groups/index.js +9 -0
  251. package/dist/features/shell/index.d.ts +2 -0
  252. package/dist/features/shell/index.js +1 -0
  253. package/dist/features/stores/components/StoreCapabilitiesGuideView.d.ts +1 -2
  254. package/dist/features/stores/components/StoreFinanceGuideView.d.ts +1 -2
  255. package/dist/features/stores/components/StoreHeader.js +2 -1
  256. package/dist/features/stores/components/StoreListingsGuideView.d.ts +1 -2
  257. package/dist/features/stores/components/StoreOrdersGuideView.d.ts +1 -2
  258. package/dist/features/stores/components/StoreScopedSearch.d.ts +16 -0
  259. package/dist/features/stores/components/StoreScopedSearch.js +27 -0
  260. package/dist/features/stores/components/StoreSettingsGuideView.d.ts +1 -2
  261. package/dist/features/stores/server.d.ts +0 -1
  262. package/dist/features/stores/server.js +0 -1
  263. package/dist/features/support/schemas/firestore.d.ts +22 -1
  264. package/dist/features/support/schemas/firestore.js +10 -0
  265. package/dist/features/wishlist/server.d.ts +0 -1
  266. package/dist/features/wishlist/server.js +0 -1
  267. package/dist/index.d.ts +9 -27
  268. package/dist/index.js +14 -50
  269. package/dist/next/routing/route-map.d.ts +8 -0
  270. package/dist/next/routing/route-map.js +4 -0
  271. package/dist/react/hooks/useListingTypeFlags.d.ts +32 -0
  272. package/dist/react/hooks/useListingTypeFlags.js +19 -0
  273. package/dist/security/index.d.ts +1 -1
  274. package/dist/security/index.js +1 -1
  275. package/dist/security/pii-redact.d.ts +8 -0
  276. package/dist/security/pii-redact.js +10 -1
  277. package/dist/seed/grouped-listings-seed-data.d.ts +4 -0
  278. package/dist/seed/products-preorders-seed-data.d.ts +4 -0
  279. package/dist/seed/products-prize-draws-seed-data.js +3 -0
  280. package/dist/seed/site-settings-seed-data.js +5 -5
  281. package/dist/seed/sub-listings-seed-data.d.ts +4 -0
  282. package/dist/server.d.ts +2 -0
  283. package/dist/server.js +4 -0
  284. package/dist/styles.css +54 -395
  285. package/dist/tailwind-utilities.css +1 -1
  286. package/dist/ui/components/BaseListingCard.d.ts +10 -0
  287. package/dist/ui/components/BaseListingCard.js +17 -1
  288. package/dist/ui/components/DetailPageGallery.d.ts +32 -0
  289. package/dist/ui/components/DetailPageGallery.js +47 -0
  290. package/dist/ui/components/DetailPageHero.d.ts +30 -0
  291. package/dist/ui/components/DetailPageHero.js +22 -0
  292. package/dist/ui/components/DetailPageTabs.d.ts +34 -0
  293. package/dist/ui/components/DetailPageTabs.js +38 -0
  294. package/dist/ui/components/HorizontalScroller.style.css +15 -2
  295. package/dist/ui/components/ListingLayout.d.ts +11 -2
  296. package/dist/ui/components/ListingLayout.js +12 -6
  297. package/dist/ui/components/PaginatedSelect.d.ts +66 -0
  298. package/dist/ui/components/PaginatedSelect.js +201 -0
  299. package/dist/ui/components/PaginatedSelect.style.css +254 -0
  300. package/dist/ui/components/Semantic.d.ts +0 -4
  301. package/dist/ui/components/Semantic.js +0 -2
  302. package/dist/ui/components/SettingsSection.d.ts +47 -0
  303. package/dist/ui/components/SettingsSection.js +38 -0
  304. package/dist/ui/components/index.style.css +1 -4
  305. package/dist/ui/index.d.ts +12 -14
  306. package/dist/ui/index.js +6 -7
  307. package/dist/utils/id-generators.d.ts +1 -18
  308. package/dist/utils/id-generators.js +51 -18
  309. package/dist/validation/schemas.d.ts +25 -0
  310. package/dist/validation/schemas.js +28 -0
  311. package/package.json +1 -1
@@ -2,25 +2,14 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import React, { useState, useCallback } from "react";
4
4
  import { UserPlus } from "lucide-react";
5
- import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
- import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
7
- import { BulkActionBar, Button, FilterChipGroup, ListingToolbar, Pagination, ListingViewShell, RowActionMenu, ListingFilterDrawer } from "../../../ui";
8
- import { useBottomActions } from "../../layout";
5
+ import { Button, FilterChipGroup, ListingLayout, RowActionMenu } from "../../../ui";
9
6
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
10
7
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
11
8
  import { buildBulkAction } from "../../../_internal/shared/actions/bulk-helpers";
12
9
  import { ALL_TAB } from "../constants/filter-tabs";
13
- import { toRecordArray, toRelativeDate, toStringValue, useAdminListingData, } from "../hooks/useAdminListingData";
14
- import { DataTable } from "./DataTable";
10
+ import { toRecordArray, toRelativeDate, toStringValue, } from "../hooks/useAdminListingData";
11
+ import { DataListingView } from "./DataListingView";
15
12
  import { AdminEmployeeEditorView } from "./AdminEmployeeEditorView";
16
- const PAGE_SIZE = 25;
17
- const FILTER_KEY = "group";
18
- const DEFAULT_SORT = "-createdAt";
19
- const SORT_OPTIONS = [
20
- { value: "-createdAt", label: "Newest" },
21
- { value: "createdAt", label: "Oldest" },
22
- { value: "displayName", label: "Name A–Z" },
23
- ];
24
13
  const GROUP_TABS = [
25
14
  ALL_TAB,
26
15
  { id: "content_moderator", label: "Content Mod" },
@@ -47,35 +36,9 @@ function formatGroup(group) {
47
36
  return group.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
48
37
  }
49
38
  export function AdminTeamView({ children, onBulkRemove, ...props }) {
50
- const hasChildren = React.Children.count(children) > 0;
51
- const [view, setView] = useState("table");
52
- const table = useUrlTable({
53
- defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT },
54
- });
55
- const [searchInput, setSearchInput] = useState(table.get("q") || "");
56
- const [filterOpen, setFilterOpen] = useState(false);
57
- const [pendingGroup, setPendingGroup] = useState(table.get(FILTER_KEY) ?? "");
58
39
  const [drawerOpen, setDrawerOpen] = useState(false);
59
40
  const [selectedRow, setSelectedRow] = useState(null);
60
41
  const [inviteMode, setInviteMode] = useState(false);
61
- const openFilters = useCallback(() => {
62
- setPendingGroup(table.get(FILTER_KEY) ?? "");
63
- setFilterOpen(true);
64
- }, [table]);
65
- const applyFilters = useCallback(() => {
66
- table.setMany({ page: "1", [FILTER_KEY]: pendingGroup });
67
- setFilterOpen(false);
68
- }, [pendingGroup, table]);
69
- const clearFilters = useCallback(() => {
70
- setPendingGroup("");
71
- }, []);
72
- const resetAll = useCallback(() => {
73
- table.setMany({ q: "", sort: "", [FILTER_KEY]: "" });
74
- setSearchInput("");
75
- }, [table]);
76
- const commitSearch = useCallback(() => {
77
- table.set("q", searchInput.trim());
78
- }, [searchInput, table]);
79
42
  const openInvite = useCallback(() => {
80
43
  setSelectedRow(null);
81
44
  setInviteMode(true);
@@ -86,22 +49,23 @@ export function AdminTeamView({ children, onBulkRemove, ...props }) {
86
49
  setInviteMode(false);
87
50
  setDrawerOpen(true);
88
51
  }, []);
89
- const activeFilterCount = table.get(FILTER_KEY) ? 1 : 0;
90
- const hasActiveState = !!table.get("q") ||
91
- table.get("sort") !== DEFAULT_SORT ||
92
- activeFilterCount > 0;
93
- const groupRaw = table.get(FILTER_KEY);
94
- const filters = groupRaw && groupRaw !== "All"
95
- ? `permissionGroup==${groupRaw}`
96
- : undefined;
97
- const { rows, total, isLoading, errorMessage } = useAdminListingData({
52
+ if (React.Children.count(children) > 0) {
53
+ return (_jsx(ListingLayout, { portal: "admin", ...props, children: children }));
54
+ }
55
+ const config = {
56
+ portal: "admin",
57
+ title: "Team",
58
+ searchPlaceholder: "Search by name or email",
59
+ emptyLabel: "No employees found",
60
+ filterKeys: ["group"],
61
+ defaultSort: "-createdAt",
98
62
  queryKey: ["admin", "team", "listing"],
99
63
  endpoint: ADMIN_ENDPOINTS.TEAM,
100
- page: table.getNumber("page", 1),
101
- pageSize: PAGE_SIZE,
102
- sorts: table.get("sort") || DEFAULT_SORT,
103
- filters,
104
- q: table.get("q") || undefined,
64
+ sortOptions: [
65
+ { value: "-createdAt", label: "Newest" },
66
+ { value: "createdAt", label: "Oldest" },
67
+ { value: "displayName", label: "Name A–Z" },
68
+ ],
105
69
  mapRows: (response) => toRecordArray(response.users).map((item, index) => ({
106
70
  id: toStringValue(item.id ?? item.uid, `employee-${index}`),
107
71
  primary: toStringValue(item.displayName, "Unnamed employee"),
@@ -112,7 +76,9 @@ export function AdminTeamView({ children, onBulkRemove, ...props }) {
112
76
  : "Custom",
113
77
  ].join(" · "),
114
78
  status: typeof item.disabled === "boolean"
115
- ? item.disabled ? "Disabled" : "Active"
79
+ ? item.disabled
80
+ ? "Disabled"
81
+ : "Active"
116
82
  : "Active",
117
83
  updatedAt: toRelativeDate(item.updatedAt ?? item.createdAt),
118
84
  _raw: item,
@@ -124,25 +90,25 @@ export function AdminTeamView({ children, onBulkRemove, ...props }) {
124
90
  return response.total;
125
91
  return mappedRows.length;
126
92
  },
127
- });
128
- const currentPage = table.getNumber("page", 1);
129
- const totalPages = Math.ceil(total / PAGE_SIZE);
130
- const selection = useBulkSelection({ items: rows, keyExtractor: (r) => r.id });
131
- const bulkActions = [
132
- ...(onBulkRemove ? [buildBulkAction(ACTIONS.ADMIN["remove-team-member"], async () => { await onBulkRemove(selection.selectedIds); selection.clearSelection(); })] : []),
133
- ];
134
- useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: bulkActions } } : {});
135
- if (hasChildren) {
136
- return (_jsx(ListingViewShell, { portal: "admin", ...props, children: children }));
137
- }
138
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search by name or email", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => {
139
- table.set("sort", v);
140
- }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { type: "button", variant: "primary", onClick: openInvite, className: "flex items-center gap-1.5 whitespace-nowrap", children: [_jsx(UserPlus, { className: "h-4 w-4" }), "Invite Employee"] }) }), 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 employees found", renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
141
- {
142
- label: ACTIONS.ADMIN["edit-team-member"].label,
143
- onClick: () => openEdit(row),
144
- },
145
- ] })) })] }), _jsx(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearFilters, activeCount: activeFilterCount, children: _jsx(FilterChipGroup, { label: "Permission Group", tabs: GROUP_TABS, value: pendingGroup, onChange: (id) => setPendingGroup(id) }) })] }), _jsx(AdminEmployeeEditorView, { open: drawerOpen, onClose: () => setDrawerOpen(false), mode: inviteMode ? "invite" : "edit", userId: selectedRow?.id, displayName: selectedRow?.primary, currentPermissionGroup: toStringValue(selectedRow?._raw?.permissionGroup, "custom"), currentPermissions: Array.isArray(selectedRow?._raw?.permissions)
93
+ buildFilters: (state) => state.group && state.group !== "All" ? `permissionGroup==${state.group}` : undefined,
94
+ toolbarExtra: (_jsxs(Button, { type: "button", variant: "primary", onClick: openInvite, className: "flex items-center gap-1.5 whitespace-nowrap", children: [_jsx(UserPlus, { className: "h-4 w-4" }), "Invite Employee"] })),
95
+ buildBulkActions: onBulkRemove
96
+ ? (selection) => [
97
+ buildBulkAction(ACTIONS.ADMIN["remove-team-member"], async () => {
98
+ await onBulkRemove(selection.selectedIds);
99
+ selection.clearSelection();
100
+ }),
101
+ ]
102
+ : undefined,
103
+ renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
104
+ {
105
+ label: ACTIONS.ADMIN["edit-team-member"].label,
106
+ onClick: () => openEdit(row),
107
+ },
108
+ ] })),
109
+ renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsx(FilterChipGroup, { label: "Permission Group", tabs: GROUP_TABS, value: pendingFilters.group ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, group: id })) })),
110
+ };
111
+ return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(AdminEmployeeEditorView, { open: drawerOpen, onClose: () => setDrawerOpen(false), mode: inviteMode ? "invite" : "edit", userId: selectedRow?.id, displayName: selectedRow?.primary, currentPermissionGroup: toStringValue(selectedRow?._raw?.permissionGroup, "custom"), currentPermissions: Array.isArray(selectedRow?._raw?.permissions)
146
112
  ? selectedRow._raw.permissions
147
113
  : [] })] }));
148
114
  }
@@ -21,6 +21,16 @@ export interface AdminUserEditorViewProps {
21
21
  /** Whether the user is hard-banned (isDisabled + hardBanReason set). */
22
22
  currentIsHardBanned?: boolean;
23
23
  currentHardBanReason?: string;
24
+ currentPhoneNumber?: string | null;
25
+ currentBio?: string;
26
+ currentLocation?: string;
27
+ currentWebsite?: string;
28
+ currentSocialLinks?: {
29
+ twitter?: string;
30
+ instagram?: string;
31
+ facebook?: string;
32
+ linkedin?: string;
33
+ };
24
34
  }
25
- export declare function AdminUserEditorView({ open, onClose, userId, displayName, currentRole, currentIsDisabled, currentEmailVerified, ownedStoreId, ownedStoreName, currentSoftBans, currentIsHardBanned, currentHardBanReason, }: AdminUserEditorViewProps): import("react/jsx-runtime").JSX.Element;
35
+ export declare function AdminUserEditorView({ open, onClose, userId, displayName, currentRole, currentIsDisabled, currentEmailVerified, ownedStoreId, ownedStoreName, currentSoftBans, currentIsHardBanned, currentHardBanReason, currentPhoneNumber, currentBio, currentLocation, currentWebsite, currentSocialLinks, }: AdminUserEditorViewProps): import("react/jsx-runtime").JSX.Element;
26
36
  export {};
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import React from "react";
4
4
  import { useMutation, useQueryClient } from "@tanstack/react-query";
5
- import { Button, ConfirmDeleteModal, Form, FormActions, Heading, Select, SideDrawer, Text, Toggle, useToast } from "../../../ui";
5
+ import { Button, ConfirmDeleteModal, Form, FormActions, Heading, Input, Label, Select, SideDrawer, StackedViewShell, Text, Toggle, useToast } from "../../../ui";
6
6
  import { apiClient } from "../../../http";
7
7
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
8
8
  const ROLE_OPTIONS = [
@@ -20,6 +20,10 @@ const BANNED_ACTION_OPTIONS = [
20
20
  { label: "Create support tickets", value: "create_support_tickets" },
21
21
  { label: "Report scammers", value: "report_scammers" },
22
22
  ];
23
+ // Standard textarea/input chrome for raw <textarea>/<input> elements in this
24
+ // view (consistent border/focus styling). Deduped to satisfy
25
+ // audit-code-quality REPEATED_STRING rule.
26
+ const TEXTAREA_CHROME = "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";
23
27
  function formatBanAction(action) {
24
28
  return BANNED_ACTION_OPTIONS.find((o) => o.value === action)?.label ?? action;
25
29
  }
@@ -37,10 +41,10 @@ function HardBanPanel({ userId, isHardBanned, currentHardBanReason, showHardBanF
37
41
  return (_jsxs("div", { className: "mb-4 rounded-lg border border-zinc-200 bg-zinc-50 p-3 dark:border-zinc-700 dark:bg-zinc-900/40", children: [_jsxs("div", { className: "mb-2 flex items-center justify-between", children: [_jsx("span", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Hard ban" }), isHardBanned ? (_jsx("span", { className: "rounded-full bg-error-surface px-2 py-0.5 text-xs font-semibold text-error", children: "Banned" })) : (_jsx("span", { className: "rounded-full bg-success-surface px-2 py-0.5 text-xs font-semibold text-success", children: "Active" }))] }), isHardBanned ? (_jsxs("div", { className: "space-y-2", children: [currentHardBanReason && _jsxs(Text, { className: "text-xs text-zinc-600 dark:text-zinc-400", children: ["Reason: ", currentHardBanReason] }), _jsx(Button, { type: "button", variant: "secondary", size: "sm", isLoading: unbanPending, disabled: unbanPending, onClick: onUnban, children: "Lift hard ban" })] })) : showHardBanForm ? (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("label", { className: "text-xs font-medium text-zinc-700 dark:text-zinc-300", children: "Ban reason (required)" }), _jsx("textarea", { value: hardBanReasonInput, onChange: (e) => setHardBanReasonInput(e.target.value), rows: 2, placeholder: "e.g. Repeated fraud, scam activity\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-red-500" })] }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { type: "button", variant: "danger", size: "sm", isLoading: hardBanPending, disabled: !hardBanReasonInput.trim() || hardBanPending, onClick: () => onHardBan(hardBanReasonInput.trim()), children: "Confirm hard ban" }), _jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: () => { setShowHardBanForm(false); setHardBanReasonInput(""); }, children: "Cancel" })] })] })) : (_jsx(Button, { type: "button", variant: "danger", size: "sm", disabled: !userId, onClick: () => setShowHardBanForm(true), children: "Impose hard ban" }))] }));
38
42
  }
39
43
  function SoftBanPanel({ userId, softBans, showAddSoftBan, setShowAddSoftBan, softBanAction, setSoftBanAction, softBanReason, setSoftBanReason, softBanExpiry, setSoftBanExpiry, softBanPending, liftPending, onAddSoftBan, onLiftSoftBan, }) {
40
- return (_jsxs("div", { className: "rounded-lg border border-zinc-200 bg-zinc-50 p-3 dark:border-zinc-700 dark:bg-zinc-900/40", children: [_jsxs("div", { className: "mb-2 flex items-center justify-between", children: [_jsxs("span", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: ["Soft bans", softBans.length > 0 ? ` (${softBans.length})` : ""] }), !showAddSoftBan && (_jsx(Button, { type: "button", variant: "secondary", size: "sm", disabled: !userId, onClick: () => setShowAddSoftBan(true), children: "Add soft ban" }))] }), softBans.length > 0 && (_jsx("ul", { className: "mb-3 space-y-2", children: softBans.map((ban) => (_jsxs("li", { className: "flex items-start justify-between gap-2 rounded-md border border-zinc-200 bg-white px-3 py-2 text-xs dark:border-zinc-700 dark:bg-zinc-800", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "font-semibold text-zinc-800 dark:text-zinc-200", children: formatBanAction(ban.action) }), _jsx("div", { className: "text-zinc-500 dark:text-zinc-400", children: ban.reason }), _jsx("div", { className: "text-zinc-400 dark:text-zinc-400", children: formatExpiry(ban.expiresAt) })] }), _jsx(Button, { type: "button", variant: "secondary", size: "sm", isLoading: liftPending, disabled: liftPending, onClick: () => onLiftSoftBan(ban.action), children: "Lift" })] }, ban.action))) })), showAddSoftBan && (_jsxs("div", { className: "space-y-2", children: [_jsx(Select, { label: "Action to restrict", options: BANNED_ACTION_OPTIONS, value: softBanAction, onValueChange: setSoftBanAction }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("label", { className: "text-xs font-medium text-zinc-700 dark:text-zinc-300", children: "Reason (required)" }), _jsx("textarea", { value: softBanReason, onChange: (e) => setSoftBanReason(e.target.value), rows: 2, placeholder: "e.g. Suspicious bid activity\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", { className: "flex flex-col gap-1", children: [_jsx("label", { className: "text-xs font-medium text-zinc-700 dark:text-zinc-300", children: "Expires at (optional \u2014 leave blank for permanent)" }), _jsx("input", { type: "datetime-local", value: softBanExpiry, onChange: (e) => setSoftBanExpiry(e.target.value), 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 focus:outline-none focus:ring-2 focus:ring-primary-500" })] }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { type: "button", variant: "primary", size: "sm", isLoading: softBanPending, disabled: !softBanReason.trim() || softBanPending, onClick: () => onAddSoftBan({ action: softBanAction, reason: softBanReason.trim(), ...(softBanExpiry ? { expiresAt: new Date(softBanExpiry).toISOString() } : {}) }), children: "Apply soft ban" }), _jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: () => { setShowAddSoftBan(false); setSoftBanReason(""); setSoftBanExpiry(""); }, children: "Cancel" })] })] })), softBans.length === 0 && !showAddSoftBan && (_jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400", children: "No active soft bans." }))] }));
44
+ return (_jsxs("div", { className: "rounded-lg border border-zinc-200 bg-zinc-50 p-3 dark:border-zinc-700 dark:bg-zinc-900/40", children: [_jsxs("div", { className: "mb-2 flex items-center justify-between", children: [_jsxs("span", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: ["Soft bans", softBans.length > 0 ? ` (${softBans.length})` : ""] }), !showAddSoftBan && (_jsx(Button, { type: "button", variant: "secondary", size: "sm", disabled: !userId, onClick: () => setShowAddSoftBan(true), children: "Add soft ban" }))] }), softBans.length > 0 && (_jsx("ul", { className: "mb-3 space-y-2", children: softBans.map((ban) => (_jsxs("li", { className: "flex items-start justify-between gap-2 rounded-md border border-zinc-200 bg-white px-3 py-2 text-xs dark:border-zinc-700 dark:bg-zinc-800", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "font-semibold text-zinc-800 dark:text-zinc-200", children: formatBanAction(ban.action) }), _jsx("div", { className: "text-zinc-500 dark:text-zinc-400", children: ban.reason }), _jsx("div", { className: "text-zinc-400 dark:text-zinc-400", children: formatExpiry(ban.expiresAt) })] }), _jsx(Button, { type: "button", variant: "secondary", size: "sm", isLoading: liftPending, disabled: liftPending, onClick: () => onLiftSoftBan(ban.action), children: "Lift" })] }, ban.action))) })), showAddSoftBan && (_jsxs("div", { className: "space-y-2", children: [_jsx(Select, { label: "Action to restrict", options: BANNED_ACTION_OPTIONS, value: softBanAction, onValueChange: setSoftBanAction }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("label", { className: "text-xs font-medium text-zinc-700 dark:text-zinc-300", children: "Reason (required)" }), _jsx("textarea", { value: softBanReason, onChange: (e) => setSoftBanReason(e.target.value), rows: 2, placeholder: "e.g. Suspicious bid activity\u2026", className: TEXTAREA_CHROME })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("label", { className: "text-xs font-medium text-zinc-700 dark:text-zinc-300", children: "Expires at (optional \u2014 leave blank for permanent)" }), _jsx("input", { type: "datetime-local", value: softBanExpiry, onChange: (e) => setSoftBanExpiry(e.target.value), 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 focus:outline-none focus:ring-2 focus:ring-primary-500" })] }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { type: "button", variant: "primary", size: "sm", isLoading: softBanPending, disabled: !softBanReason.trim() || softBanPending, onClick: () => onAddSoftBan({ action: softBanAction, reason: softBanReason.trim(), ...(softBanExpiry ? { expiresAt: new Date(softBanExpiry).toISOString() } : {}) }), children: "Apply soft ban" }), _jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: () => { setShowAddSoftBan(false); setSoftBanReason(""); setSoftBanExpiry(""); }, children: "Cancel" })] })] })), softBans.length === 0 && !showAddSoftBan && (_jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400", children: "No active soft bans." }))] }));
41
45
  }
42
46
  // --- Component ---------------------------------------------------------------
43
- export function AdminUserEditorView({ open, onClose, userId, displayName, currentRole, currentIsDisabled, currentEmailVerified, ownedStoreId, ownedStoreName, currentSoftBans, currentIsHardBanned, currentHardBanReason, }) {
47
+ export function AdminUserEditorView({ open, onClose, userId, displayName, currentRole, currentIsDisabled, currentEmailVerified, ownedStoreId, ownedStoreName, currentSoftBans, currentIsHardBanned, currentHardBanReason, currentPhoneNumber, currentBio, currentLocation, currentWebsite, currentSocialLinks, }) {
44
48
  const queryClient = useQueryClient();
45
49
  const { showToast } = useToast();
46
50
  // --- General fields -------------------------------------------------------
@@ -48,6 +52,16 @@ export function AdminUserEditorView({ open, onClose, userId, displayName, curren
48
52
  const [emailVerified, setEmailVerified] = React.useState(currentEmailVerified ?? false);
49
53
  const [adminNotes, setAdminNotes] = React.useState("");
50
54
  const [deleteOpen, setDeleteOpen] = React.useState(false);
55
+ // --- ST-2 profile fields --------------------------------------------------
56
+ const [editDisplayName, setEditDisplayName] = React.useState(displayName ?? "");
57
+ const [phoneNumber, setPhoneNumber] = React.useState(currentPhoneNumber ?? "");
58
+ const [bio, setBio] = React.useState(currentBio ?? "");
59
+ const [location, setLocation] = React.useState(currentLocation ?? "");
60
+ const [website, setWebsite] = React.useState(currentWebsite ?? "");
61
+ const [twitter, setTwitter] = React.useState(currentSocialLinks?.twitter ?? "");
62
+ const [instagram, setInstagram] = React.useState(currentSocialLinks?.instagram ?? "");
63
+ const [facebook, setFacebook] = React.useState(currentSocialLinks?.facebook ?? "");
64
+ const [linkedin, setLinkedin] = React.useState(currentSocialLinks?.linkedin ?? "");
51
65
  // --- Hard ban form --------------------------------------------------------
52
66
  const [showHardBanForm, setShowHardBanForm] = React.useState(false);
53
67
  const [hardBanReasonInput, setHardBanReasonInput] = React.useState("");
@@ -61,6 +75,15 @@ export function AdminUserEditorView({ open, onClose, userId, displayName, curren
61
75
  setRole(currentRole ?? "user");
62
76
  setEmailVerified(currentEmailVerified ?? false);
63
77
  setAdminNotes("");
78
+ setEditDisplayName(displayName ?? "");
79
+ setPhoneNumber(currentPhoneNumber ?? "");
80
+ setBio(currentBio ?? "");
81
+ setLocation(currentLocation ?? "");
82
+ setWebsite(currentWebsite ?? "");
83
+ setTwitter(currentSocialLinks?.twitter ?? "");
84
+ setInstagram(currentSocialLinks?.instagram ?? "");
85
+ setFacebook(currentSocialLinks?.facebook ?? "");
86
+ setLinkedin(currentSocialLinks?.linkedin ?? "");
64
87
  setShowHardBanForm(false);
65
88
  setHardBanReasonInput("");
66
89
  setShowAddSoftBan(false);
@@ -68,15 +91,51 @@ export function AdminUserEditorView({ open, onClose, userId, displayName, curren
68
91
  setSoftBanReason("");
69
92
  setSoftBanExpiry("");
70
93
  }
71
- }, [open, currentRole, currentEmailVerified]);
94
+ }, [
95
+ open,
96
+ currentRole,
97
+ currentEmailVerified,
98
+ displayName,
99
+ currentPhoneNumber,
100
+ currentBio,
101
+ currentLocation,
102
+ currentWebsite,
103
+ currentSocialLinks?.twitter,
104
+ currentSocialLinks?.instagram,
105
+ currentSocialLinks?.facebook,
106
+ currentSocialLinks?.linkedin,
107
+ ]);
72
108
  const invalidate = () => queryClient.invalidateQueries({ queryKey: ["admin", "users"] });
73
109
  // --- Mutations ------------------------------------------------------------
74
110
  const saveMutation = useMutation({
75
111
  mutationFn: async () => {
112
+ // ST-2 — build publicProfile partial only when something changed; keeps
113
+ // the PATCH payload minimal and avoids overwriting unrelated subkeys.
114
+ const socialLinks = {};
115
+ if (twitter.trim())
116
+ socialLinks.twitter = twitter.trim();
117
+ if (instagram.trim())
118
+ socialLinks.instagram = instagram.trim();
119
+ if (facebook.trim())
120
+ socialLinks.facebook = facebook.trim();
121
+ if (linkedin.trim())
122
+ socialLinks.linkedin = linkedin.trim();
123
+ const publicProfile = {};
124
+ if (bio.trim())
125
+ publicProfile.bio = bio.trim();
126
+ if (location.trim())
127
+ publicProfile.location = location.trim();
128
+ if (website.trim())
129
+ publicProfile.website = website.trim();
130
+ if (Object.keys(socialLinks).length > 0)
131
+ publicProfile.socialLinks = socialLinks;
76
132
  await apiClient.patch(ADMIN_ENDPOINTS.USER_BY_ID(userId), {
77
133
  role,
78
134
  emailVerified,
79
135
  adminNotes: adminNotes || undefined,
136
+ displayName: editDisplayName.trim() || undefined,
137
+ phoneNumber: phoneNumber.trim() || undefined,
138
+ publicProfile: Object.keys(publicProfile).length > 0 ? publicProfile : undefined,
80
139
  });
81
140
  },
82
141
  onSuccess: () => {
@@ -160,8 +219,23 @@ export function AdminUserEditorView({ open, onClose, userId, displayName, curren
160
219
  });
161
220
  const isHardBanned = currentIsHardBanned ?? false;
162
221
  const softBans = currentSoftBans ?? [];
163
- return (_jsxs(_Fragment, { children: [_jsx(SideDrawer, { isOpen: open, onClose: onClose, title: displayName ? `Manage: ${displayName}` : "Manage User", children: _jsxs(Form, { onSubmit: (e) => {
222
+ const renderInfoCard = () => userId ? (_jsx("div", { className: "rounded-lg border border-zinc-200 bg-zinc-50 px-3 py-2 text-xs dark:border-zinc-700 dark:bg-zinc-900/40", children: _jsxs("div", { className: "flex flex-col gap-1 text-zinc-700 dark:text-zinc-300", children: [_jsxs(_Fragment, { children: [_jsx("span", { className: "font-semibold", children: "Owner ID (Firebase UID):" }), " ", _jsx("code", { className: "select-all font-mono", children: userId })] }), ownedStoreId && (_jsxs(_Fragment, { children: [_jsx("span", { className: "font-semibold", children: "Owns store:" }), " ", _jsx("code", { className: "select-all font-mono", children: ownedStoreId }), ownedStoreName ? ` — ${ownedStoreName}` : ""] }))] }) })) : null;
223
+ const renderRoleSection = () => (_jsx(Select, { label: "Role", options: ROLE_OPTIONS, value: role, onValueChange: setRole }));
224
+ const renderEmailVerifiedSection = () => (_jsx(Toggle, { label: "Email verified", checked: emailVerified, onChange: setEmailVerified }));
225
+ const renderProfileSection = () => (_jsxs("div", { className: "border-t border-zinc-200 pt-3 dark:border-zinc-700", children: [_jsx(Heading, { level: 3, className: "mb-3 text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Profile details" }), _jsxs("div", { className: "space-y-3", children: [_jsx(Input, { label: "Display name", value: editDisplayName, onChange: (e) => setEditDisplayName(e.target.value), placeholder: "Full name shown on profile" }), _jsx(Input, { label: "Phone number", type: "tel", value: phoneNumber, onChange: (e) => setPhoneNumber(e.target.value), placeholder: "+91 90000 00000" }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { children: "Bio" }), _jsx("textarea", { value: bio, onChange: (e) => setBio(e.target.value), rows: 3, placeholder: "Short bio shown on the public profile\u2026", className: TEXTAREA_CHROME })] }), _jsx(Input, { label: "Location", value: location, onChange: (e) => setLocation(e.target.value), placeholder: "City, Country" }), _jsx(Input, { label: "Website", type: "url", value: website, onChange: (e) => setWebsite(e.target.value), placeholder: "https://" }), _jsx(Text, { size: "xs", color: "muted", children: "Social links" }), _jsx(Input, { label: "Twitter / X", value: twitter, onChange: (e) => setTwitter(e.target.value), placeholder: "@handle or full URL" }), _jsx(Input, { label: "Instagram", value: instagram, onChange: (e) => setInstagram(e.target.value), placeholder: "@handle or full URL" }), _jsx(Input, { label: "Facebook", value: facebook, onChange: (e) => setFacebook(e.target.value), placeholder: "https://facebook.com/\u2026" }), _jsx(Input, { label: "LinkedIn", value: linkedin, onChange: (e) => setLinkedin(e.target.value), placeholder: "https://linkedin.com/in/\u2026" })] })] }));
226
+ const renderAdminNotesSection = () => (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { children: "Admin notes (optional)" }), _jsx("textarea", { value: adminNotes, onChange: (e) => setAdminNotes(e.target.value), rows: 3, placeholder: "Internal notes about this user\u2026", className: TEXTAREA_CHROME })] }));
227
+ const renderActionsSection = () => (_jsxs(FormActions, { align: "right", children: [_jsx(Button, { type: "button", variant: "danger", onClick: () => setDeleteOpen(true), disabled: !userId, children: "Delete user" }), _jsx(Button, { type: "button", variant: "secondary", onClick: onClose, children: "Cancel" }), _jsx(Button, { type: "submit", isLoading: saveMutation.isPending, disabled: !userId || saveMutation.isPending, children: "Save changes" })] }));
228
+ const renderModerationSection = () => (_jsxs("div", { className: "border-t border-zinc-200 pt-4 dark:border-zinc-700", children: [_jsx(Heading, { level: 3, className: "mb-3 text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Moderation" }), _jsx(HardBanPanel, { userId: userId, isHardBanned: isHardBanned, currentHardBanReason: currentHardBanReason, showHardBanForm: showHardBanForm, setShowHardBanForm: setShowHardBanForm, hardBanReasonInput: hardBanReasonInput, setHardBanReasonInput: setHardBanReasonInput, hardBanPending: hardBanMutation.isPending, unbanPending: unbanMutation.isPending, onHardBan: (reason) => hardBanMutation.mutate(reason), onUnban: () => unbanMutation.mutate() }), _jsx(SoftBanPanel, { userId: userId, softBans: softBans, showAddSoftBan: showAddSoftBan, setShowAddSoftBan: setShowAddSoftBan, softBanAction: softBanAction, setSoftBanAction: setSoftBanAction, softBanReason: softBanReason, setSoftBanReason: setSoftBanReason, softBanExpiry: softBanExpiry, setSoftBanExpiry: setSoftBanExpiry, softBanPending: softBanMutation.isPending, liftPending: liftSoftBanMutation.isPending, onAddSoftBan: (payload) => softBanMutation.mutate(payload), onLiftSoftBan: (action) => liftSoftBanMutation.mutate(action) })] }));
229
+ return (_jsxs(_Fragment, { children: [_jsx(SideDrawer, { isOpen: open, onClose: onClose, title: displayName ? `Manage: ${displayName}` : "Manage User", children: _jsx(Form, { onSubmit: (e) => {
164
230
  e.preventDefault();
165
231
  saveMutation.mutate();
166
- }, className: "space-y-4 p-4", children: [userId && (_jsx("div", { className: "rounded-lg border border-zinc-200 bg-zinc-50 px-3 py-2 text-xs dark:border-zinc-700 dark:bg-zinc-900/40", children: _jsxs("div", { className: "flex flex-col gap-1 text-zinc-700 dark:text-zinc-300", children: [_jsxs(_Fragment, { children: [_jsx("span", { className: "font-semibold", children: "Owner ID (Firebase UID):" }), " ", _jsx("code", { className: "select-all font-mono", children: userId })] }), ownedStoreId && (_jsxs(_Fragment, { children: [_jsx("span", { className: "font-semibold", children: "Owns store:" }), " ", _jsx("code", { className: "select-all font-mono", children: ownedStoreId }), ownedStoreName ? ` — ${ownedStoreName}` : ""] }))] }) })), _jsx(Select, { label: "Role", options: ROLE_OPTIONS, value: role, onValueChange: setRole }), _jsx(Toggle, { label: "Email verified", checked: emailVerified, onChange: setEmailVerified }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("label", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Admin notes (optional)" }), _jsx("textarea", { value: adminNotes, onChange: (e) => setAdminNotes(e.target.value), rows: 3, placeholder: "Internal notes about this user\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: "danger", onClick: () => setDeleteOpen(true), disabled: !userId, children: "Delete user" }), _jsx(Button, { type: "button", variant: "secondary", onClick: onClose, children: "Cancel" }), _jsx(Button, { type: "submit", isLoading: saveMutation.isPending, disabled: !userId || saveMutation.isPending, children: "Save changes" })] }), _jsxs("div", { className: "border-t border-zinc-200 pt-4 dark:border-zinc-700", children: [_jsx(Heading, { level: 3, className: "mb-3 text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Moderation" }), _jsx(HardBanPanel, { userId: userId, isHardBanned: isHardBanned, currentHardBanReason: currentHardBanReason, showHardBanForm: showHardBanForm, setShowHardBanForm: setShowHardBanForm, hardBanReasonInput: hardBanReasonInput, setHardBanReasonInput: setHardBanReasonInput, hardBanPending: hardBanMutation.isPending, unbanPending: unbanMutation.isPending, onHardBan: (reason) => hardBanMutation.mutate(reason), onUnban: () => unbanMutation.mutate() }), _jsx(SoftBanPanel, { userId: userId, softBans: softBans, showAddSoftBan: showAddSoftBan, setShowAddSoftBan: setShowAddSoftBan, softBanAction: softBanAction, setSoftBanAction: setSoftBanAction, softBanReason: softBanReason, setSoftBanReason: setSoftBanReason, softBanExpiry: softBanExpiry, setSoftBanExpiry: setSoftBanExpiry, softBanPending: softBanMutation.isPending, liftPending: liftSoftBanMutation.isPending, onAddSoftBan: (payload) => softBanMutation.mutate(payload), onLiftSoftBan: (action) => liftSoftBanMutation.mutate(action) })] })] }) }), _jsx(ConfirmDeleteModal, { isOpen: deleteOpen, onClose: () => setDeleteOpen(false), onConfirm: () => deleteMutation.mutate(), isDeleting: deleteMutation.isPending, title: `Delete ${displayName ?? "user"}?`, message: "This action cannot be undone. The user's account and all associated data will be permanently removed.", confirmText: "Delete user", variant: "danger" })] }));
232
+ }, className: "p-4", children: _jsx(StackedViewShell, { portal: "admin", className: "space-y-4", sections: [
233
+ renderInfoCard,
234
+ renderRoleSection,
235
+ renderEmailVerifiedSection,
236
+ renderProfileSection,
237
+ renderAdminNotesSection,
238
+ renderActionsSection,
239
+ renderModerationSection,
240
+ ] }) }) }), _jsx(ConfirmDeleteModal, { isOpen: deleteOpen, onClose: () => setDeleteOpen(false), onConfirm: () => deleteMutation.mutate(), isDeleting: deleteMutation.isPending, title: `Delete ${displayName ?? "user"}?`, message: "This action cannot be undone. The user's account and all associated data will be permanently removed.", confirmText: "Delete user", variant: "danger" })] }));
167
241
  }
@@ -1,4 +1,3 @@
1
- import type { ListingViewShellProps } from "../../../ui";
2
- export interface AdminUsersViewProps extends ListingViewShellProps {
3
- }
1
+ import type { ListingLayoutProps } from "../../../ui";
2
+ export type AdminUsersViewProps = ListingLayoutProps;
4
3
  export declare function AdminUsersView({ children, ...props }: AdminUsersViewProps): import("react/jsx-runtime").JSX.Element;