@mohasinac/appkit 2.7.57 → 2.7.59

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 (245) hide show
  1. package/dist/_internal/client/features/layout/DashboardLayoutClient.d.ts +7 -1
  2. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +8 -2
  3. package/dist/_internal/server/features/scams/og.js +1 -1
  4. package/dist/_internal/shared/actions/bulk-helpers.d.ts +3 -0
  5. package/dist/_internal/shared/actions/bulk-helpers.js +19 -0
  6. package/dist/_internal/shared/config/schema.d.ts +4 -4
  7. package/dist/client.d.ts +4 -1
  8. package/dist/client.js +3 -1
  9. package/dist/configs/next.js +11 -0
  10. package/dist/configs/tailwind.d.ts +16 -3
  11. package/dist/configs/tailwind.js +18 -5
  12. package/dist/features/account/components/AddressBook.js +1 -1
  13. package/dist/features/account/components/AddressesIndexListing.js +3 -4
  14. package/dist/features/account/components/BuyerAccountGuideView.js +7 -7
  15. package/dist/features/account/components/BuyerAuctionsGuideView.js +7 -7
  16. package/dist/features/account/components/BuyerOrdersGuideView.js +6 -6
  17. package/dist/features/account/components/BuyerShoppingGuideView.js +7 -7
  18. package/dist/features/account/components/UserOffersPanel.js +1 -1
  19. package/dist/features/account/components/UserSidebar.js +14 -10
  20. package/dist/features/account/components/UserSupportView.js +4 -4
  21. package/dist/features/admin/components/AdminAdsView.js +1 -1
  22. package/dist/features/admin/components/AdminAllEventEntriesView.js +4 -10
  23. package/dist/features/admin/components/AdminAnalyticsGuideView.js +3 -3
  24. package/dist/features/admin/components/AdminBidsView.js +3 -9
  25. package/dist/features/admin/components/AdminBlogView.js +4 -9
  26. package/dist/features/admin/components/AdminBrandEditorView.js +14 -17
  27. package/dist/features/admin/components/AdminBrandsView.js +4 -9
  28. package/dist/features/admin/components/AdminBundlesView.js +40 -59
  29. package/dist/features/admin/components/AdminCarouselView.js +8 -21
  30. package/dist/features/admin/components/AdminCartsView.js +3 -4
  31. package/dist/features/admin/components/AdminCatalogGuideView.js +5 -5
  32. package/dist/features/admin/components/AdminCategoriesView.js +4 -9
  33. package/dist/features/admin/components/AdminCategoryEditorView.js +1 -5
  34. package/dist/features/admin/components/AdminContactEditorView.js +2 -2
  35. package/dist/features/admin/components/AdminContactView.js +7 -25
  36. package/dist/features/admin/components/AdminContentGuideView.js +6 -6
  37. package/dist/features/admin/components/AdminCouponEditorView.js +14 -17
  38. package/dist/features/admin/components/AdminCouponsView.js +8 -16
  39. package/dist/features/admin/components/AdminFaqEditorView.js +14 -17
  40. package/dist/features/admin/components/AdminFaqsView.js +18 -69
  41. package/dist/features/admin/components/AdminFeatureEditorView.js +7 -9
  42. package/dist/features/admin/components/AdminFeatureFlagsView.js +1 -1
  43. package/dist/features/admin/components/AdminFeaturesView.js +1 -1
  44. package/dist/features/admin/components/AdminGuideHubView.js +1 -1
  45. package/dist/features/admin/components/AdminHistoryView.js +1 -1
  46. package/dist/features/admin/components/AdminListingScaffold.js +1 -1
  47. package/dist/features/admin/components/AdminNewsletterView.js +5 -15
  48. package/dist/features/admin/components/AdminNotificationsView.js +3 -9
  49. package/dist/features/admin/components/AdminOrdersGuideView.js +5 -5
  50. package/dist/features/admin/components/AdminOrdersView.js +3 -9
  51. package/dist/features/admin/components/AdminPayoutsView.js +3 -9
  52. package/dist/features/admin/components/AdminPrizeDrawsView.js +4 -9
  53. package/dist/features/admin/components/AdminProductEditorView.js +1 -5
  54. package/dist/features/admin/components/AdminProductsView.js +5 -10
  55. package/dist/features/admin/components/AdminReturnRequestsView.js +1 -1
  56. package/dist/features/admin/components/AdminReviewsView.js +3 -9
  57. package/dist/features/admin/components/AdminScammerEditorView.js +3 -3
  58. package/dist/features/admin/components/AdminScammersView.js +6 -12
  59. package/dist/features/admin/components/AdminSectionsView.js +1 -1
  60. package/dist/features/admin/components/AdminSessionsView.js +3 -9
  61. package/dist/features/admin/components/AdminSiteSettingsView.js +1 -1
  62. package/dist/features/admin/components/AdminStoreAddressesView.js +1 -1
  63. package/dist/features/admin/components/AdminStoresGuideView.js +6 -6
  64. package/dist/features/admin/components/AdminStoresView.js +3 -9
  65. package/dist/features/admin/components/AdminSublistingCategoriesView.js +3 -7
  66. package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +17 -20
  67. package/dist/features/admin/components/AdminSupportTicketDetailView.js +4 -4
  68. package/dist/features/admin/components/AdminSupportTicketsView.js +9 -15
  69. package/dist/features/admin/components/AdminTeamGuideView.js +4 -4
  70. package/dist/features/admin/components/AdminTeamView.js +6 -15
  71. package/dist/features/admin/components/AdminTrustGuideView.js +5 -5
  72. package/dist/features/admin/components/AdminUserEditorView.js +1 -1
  73. package/dist/features/admin/components/AdminUsersGuideView.js +5 -5
  74. package/dist/features/admin/components/AdminUsersView.js +3 -9
  75. package/dist/features/admin/components/AdminViewCards.js +1 -1
  76. package/dist/features/admin/components/AdminWishlistsView.js +1 -1
  77. package/dist/features/admin/components/DataTable.js +1 -1
  78. package/dist/features/admin/hooks/useAdminListing.d.ts +58 -0
  79. package/dist/features/admin/hooks/useAdminListing.js +71 -0
  80. package/dist/features/auctions/components/AuctionBidsTable.js +1 -1
  81. package/dist/features/auctions/components/AuctionDetailPageView.js +2 -2
  82. package/dist/features/auctions/components/MarketplaceAuctionCard.js +2 -2
  83. package/dist/features/auctions/components/PlaceBidFormClient.js +1 -1
  84. package/dist/features/auth/components/VerifyEmailView.js +1 -1
  85. package/dist/features/auth/schemas/firestore.d.ts +1 -0
  86. package/dist/features/blog/components/BlogIndexListing.js +3 -6
  87. package/dist/features/blog/components/BlogListView.js +1 -1
  88. package/dist/features/blog/components/BlogPostView.js +1 -1
  89. package/dist/features/cart/components/CartDrawer.js +1 -1
  90. package/dist/features/categories/components/CategoriesIndexListing.js +3 -6
  91. package/dist/features/categories/components/CategoryDetailPageView.js +1 -1
  92. package/dist/features/checkout/components/CheckoutStepper.js +1 -1
  93. package/dist/features/collections/components/CollectionCard.js +1 -1
  94. package/dist/features/copilot/components/AdminCopilotView.js +2 -2
  95. package/dist/features/events/components/AdminEventsView.js +4 -4
  96. package/dist/features/events/components/EventPollWidget.js +2 -2
  97. package/dist/features/events/components/EventStatusBadge.js +4 -4
  98. package/dist/features/events/components/EventsIndexListing.js +3 -4
  99. package/dist/features/events/components/SpinWheelView.js +1 -1
  100. package/dist/features/faq/components/FAQAccordion.js +2 -2
  101. package/dist/features/forms/Input.js +3 -3
  102. package/dist/features/forms/Select.js +2 -2
  103. package/dist/features/forms/Textarea.js +2 -2
  104. package/dist/features/forms/utils.d.ts +1 -1
  105. package/dist/features/forms/utils.js +1 -1
  106. package/dist/features/homepage/components/AnnouncementBar.d.ts +4 -1
  107. package/dist/features/homepage/components/AnnouncementBar.js +51 -4
  108. package/dist/features/homepage/components/CharacterHotspotForm.js +2 -2
  109. package/dist/features/homepage/components/MarketplaceHomepageView.d.ts +3 -1
  110. package/dist/features/homepage/components/MarketplaceHomepageView.js +2 -2
  111. package/dist/features/homepage/components/index.d.ts +1 -1
  112. package/dist/features/homepage/components/index.js +1 -1
  113. package/dist/features/homepage/lib/section-renderer.d.ts +2 -2
  114. package/dist/features/homepage/lib/section-renderer.js +2 -2
  115. package/dist/features/layout/BottomActions.js +2 -2
  116. package/dist/features/layout/ListingLayout.js +3 -3
  117. package/dist/features/layout/TitleBarLayout.js +1 -1
  118. package/dist/features/media/index.d.ts +2 -0
  119. package/dist/features/media/index.js +1 -0
  120. package/dist/features/media/modals/ImageCropModal.js +1 -1
  121. package/dist/features/media/modals/ImageEditor.d.ts +12 -0
  122. package/dist/features/media/modals/ImageEditor.js +73 -0
  123. package/dist/features/media/upload/ImageUpload.d.ts +5 -1
  124. package/dist/features/media/upload/ImageUpload.js +33 -8
  125. package/dist/features/media/upload/MediaUploadField.d.ts +5 -1
  126. package/dist/features/media/upload/MediaUploadField.js +26 -12
  127. package/dist/features/orders/components/OrdersList.js +7 -7
  128. package/dist/features/orders/components/RefundHistoryTable.js +2 -2
  129. package/dist/features/orders/components/RefundRequestView.js +3 -3
  130. package/dist/features/orders/repository/orders.repository.d.ts +0 -1
  131. package/dist/features/orders/repository/orders.repository.js +0 -1
  132. package/dist/features/orders/server.d.ts +1 -1
  133. package/dist/features/orders/server.js +1 -1
  134. package/dist/features/pre-orders/components/PreOrderActionsClient.js +1 -1
  135. package/dist/features/pre-orders/components/PreOrderBadge.js +4 -4
  136. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +1 -1
  137. package/dist/features/pre-orders/components/PreorderCard.js +2 -2
  138. package/dist/features/products/components/CustomSectionsEditor.js +1 -1
  139. package/dist/features/products/components/GroupSettingsPanel.js +64 -48
  140. package/dist/features/products/components/MakeOfferButton.js +2 -2
  141. package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -2
  142. package/dist/features/products/components/PrizeDrawItemsEditor.js +3 -3
  143. package/dist/features/products/components/PrizeRevealModal.js +3 -3
  144. package/dist/features/products/components/ProductDetailPageView.js +4 -4
  145. package/dist/features/products/components/ProductFeaturesSelector.js +1 -1
  146. package/dist/features/products/components/ProductGrid.js +3 -3
  147. package/dist/features/products/repository/products.repository.d.ts +0 -2
  148. package/dist/features/products/repository/products.repository.js +0 -2
  149. package/dist/features/products/server.d.ts +1 -1
  150. package/dist/features/products/server.js +1 -1
  151. package/dist/features/promotions/components/CouponCard.js +7 -7
  152. package/dist/features/promotions/components/CouponsIndexListing.js +3 -2
  153. package/dist/features/promotions/components/PromotionsView.js +1 -1
  154. package/dist/features/reviews/components/ReviewDetailShell.js +2 -2
  155. package/dist/features/reviews/components/ReviewsIndexListing.js +3 -4
  156. package/dist/features/reviews/components/ReviewsList.js +1 -1
  157. package/dist/features/reviews/repository/reviews.repository.d.ts +0 -1
  158. package/dist/features/reviews/repository/reviews.repository.js +0 -1
  159. package/dist/features/reviews/server.d.ts +1 -1
  160. package/dist/features/reviews/server.js +1 -1
  161. package/dist/features/seller/components/SellerAddressesView.js +11 -21
  162. package/dist/features/seller/components/SellerAnalyticsAlertsView.js +2 -2
  163. package/dist/features/seller/components/SellerAuctionsView.js +14 -23
  164. package/dist/features/seller/components/SellerBidsView.js +6 -6
  165. package/dist/features/seller/components/SellerBundlesView.js +13 -21
  166. package/dist/features/seller/components/SellerClassifiedView.js +14 -22
  167. package/dist/features/seller/components/SellerCouponEditorView.js +2 -2
  168. package/dist/features/seller/components/SellerCouponsView.js +14 -20
  169. package/dist/features/seller/components/SellerDigitalCodesView.js +13 -21
  170. package/dist/features/seller/components/SellerFeaturesView.js +1 -1
  171. package/dist/features/seller/components/SellerGroupedListingsView.js +6 -10
  172. package/dist/features/seller/components/SellerLiveView.js +15 -23
  173. package/dist/features/seller/components/SellerOffersPanel.js +2 -2
  174. package/dist/features/seller/components/SellerOffersView.js +4 -5
  175. package/dist/features/seller/components/SellerOrdersView.js +9 -23
  176. package/dist/features/seller/components/SellerPayoutMethodsView.js +13 -25
  177. package/dist/features/seller/components/SellerPayoutsView.js +4 -5
  178. package/dist/features/seller/components/SellerPreOrdersView.js +13 -22
  179. package/dist/features/seller/components/SellerPrizeDrawsView.js +13 -22
  180. package/dist/features/seller/components/SellerProductsCards.js +1 -1
  181. package/dist/features/seller/components/SellerProductsFilterDrawer.d.ts +1 -1
  182. package/dist/features/seller/components/SellerProductsFilterDrawer.js +3 -6
  183. package/dist/features/seller/components/SellerProductsView.js +10 -23
  184. package/dist/features/seller/components/SellerReviewsView.js +1 -1
  185. package/dist/features/seller/components/SellerShippingConfigsView.js +14 -26
  186. package/dist/features/seller/components/SellerStoreCategoriesView.js +16 -35
  187. package/dist/features/seller/components/SellerTemplatesView.js +27 -43
  188. package/dist/features/seller/components/analytics/SellerTopProducts.js +1 -1
  189. package/dist/features/stores/components/StoreFinanceGuideView.js +2 -2
  190. package/dist/features/stores/components/StoreHeader.js +1 -1
  191. package/dist/features/stores/components/StoreListingsGuideView.js +3 -3
  192. package/dist/features/stores/components/StoreOrdersGuideView.js +4 -4
  193. package/dist/features/stores/components/StoreReviewsListing.js +3 -4
  194. package/dist/features/stores/components/StoreSettingsGuideView.js +2 -2
  195. package/dist/features/stores/components/StoresIndexListing.js +3 -4
  196. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +4 -4
  197. package/dist/features/wishlist/components/WishlistPage.js +1 -1
  198. package/dist/index.d.ts +4 -6
  199. package/dist/index.js +6 -12
  200. package/dist/react/contexts/SessionContext.d.ts +2 -0
  201. package/dist/react/contexts/SessionContext.js +2 -0
  202. package/dist/react/hooks/useEntityDelete.d.ts +15 -0
  203. package/dist/react/hooks/useEntityDelete.js +39 -0
  204. package/dist/react/index.d.ts +2 -0
  205. package/dist/react/index.js +2 -0
  206. package/dist/repositories/index.d.ts +3 -3
  207. package/dist/repositories/index.js +3 -3
  208. package/dist/styles.css +286 -3
  209. package/dist/tailwind-utilities.css +1 -1
  210. package/dist/tokens/motion.d.ts +162 -0
  211. package/dist/tokens/motion.js +89 -0
  212. package/dist/ui/DataTable.js +3 -2
  213. package/dist/ui/components/Accordion.js +2 -1
  214. package/dist/ui/components/Card.d.ts +5 -2
  215. package/dist/ui/components/Card.js +29 -11
  216. package/dist/ui/components/Div.d.ts +2 -16
  217. package/dist/ui/components/Div.js +2 -16
  218. package/dist/ui/components/Layout.d.ts +9 -19
  219. package/dist/ui/components/Layout.js +9 -7
  220. package/dist/ui/components/ListingFilterDrawer.d.ts +10 -0
  221. package/dist/ui/components/ListingFilterDrawer.js +8 -0
  222. package/dist/ui/components/Modal.js +7 -4
  223. package/dist/ui/components/Motion.d.ts +75 -0
  224. package/dist/ui/components/Motion.js +122 -0
  225. package/dist/ui/components/Semantic.d.ts +81 -14
  226. package/dist/ui/components/Semantic.js +75 -10
  227. package/dist/ui/components/Semantic.style.css +261 -2
  228. package/dist/ui/components/SideDrawer.d.ts +1 -1
  229. package/dist/ui/components/SideDrawer.js +8 -6
  230. package/dist/ui/components/SideModal.d.ts +1 -1
  231. package/dist/ui/components/SideModal.js +11 -9
  232. package/dist/ui/components/StackedViewShell.js +6 -1
  233. package/dist/ui/components/Toast.js +5 -2
  234. package/dist/ui/components/Typography.d.ts +44 -3
  235. package/dist/ui/components/Typography.js +15 -30
  236. package/dist/ui/components/Typography.style.css +24 -0
  237. package/dist/ui/components/VacationBanner.js +2 -1
  238. package/dist/ui/components/surface-tokens.d.ts +70 -0
  239. package/dist/ui/components/surface-tokens.js +68 -0
  240. package/dist/ui/forms/FormShell.d.ts +6 -1
  241. package/dist/ui/forms/FormShell.js +32 -4
  242. package/dist/ui/index.d.ts +11 -2
  243. package/dist/ui/index.js +5 -2
  244. package/dist/validation/schemas.d.ts +28 -28
  245. package/package.json +3 -1
@@ -1,10 +1,11 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import React, { useState, useCallback } from "react";
4
- import { X, Plus } from "lucide-react";
4
+ import { useEntityDelete } from "../../../react/hooks/useEntityDelete";
5
+ import { Plus } from "lucide-react";
5
6
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
7
  import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
7
- import { Button, Div, ListingToolbar, Pagination, ListingViewShell, Text, useToast } from "../../../ui";
8
+ import { Button, Div, ListingFilterDrawer, ListingToolbar, Pagination, ListingViewShell, Text, useToast } from "../../../ui";
8
9
  import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
9
10
  import { toRecordArray, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
10
11
  import { CouponCard } from "../../promotions/components/CouponCard";
@@ -33,7 +34,11 @@ export function SellerCouponsView({ onCreateClick, onEditClick, onToggle, onDele
33
34
  const hasChildren = React.Children.count(children) > 0;
34
35
  const [view, setView] = useState("table");
35
36
  const [togglingId, setTogglingId] = useState(null);
36
- const [deletingId, setDeletingId] = useState(null);
37
+ const { deletingId, handleDelete: performDelete } = useEntityDelete({
38
+ deleteFn: onDelete,
39
+ successMessage: "Coupon deleted.",
40
+ onSuccess: () => { refetch?.(); },
41
+ });
37
42
  const { showToast } = useToast();
38
43
  const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
39
44
  const [searchInput, setSearchInput] = useState(table.get("q") || "");
@@ -102,26 +107,15 @@ export function SellerCouponsView({ onCreateClick, onEditClick, onToggle, onDele
102
107
  const handleDelete = useCallback(async (id) => {
103
108
  if (!onDelete)
104
109
  return;
105
- setDeletingId(id);
106
- try {
107
- await onDelete(id);
108
- refetch?.();
109
- showToast("Coupon deleted.", "success");
110
- }
111
- catch (err) {
112
- showToast(err instanceof Error ? err.message : "Failed to delete coupon.", "error");
113
- }
114
- finally {
115
- setDeletingId(null);
116
- }
117
- }, [onDelete, refetch, showToast]);
110
+ await performDelete(id);
111
+ }, [onDelete, performDelete]);
118
112
  const selection = useBulkSelection({ items: rows, keyExtractor: (r) => r.id });
119
113
  if (hasChildren) {
120
114
  return _jsx(ListingViewShell, { portal: "seller", ...props, children: children });
121
115
  }
122
116
  return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search by coupon code", 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, extra: onCreateClick
123
117
  ? (_jsxs(Button, { size: "sm", onClick: onCreateClick, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: "Add Coupon" })] }))
124
- : undefined }), 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-red-50 dark:bg-red-950/40 dark:border-red-900/60 px-4 py-3 text-sm text-red-700 dark:text-red-200", children: errorMessage })), isLoading ? (_jsx(Div, { className: "fluid-grid-card gap-3", children: Array.from({ length: 6 }).map((_, i) => (_jsxs(Div, { className: "rounded-xl border-2 border-zinc-100 dark:border-slate-700 p-4 animate-pulse space-y-3", children: [_jsx(Div, { className: "h-6 bg-zinc-200 dark:bg-slate-700 rounded w-2/3" }), _jsx(Div, { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx(Div, { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-1/2" })] }, i))) })) : rows.length === 0 ? (_jsx(Div, { className: "py-16 text-center", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-400", children: "No coupons found \u2014 create your first coupon" }) })) : (_jsx(Div, { className: "fluid-grid-card gap-3", children: rows.map((row) => (_jsx(CouponCard, { coupon: row.raw, onEdit: onEditClick ? handleEdit : undefined, onToggleActive: onToggle ? handleToggle : undefined, onDelete: onDelete ? handleDelete : undefined, className: togglingId === row.id || deletingId === row.id ? "pointer-events-none opacity-60" : undefined }, row.id))) }))] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 dark:text-zinc-400 hover:text-rose-500 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsxs("div", { className: "space-y-2", children: [_jsx(Text, { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Status" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Active", value: "true" }, { label: "Inactive", value: "false" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isActive: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isActive || "") === opt.value
125
- ? "bg-[var(--appkit-color-primary)] text-white border-[var(--appkit-color-primary)]"
126
- : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-[var(--appkit-color-primary)] py-2.5 text-sm font-semibold text-white transition-colors active:scale-[0.98]", children: ["Apply", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }))] }));
118
+ : undefined }), 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 dark:border-red-900/60 px-4 py-3 text-sm text-error", children: errorMessage })), isLoading ? (_jsx(Div, { className: "fluid-grid-card gap-3", children: Array.from({ length: 6 }).map((_, i) => (_jsxs(Div, { className: "rounded-xl border-2 border-zinc-100 dark:border-slate-700 p-4 animate-pulse space-y-3", children: [_jsx(Div, { className: "h-6 bg-zinc-200 dark:bg-slate-700 rounded w-2/3" }), _jsx(Div, { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx(Div, { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-1/2" })] }, i))) })) : rows.length === 0 ? (_jsx(Div, { className: "py-16 text-center", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-400", children: "No coupons found \u2014 create your first coupon" }) })) : (_jsx(Div, { className: "fluid-grid-card gap-3", children: rows.map((row) => (_jsx(CouponCard, { coupon: row.raw, onEdit: onEditClick ? handleEdit : undefined, onToggleActive: onToggle ? handleToggle : undefined, onDelete: onDelete ? handleDelete : undefined, className: togglingId === row.id || deletingId === row.id ? "pointer-events-none opacity-60" : undefined }, row.id))) }))] }), _jsx(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearFilters, activeCount: activeFilterCount, children: _jsxs("div", { className: "space-y-2", children: [_jsx(Text, { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Status" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Active", value: "true" }, { label: "Inactive", value: "false" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isActive: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isActive || "") === opt.value
119
+ ? "bg-[var(--appkit-color-primary)] text-white border-[var(--appkit-color-primary)]"
120
+ : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] }) })] }));
127
121
  }
@@ -1,10 +1,11 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useCallback } from "react";
4
+ import { useEntityDelete } from "../../../react/hooks/useEntityDelete";
4
5
  import { Plus } from "lucide-react";
5
6
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
7
  import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
7
- import { BulkActionBar, Button, ConfirmDeleteModal, DataTable, Div, ListingToolbar, Pagination, RowActionMenu, Text, useToast, } from "../../../ui";
8
+ import { BulkActionBar, Button, ConfirmDeleteModal, DataTable, Div, ListingToolbar, Pagination, RowActionMenu, Text, } from "../../../ui";
8
9
  import { useBottomActions } from "../../layout";
9
10
  import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
10
11
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
@@ -49,7 +50,7 @@ const COLUMNS = [
49
50
  key: "status",
50
51
  header: "Status",
51
52
  render: (row) => (_jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium capitalize ${row.status === "active"
52
- ? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300"
53
+ ? "bg-success-surface text-success"
53
54
  : "bg-zinc-100 text-zinc-600 dark:bg-slate-800 dark:text-slate-400"}`, children: row.status })),
54
55
  },
55
56
  {
@@ -63,8 +64,12 @@ export function SellerDigitalCodesView({ onCreateClick, onEditClick, onDelete, o
63
64
  const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
64
65
  const [view] = useState("table");
65
66
  const [deleteTargetId, setDeleteTargetId] = useState(null);
66
- const [deletingId, setDeletingId] = useState(null);
67
- const { showToast } = useToast();
67
+ const { deletingId, handleDelete: performDelete } = useEntityDelete({
68
+ endpoint: (id) => `/api/store/products/${id}`,
69
+ deleteFn: onDelete,
70
+ successMessage: "Code deleted.",
71
+ fetchOptions: { credentials: "include" },
72
+ });
68
73
  const commitSearch = useCallback(() => {
69
74
  table.set(TABLE_KEYS.QUERY, searchInput.trim());
70
75
  }, [searchInput, table]);
@@ -109,22 +114,9 @@ export function SellerDigitalCodesView({ onCreateClick, onEditClick, onDelete, o
109
114
  }]
110
115
  : [];
111
116
  const handleDelete = useCallback(async (id) => {
112
- setDeletingId(id);
113
- try {
114
- if (onDelete)
115
- await onDelete(id);
116
- else
117
- await fetch(`/api/store/products/${id}`, { method: "DELETE", credentials: "include" });
118
- showToast("Code deleted.", "success");
119
- }
120
- catch (err) {
121
- showToast(err instanceof Error ? err.message : "Failed to delete code.", "error");
122
- }
123
- finally {
124
- setDeletingId(null);
125
- setDeleteTargetId(null);
126
- }
127
- }, [onDelete, showToast]);
117
+ await performDelete(id);
118
+ setDeleteTargetId(null);
119
+ }, [performDelete]);
128
120
  const handleEdit = useCallback((id) => {
129
121
  if (onEditClick)
130
122
  onEditClick(id);
@@ -140,7 +132,7 @@ export function SellerDigitalCodesView({ onCreateClick, onEditClick, onDelete, o
140
132
  }
141
133
  }, [onCreateClick]);
142
134
  useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: bulkActions } } : {});
143
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: 0, searchValue: searchInput, searchPlaceholder: "Search digital code products...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, showTableView: true, view: view, onViewChange: () => { }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: handleCreate, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: "New Digital Code" })] }) }), 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) }) })), selection.selectedCount > 0 && bulkActions.length > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx(Div, { className: "mb-4 rounded-xl border border-red-200 bg-red-50 dark:bg-red-950/40 dark:border-red-900/60 px-4 py-3 text-sm text-red-700 dark:text-red-200", children: errorMessage })), isLoading ? (_jsx(Div, { className: "space-y-2", children: Array.from({ length: 5 }).map((_, i) => (_jsx(Div, { className: "h-14 animate-pulse rounded-xl border border-zinc-100 dark:border-slate-700 bg-zinc-50 dark:bg-slate-800" }, i))) })) : rows.length === 0 ? (_jsx(Div, { className: "py-16 text-center", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-400", children: "No digital code products yet \u2014 sell Steam keys, gift cards, and more" }) })) : (_jsx(DataTable, { columns: COLUMNS, data: rows, keyExtractor: (r) => r.id, selectable: bulkActions.length > 0, selectedIds: selection.selectedIds, onSelectionChange: (ids) => selection.setSelectedIds(ids), actions: (row) => (_jsx(RowActionMenu, { actions: [
135
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: 0, searchValue: searchInput, searchPlaceholder: "Search digital code products...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, showTableView: true, view: view, onViewChange: () => { }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: handleCreate, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: "New Digital Code" })] }) }), 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) }) })), selection.selectedCount > 0 && bulkActions.length > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), _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 dark:border-red-900/60 px-4 py-3 text-sm text-error", children: errorMessage })), isLoading ? (_jsx(Div, { className: "space-y-2", children: Array.from({ length: 5 }).map((_, i) => (_jsx(Div, { className: "h-14 animate-pulse rounded-xl border border-zinc-100 dark:border-slate-700 bg-zinc-50 dark:bg-slate-800" }, i))) })) : rows.length === 0 ? (_jsx(Div, { className: "py-16 text-center", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-400", children: "No digital code products yet \u2014 sell Steam keys, gift cards, and more" }) })) : (_jsx(DataTable, { columns: COLUMNS, data: rows, keyExtractor: (r) => r.id, selectable: bulkActions.length > 0, selectedIds: selection.selectedIds, onSelectionChange: (ids) => selection.setSelectedIds(ids), actions: (row) => (_jsx(RowActionMenu, { actions: [
144
136
  {
145
137
  label: ACTIONS.STORE["edit-listing"].label,
146
138
  onClick: () => handleEdit(row.id),
@@ -15,7 +15,7 @@ const TOAST = {
15
15
  DISABLED: "Feature disabled.",
16
16
  };
17
17
  const ROW_CLASS = "flex items-center justify-between gap-3 px-4 py-3";
18
- const CAP_BANNER_CLASS = "rounded-xl border border-amber-200 dark:border-amber-900/60 bg-amber-50 dark:bg-amber-950/40 px-4 py-2.5 text-xs text-amber-800 dark:text-amber-200";
18
+ const CAP_BANNER_CLASS = "rounded-xl border border-amber-200 dark:border-amber-900/60 bg-warning-surface px-4 py-2.5 text-xs text-warning";
19
19
  const EMPTY_STATE_CLASS = "rounded-xl border border-zinc-200 dark:border-slate-700 bg-white dark:bg-slate-900 p-6 text-center text-sm text-zinc-500 dark:text-zinc-400";
20
20
  const LIST_CLASS = "divide-y divide-zinc-200 dark:divide-slate-700 rounded-xl border border-zinc-200 dark:border-slate-700 bg-white dark:bg-slate-900";
21
21
  function unwrap(res) {
@@ -7,6 +7,7 @@ import { Badge, BulkActionBar, Button, ListingToolbar, Pagination } from "../../
7
7
  import { useBottomActions } from "../../layout";
8
8
  import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
9
9
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
10
+ import { buildBulkAction } from "../../../_internal/shared/actions/bulk-helpers";
10
11
  import { toRecordArray, toRelativeDate, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
11
12
  import { DataTable } from "../../admin/components/DataTable";
12
13
  // ---------------------------------------------------------------------------
@@ -99,16 +100,11 @@ export function SellerGroupedListingsView({ onCreateClick, onEditClick, onDelete
99
100
  const totalPages = Math.ceil(total / PAGE_SIZE);
100
101
  const selection = useBulkSelection({ items: rows, keyExtractor: (r) => r.id });
101
102
  const bulkActions = [
102
- {
103
- id: "delete",
104
- label: ACTIONS.STORE["delete-listing"].label,
105
- variant: "danger",
106
- onClick: () => {
107
- for (const id of selection.selectedIds)
108
- onDeleteClick?.(id);
109
- selection.clearSelection();
110
- },
111
- },
103
+ buildBulkAction(ACTIONS.STORE["delete-listing"], () => {
104
+ for (const id of selection.selectedIds)
105
+ onDeleteClick?.(id);
106
+ selection.clearSelection();
107
+ }),
112
108
  ];
113
109
  useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: bulkActions } } : {});
114
110
  return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { searchValue: searchInput, searchPlaceholder: "Search grouped listings", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: onCreateClick ? (_jsx(Button, { size: "sm", onClick: onCreateClick, children: "+ New Group" })) : null }), selection.selectedCount > 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) }) })), _jsx(DataTable, { columns: COLUMNS, rows: rows, isLoading: isLoading, emptyLabel: errorMessage ?? "No grouped listings yet", selectedIds: selection.selectedIdSet, onToggleSelect: (id, _selected) => selection.toggle(id), onToggleSelectAll: (_next) => selection.toggleAll(), renderRowActions: (row) => (_jsxs("div", { className: "flex gap-1", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: () => onEditClick?.(row.id), children: ACTIONS.STORE["edit-listing"].label }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => onDeleteClick?.(row.id), children: ACTIONS.STORE["delete-listing"].label })] })) })] }));
@@ -1,10 +1,11 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useCallback } from "react";
4
+ import { useEntityDelete } from "../../../react/hooks/useEntityDelete";
4
5
  import { Plus } from "lucide-react";
5
6
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
7
  import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
7
- import { BulkActionBar, Button, ConfirmDeleteModal, DataTable, Div, ListingToolbar, Pagination, RowActionMenu, Text, useToast, } from "../../../ui";
8
+ import { BulkActionBar, Button, ConfirmDeleteModal, DataTable, Div, ListingToolbar, Pagination, RowActionMenu, Text, } from "../../../ui";
8
9
  import { useBottomActions } from "../../layout";
9
10
  import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
10
11
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
@@ -40,14 +41,14 @@ const COLUMNS = [
40
41
  key: "vendorVerified",
41
42
  header: "Verified",
42
43
  render: (row) => (_jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${row.vendorVerified
43
- ? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300"
44
- : "bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300"}`, children: row.vendorVerified ? "Verified" : "Pending" })),
44
+ ? "bg-success-surface text-success"
45
+ : "bg-warning-surface text-warning"}`, children: row.vendorVerified ? "Verified" : "Pending" })),
45
46
  },
46
47
  {
47
48
  key: "status",
48
49
  header: "Status",
49
50
  render: (row) => (_jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium capitalize ${row.status === "active"
50
- ? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300"
51
+ ? "bg-success-surface text-success"
51
52
  : "bg-zinc-100 text-zinc-600 dark:bg-slate-800 dark:text-slate-400"}`, children: row.status })),
52
53
  },
53
54
  {
@@ -61,8 +62,12 @@ export function SellerLiveView({ onCreateClick, onEditClick, onDelete, onBulkDel
61
62
  const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
62
63
  const [view] = useState("table");
63
64
  const [deleteTargetId, setDeleteTargetId] = useState(null);
64
- const [deletingId, setDeletingId] = useState(null);
65
- const { showToast } = useToast();
65
+ const { deletingId, handleDelete: performDelete } = useEntityDelete({
66
+ endpoint: (id) => `/api/store/products/${id}`,
67
+ deleteFn: onDelete,
68
+ successMessage: "Listing deleted.",
69
+ fetchOptions: { credentials: "include" },
70
+ });
66
71
  const commitSearch = useCallback(() => {
67
72
  table.set(TABLE_KEYS.QUERY, searchInput.trim());
68
73
  }, [searchInput, table]);
@@ -107,22 +112,9 @@ export function SellerLiveView({ onCreateClick, onEditClick, onDelete, onBulkDel
107
112
  }]
108
113
  : [];
109
114
  const handleDelete = useCallback(async (id) => {
110
- setDeletingId(id);
111
- try {
112
- if (onDelete)
113
- await onDelete(id);
114
- else
115
- await fetch(`/api/store/products/${id}`, { method: "DELETE", credentials: "include" });
116
- showToast("Listing deleted.", "success");
117
- }
118
- catch (err) {
119
- showToast(err instanceof Error ? err.message : "Failed to delete listing.", "error");
120
- }
121
- finally {
122
- setDeletingId(null);
123
- setDeleteTargetId(null);
124
- }
125
- }, [onDelete, showToast]);
115
+ await performDelete(id);
116
+ setDeleteTargetId(null);
117
+ }, [performDelete]);
126
118
  const handleEdit = useCallback((id) => {
127
119
  if (onEditClick)
128
120
  onEditClick(id);
@@ -138,7 +130,7 @@ export function SellerLiveView({ onCreateClick, onEditClick, onDelete, onBulkDel
138
130
  }
139
131
  }, [onCreateClick]);
140
132
  useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: bulkActions } } : {});
141
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: 0, searchValue: searchInput, searchPlaceholder: "Search live items by name or species...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, showTableView: true, view: view, onViewChange: () => { }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: handleCreate, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: "New Live Item" })] }) }), 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) }) })), selection.selectedCount > 0 && bulkActions.length > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx(Div, { className: "mb-4 rounded-xl border border-red-200 bg-red-50 dark:bg-red-950/40 dark:border-red-900/60 px-4 py-3 text-sm text-red-700 dark:text-red-200", children: errorMessage })), isLoading ? (_jsx(Div, { className: "space-y-2", children: Array.from({ length: 5 }).map((_, i) => (_jsx(Div, { className: "h-14 animate-pulse rounded-xl border border-zinc-100 dark:border-slate-700 bg-zinc-50 dark:bg-slate-800" }, i))) })) : rows.length === 0 ? (_jsx(Div, { className: "py-16 text-center", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-400", children: "No live items yet \u2014 list animals, plants, or other living specimens" }) })) : (_jsx(DataTable, { columns: COLUMNS, data: rows, keyExtractor: (r) => r.id, selectable: bulkActions.length > 0, selectedIds: selection.selectedIds, onSelectionChange: (ids) => selection.setSelectedIds(ids), actions: (row) => (_jsx(RowActionMenu, { actions: [
133
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: 0, searchValue: searchInput, searchPlaceholder: "Search live items by name or species...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, showTableView: true, view: view, onViewChange: () => { }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: handleCreate, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: "New Live Item" })] }) }), 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) }) })), selection.selectedCount > 0 && bulkActions.length > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), _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 dark:border-red-900/60 px-4 py-3 text-sm text-error", children: errorMessage })), isLoading ? (_jsx(Div, { className: "space-y-2", children: Array.from({ length: 5 }).map((_, i) => (_jsx(Div, { className: "h-14 animate-pulse rounded-xl border border-zinc-100 dark:border-slate-700 bg-zinc-50 dark:bg-slate-800" }, i))) })) : rows.length === 0 ? (_jsx(Div, { className: "py-16 text-center", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-400", children: "No live items yet \u2014 list animals, plants, or other living specimens" }) })) : (_jsx(DataTable, { columns: COLUMNS, data: rows, keyExtractor: (r) => r.id, selectable: bulkActions.length > 0, selectedIds: selection.selectedIds, onSelectionChange: (ids) => selection.setSelectedIds(ids), actions: (row) => (_jsx(RowActionMenu, { actions: [
142
134
  {
143
135
  label: ACTIONS.STORE["edit-listing"].label,
144
136
  onClick: () => handleEdit(row.id),
@@ -106,7 +106,7 @@ function OfferCard({ offer, onRespond, onUpdate, onNeedsLogin }) {
106
106
  }
107
107
  submit({ action: "counter", offerId: offer.id, counterAmount: amount, sellerNote: sellerNote || undefined });
108
108
  }
109
- return (_jsxs(Div, { className: "rounded-xl border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-900 p-4 space-y-3", children: [_jsxs(Div, { className: "flex items-start justify-between gap-2 flex-wrap", children: [_jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { className: "font-semibold text-sm text-zinc-900 dark:text-zinc-100 truncate", children: offer.productTitle ?? "Unknown Product" }), _jsxs(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400 mt-0.5", children: [relativeTime(offer.createdAt), " \u00B7 ", isPendingOffer ? expiresIn(offer.expiresAt) : ""] })] }), _jsx(Badge, { variant: statusVariant(offer.status), className: "shrink-0 capitalize text-xs", children: offer.status })] }), _jsxs(Div, { className: "flex gap-4 flex-wrap", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400 uppercase tracking-wide", children: "Listed" }), _jsx(Text, { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: formatRupees(offer.listedPrice) })] }), _jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400 uppercase tracking-wide", children: "Offered" }), _jsx(Text, { className: "text-sm font-semibold text-zinc-900 dark:text-zinc-100", children: formatRupees(offer.offerAmount) })] }), offer.counterAmount != null && (_jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400 uppercase tracking-wide", children: "Your Counter" }), _jsx(Text, { className: "text-sm font-medium text-blue-600 dark:text-blue-400", children: formatRupees(offer.counterAmount) })] }))] }), offer.buyerNote && (_jsxs(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400 italic", children: ["\"", offer.buyerNote, "\""] })), isPendingOffer && uiState === "idle" && (_jsxs(Div, { className: "flex gap-2 flex-wrap", children: [_jsx(Button, { size: "sm", variant: "primary", onClick: toAccepting, disabled: isPending, children: "Accept" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toCountering, disabled: isPending, className: "border border-zinc-300 dark:border-zinc-600", children: "Counter" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toDeclining, disabled: isPending, className: "text-red-600 dark:text-red-400 border border-red-200 dark:border-red-800", children: "Decline" })] })), uiState === "accepting" && (_jsxs(Div, { className: "space-y-2", children: [_jsx(Input, { placeholder: PLACEHOLDER_SELLER_NOTE, value: sellerNote, onChange: (e) => setSellerNote(e.target.value), disabled: isPending }), _jsxs(Div, { className: "flex gap-2", children: [_jsx(Button, { size: "sm", variant: "primary", onClick: handleAccept, disabled: isPending, children: isPending ? "Accepting…" : "Confirm Accept" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toIdle, disabled: isPending, children: ACTIONS.STORE["cancel-form"].label })] })] })), uiState === "declining" && (_jsxs(Div, { className: "space-y-2", children: [_jsx(Input, { placeholder: PLACEHOLDER_SELLER_NOTE, value: sellerNote, onChange: (e) => setSellerNote(e.target.value), disabled: isPending }), _jsxs(Div, { className: "flex gap-2", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: handleDecline, disabled: isPending, className: "text-red-600 dark:text-red-400 border border-red-200 dark:border-red-800", children: isPending ? "Declining…" : "Confirm Decline" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toIdle, disabled: isPending, children: ACTIONS.STORE["cancel-form"].label })] })] })), uiState === "countering" && (_jsxs(Div, { className: "space-y-2", children: [_jsxs(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: ["Suggest a price between the buyer's offer (", formatRupees(offer.offerAmount), ") and your listed price (", formatRupees(offer.listedPrice), ")."] }), _jsx(Input, { type: "number", placeholder: "Your counter amount (\u20B9)", value: counterInput, onChange: (e) => setCounterInput(e.target.value), disabled: isPending }), _jsx(Input, { placeholder: PLACEHOLDER_SELLER_NOTE, value: sellerNote, onChange: (e) => setSellerNote(e.target.value), disabled: isPending }), _jsxs(Div, { className: "flex gap-2", children: [_jsx(Button, { size: "sm", variant: "secondary", onClick: handleCounter, disabled: isPending, children: isPending ? "Sending…" : "Send Counter" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toIdle, disabled: isPending, children: ACTIONS.STORE["cancel-form"].label })] })] })), error && _jsx(Alert, { variant: "error", children: _jsx(Text, { className: "text-xs", children: error }) })] }));
109
+ return (_jsxs(Div, { surface: "card", padding: "sm", className: "space-y-3", children: [_jsxs(Div, { className: "flex items-start justify-between gap-2 flex-wrap", children: [_jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { className: "font-semibold text-sm text-zinc-900 dark:text-zinc-100 truncate", children: offer.productTitle ?? "Unknown Product" }), _jsxs(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400 mt-0.5", children: [relativeTime(offer.createdAt), " \u00B7 ", isPendingOffer ? expiresIn(offer.expiresAt) : ""] })] }), _jsx(Badge, { variant: statusVariant(offer.status), className: "shrink-0 capitalize text-xs", children: offer.status })] }), _jsxs(Div, { className: "flex gap-4 flex-wrap", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400 uppercase tracking-wide", children: "Listed" }), _jsx(Text, { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: formatRupees(offer.listedPrice) })] }), _jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400 uppercase tracking-wide", children: "Offered" }), _jsx(Text, { className: "text-sm font-semibold text-zinc-900 dark:text-zinc-100", children: formatRupees(offer.offerAmount) })] }), offer.counterAmount != null && (_jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400 uppercase tracking-wide", children: "Your Counter" }), _jsx(Text, { className: "text-sm font-medium text-info", children: formatRupees(offer.counterAmount) })] }))] }), offer.buyerNote && (_jsxs(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400 italic", children: ["\"", offer.buyerNote, "\""] })), isPendingOffer && uiState === "idle" && (_jsxs(Div, { className: "flex gap-2 flex-wrap", children: [_jsx(Button, { size: "sm", variant: "primary", onClick: toAccepting, disabled: isPending, children: "Accept" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toCountering, disabled: isPending, className: "border border-zinc-300 dark:border-zinc-600", children: "Counter" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toDeclining, disabled: isPending, className: "text-error border border-red-200 dark:border-red-800", children: "Decline" })] })), uiState === "accepting" && (_jsxs(Div, { className: "space-y-2", children: [_jsx(Input, { placeholder: PLACEHOLDER_SELLER_NOTE, value: sellerNote, onChange: (e) => setSellerNote(e.target.value), disabled: isPending }), _jsxs(Div, { className: "flex gap-2", children: [_jsx(Button, { size: "sm", variant: "primary", onClick: handleAccept, disabled: isPending, children: isPending ? "Accepting…" : "Confirm Accept" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toIdle, disabled: isPending, children: ACTIONS.STORE["cancel-form"].label })] })] })), uiState === "declining" && (_jsxs(Div, { className: "space-y-2", children: [_jsx(Input, { placeholder: PLACEHOLDER_SELLER_NOTE, value: sellerNote, onChange: (e) => setSellerNote(e.target.value), disabled: isPending }), _jsxs(Div, { className: "flex gap-2", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: handleDecline, disabled: isPending, className: "text-error border border-red-200 dark:border-red-800", children: isPending ? "Declining…" : "Confirm Decline" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toIdle, disabled: isPending, children: ACTIONS.STORE["cancel-form"].label })] })] })), uiState === "countering" && (_jsxs(Div, { className: "space-y-2", children: [_jsxs(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: ["Suggest a price between the buyer's offer (", formatRupees(offer.offerAmount), ") and your listed price (", formatRupees(offer.listedPrice), ")."] }), _jsx(Input, { type: "number", placeholder: "Your counter amount (\u20B9)", value: counterInput, onChange: (e) => setCounterInput(e.target.value), disabled: isPending }), _jsx(Input, { placeholder: PLACEHOLDER_SELLER_NOTE, value: sellerNote, onChange: (e) => setSellerNote(e.target.value), disabled: isPending }), _jsxs(Div, { className: "flex gap-2", children: [_jsx(Button, { size: "sm", variant: "secondary", onClick: handleCounter, disabled: isPending, children: isPending ? "Sending…" : "Send Counter" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toIdle, disabled: isPending, children: ACTIONS.STORE["cancel-form"].label })] })] })), error && _jsx(Alert, { variant: "error", children: _jsx(Text, { className: "text-xs", children: error }) })] }));
110
110
  }
111
111
  export function SellerOffersPanel({ fetchEndpoint = "/api/store/offers", onRespond, className = "", }) {
112
112
  const [offers, setOffers] = useState([]);
@@ -152,5 +152,5 @@ export function SellerOffersPanel({ fetchEndpoint = "/api/store/offers", onRespo
152
152
  { value: "expired", label: "Expired" },
153
153
  ];
154
154
  const pending = offers.filter((o) => o.status === "pending").length;
155
- return (_jsxs(Div, { className: `space-y-4 ${className}`, children: [_jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to manage offers. Please log in or create an account to continue." }), _jsxs(Div, { className: "flex items-center justify-between flex-wrap gap-2", children: [_jsxs(Div, { children: [_jsx(Heading, { level: 2, className: "text-lg font-semibold text-zinc-900 dark:text-zinc-100", children: "Offers Received" }), pending > 0 && (_jsxs(Text, { className: "text-xs text-amber-600 dark:text-amber-400 mt-0.5", children: [pending, " pending offer", pending > 1 ? "s" : "", " awaiting your response"] }))] }), _jsx(Button, { size: "sm", variant: "ghost", onClick: loadOffers, disabled: loading, className: "border border-zinc-300 dark:border-zinc-600 text-xs", children: loading ? "Refreshing…" : ACTIONS.STORE["refresh-offers"].label })] }), _jsx(Div, { className: "flex gap-1 flex-wrap", children: STATUS_FILTERS.map((f) => (_jsx(Button, { size: "sm", variant: statusFilter === f.value ? "primary" : "ghost", onClick: () => setStatusFilter(f.value), className: "text-xs px-2 py-1", children: f.label }, f.value))) }), fetchError && _jsx(Alert, { variant: "error", children: _jsx(Text, { className: "text-sm", children: fetchError }) }), loading && (_jsx(Div, { className: "flex justify-center py-12", children: _jsx(Spinner, { size: "lg" }) })), !loading && offers.length === 0 && (_jsx(Div, { className: "text-center py-12", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-400 text-sm", children: "No offers found" }) })), !loading && offers.length > 0 && (_jsx(Div, { className: "space-y-3", children: offers.map((offer) => (_jsx(OfferCard, { offer: offer, onRespond: onRespond, onUpdate: handleUpdate, onNeedsLogin: () => setShowLoginModal(true) }, offer.id))) }))] }));
155
+ return (_jsxs(Div, { className: `space-y-4 ${className}`, children: [_jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to manage offers. Please log in or create an account to continue." }), _jsxs(Div, { className: "flex items-center justify-between flex-wrap gap-2", children: [_jsxs(Div, { children: [_jsx(Heading, { level: 2, className: "text-lg font-semibold text-zinc-900 dark:text-zinc-100", children: "Offers Received" }), pending > 0 && (_jsxs(Text, { className: "text-xs text-warning mt-0.5", children: [pending, " pending offer", pending > 1 ? "s" : "", " awaiting your response"] }))] }), _jsx(Button, { size: "sm", variant: "ghost", onClick: loadOffers, disabled: loading, className: "border border-zinc-300 dark:border-zinc-600 text-xs", children: loading ? "Refreshing…" : ACTIONS.STORE["refresh-offers"].label })] }), _jsx(Div, { className: "flex gap-1 flex-wrap", children: STATUS_FILTERS.map((f) => (_jsx(Button, { size: "sm", variant: statusFilter === f.value ? "primary" : "ghost", onClick: () => setStatusFilter(f.value), className: "text-xs px-2 py-1", children: f.label }, f.value))) }), fetchError && _jsx(Alert, { variant: "error", children: _jsx(Text, { className: "text-sm", children: fetchError }) }), loading && (_jsx(Div, { className: "flex justify-center py-12", children: _jsx(Spinner, { size: "lg" }) })), !loading && offers.length === 0 && (_jsx(Div, { className: "text-center py-12", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-400 text-sm", children: "No offers found" }) })), !loading && offers.length > 0 && (_jsx(Div, { className: "space-y-3", children: offers.map((offer) => (_jsx(OfferCard, { offer: offer, onRespond: onRespond, onUpdate: handleUpdate, onNeedsLogin: () => setShowLoginModal(true) }, offer.id))) }))] }));
156
156
  }
@@ -1,11 +1,10 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import React, { useState, useCallback } from "react";
4
- import { X } from "lucide-react";
5
4
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
5
  import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
7
6
  import { AdminViewCards } from "../../admin/components/AdminViewCards";
8
- import { FilterChipGroup, ListingToolbar, Pagination, ListingViewShell, RowActionMenu } from "../../../ui";
7
+ import { FilterChipGroup, ListingFilterDrawer, ListingToolbar, Pagination, ListingViewShell, RowActionMenu } from "../../../ui";
9
8
  import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
10
9
  import { SELLER_OFFER_STATUS_TABS } from "../../admin/constants/filter-tabs";
11
10
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
@@ -80,9 +79,9 @@ export function SellerOffersView({ children, onAcceptOffer, onRejectOffer, onCou
80
79
  if (hasChildren) {
81
80
  return _jsx(ListingViewShell, { portal: "seller", ...props, children: children });
82
81
  }
83
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search offers by product or buyer name", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("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-red-50 px-4 py-3 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-200", children: errorMessage })), view === "table" ? (_jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No offers received", renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
82
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search offers by product or buyer name", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("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 offers received", renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
84
83
  ...(onAcceptOffer ? [{ label: ACTIONS.STORE["accept-offer"].label, onClick: () => void onAcceptOffer(row.id) }] : []),
85
84
  ...(onCounterOffer ? [{ label: ACTIONS.STORE["counter-offer"].label, onClick: () => onCounterOffer(row.id) }] : []),
86
85
  ...(onRejectOffer ? [{ label: ACTIONS.STORE["reject-offer"].label, destructive: true, onClick: () => void onRejectOffer(row.id) }] : []),
87
- ] })) })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No offers received", onRowClick: undefined, selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }))] }));
86
+ ] })) })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No offers received", onRowClick: undefined, 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 })) }) })] }));
88
87
  }
@@ -1,14 +1,15 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import React, { useState, useCallback } from "react";
4
- import { X, Eye, Printer, MapPin, Truck } from "lucide-react";
4
+ import { Eye, Printer, MapPin, Truck } from "lucide-react";
5
5
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
6
  import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
7
7
  import { useActionDispatch } from "../../../react/hooks/use-action-dispatch";
8
- import { BulkActionBar, Badge, Button, Div, FilterChipGroup, Heading, Input, ListingToolbar, Pagination, ListingViewShell, Select, SideDrawer, Stack, Text, useToast } from "../../../ui";
8
+ import { BulkActionBar, Badge, Button, Div, FilterChipGroup, Heading, Input, ListingFilterDrawer, ListingToolbar, Pagination, ListingViewShell, Select, SideDrawer, Stack, Text, useToast } from "../../../ui";
9
9
  import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
10
10
  import { SELLER_ORDER_STATUS_TABS } from "../../admin/constants/filter-tabs";
11
11
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
12
+ import { buildBulkAction } from "../../../_internal/shared/actions/bulk-helpers";
12
13
  import { PhysicalLocationModal } from "./PhysicalLocationModal";
13
14
  import { ROUTES } from "../../../constants";
14
15
  import { toRecordArray, toRelativeDate, toRupees, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
@@ -110,7 +111,7 @@ function OrderDetailDrawer({ orderId, apiBase, onClose, }) {
110
111
  };
111
112
  const addr = order?.shippingAddress ?? {};
112
113
  const addrLine = [addr.addressLine1, addr.city, addr.state, addr.pincode].filter(Boolean).join(", ");
113
- return (_jsxs(SideDrawer, { isOpen: true, title: `Order ${order?.id ?? orderId}`, onClose: onClose, children: [loading && (_jsx(Div, { className: "flex items-center justify-center py-16", children: _jsx("div", { className: "h-6 w-6 animate-spin rounded-full border-2 border-[var(--appkit-color-primary)] border-t-transparent" }) })), fetchError && (_jsx(Div, { className: "mx-4 mt-4 rounded-lg border border-red-200 bg-red-50 dark:bg-red-950/40 dark:border-red-900/60 px-4 py-3 text-sm text-red-700 dark:text-red-200", children: fetchError })), order && !loading && (_jsxs(Stack, { gap: "none", className: "flex flex-col", children: [_jsxs("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: [_jsxs(Div, { className: "flex items-center justify-between", children: [_jsx(Badge, { variant: STATUS_BADGE_VARIANT[order.status?.toUpperCase()] ?? "default", children: order.status ?? "Unknown" }), _jsx(Text, { size: "sm", className: "text-[var(--appkit-color-text-secondary)]", children: toRelativeDate(order.createdAt) })] }), (order.items ?? []).length > 0 && (_jsxs(Div, { children: [_jsx(Text, { size: "sm", className: "font-semibold text-[var(--appkit-color-text-primary)] mb-2", children: "Items" }), _jsx("div", { className: "divide-y divide-[var(--appkit-color-border)] dark:divide-slate-700 rounded-lg border border-[var(--appkit-color-border)] dark:border-slate-700", children: (order.items ?? []).map((item, i) => (_jsxs("div", { className: "flex items-center justify-between px-3 py-2.5 gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx(Text, { size: "sm", className: "font-medium truncate", children: item.title ?? item.productId ?? "Item" }), _jsxs(Text, { size: "xs", className: "text-[var(--appkit-color-text-secondary)]", children: ["Qty: ", item.quantity ?? 1] })] }), _jsx(Text, { size: "sm", className: "shrink-0 font-medium", children: toRupees(item.price ?? 0) })] }, i))) })] })), _jsxs(Div, { className: "flex items-center justify-between rounded-lg bg-zinc-50 dark:bg-slate-800/60 px-4 py-3", children: [_jsx(Text, { size: "sm", className: "font-semibold", children: "Total" }), _jsx(Text, { size: "sm", className: "font-bold text-[var(--appkit-color-primary)]", children: toRupees(order.totalAmount ?? 0) })] }), addrLine && (_jsxs(Div, { children: [_jsx(Text, { size: "sm", className: "font-semibold mb-1", children: "Shipping address" }), _jsx(Text, { size: "sm", className: "text-[var(--appkit-color-text-secondary)]", children: [String(addr.fullName ?? ""), addrLine].filter(Boolean).join(" · ") })] })), order.paymentMethod && (_jsxs(Div, { children: [_jsx(Text, { size: "sm", className: "font-semibold mb-1", children: "Payment" }), _jsx(Text, { size: "sm", className: "text-[var(--appkit-color-text-secondary)] capitalize", children: order.paymentMethod })] })), _jsxs("div", { className: "border-t border-[var(--appkit-color-border)] dark:border-slate-700 pt-4 space-y-3", children: [_jsx(Heading, { level: 4, className: "text-sm font-semibold", children: "Update order" }), _jsx(Select, { label: "New status", value: newStatus, options: UPDATE_STATUS_OPTIONS, onChange: (e) => setNewStatus(e.target.value) }), _jsx(Input, { label: "Tracking number", value: trackingNumber, onChange: (e) => setTrackingNumber(e.target.value), placeholder: "e.g. 12345678901234" }), _jsx(Input, { label: "Carrier", value: carrier, onChange: (e) => setCarrier(e.target.value), placeholder: "e.g. Delhivery, Bluedart" }), _jsx(Input, { label: "Tracking URL (optional)", value: trackingUrl, onChange: (e) => setTrackingUrl(e.target.value), placeholder: "https://...", type: "url" }), saveError && (_jsx(Div, { className: "rounded-lg border border-red-200 bg-red-50 dark:bg-red-950/40 dark:border-red-900/60 px-3 py-2 text-xs text-red-700 dark:text-red-200", children: saveError }))] })] }), _jsxs("div", { className: "border-t border-[var(--appkit-color-border)] dark:border-slate-700 px-4 py-3.5 flex items-center justify-end gap-3", children: [_jsx(Button, { variant: "outline", onClick: onClose, disabled: saving, children: "Close" }), _jsx(Button, { onClick: handleSave, isLoading: saving, disabled: saving, children: "Save" })] })] }))] }));
114
+ return (_jsxs(SideDrawer, { isOpen: true, title: `Order ${order?.id ?? orderId}`, onClose: onClose, children: [loading && (_jsx(Div, { className: "flex items-center justify-center py-16", children: _jsx("div", { className: "h-6 w-6 animate-spin rounded-full border-2 border-[var(--appkit-color-primary)] border-t-transparent" }) })), fetchError && (_jsx(Div, { className: "mx-4 mt-4 rounded-lg border border-red-200 bg-error-surface dark:border-red-900/60 px-4 py-3 text-sm text-error", children: fetchError })), order && !loading && (_jsxs(Stack, { gap: "none", className: "flex flex-col", children: [_jsxs("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: [_jsxs(Div, { className: "flex items-center justify-between", children: [_jsx(Badge, { variant: STATUS_BADGE_VARIANT[order.status?.toUpperCase()] ?? "default", children: order.status ?? "Unknown" }), _jsx(Text, { size: "sm", className: "text-[var(--appkit-color-text-secondary)]", children: toRelativeDate(order.createdAt) })] }), (order.items ?? []).length > 0 && (_jsxs(Div, { children: [_jsx(Text, { size: "sm", className: "font-semibold text-[var(--appkit-color-text-primary)] mb-2", children: "Items" }), _jsx("div", { className: "divide-y divide-[var(--appkit-color-border)] dark:divide-slate-700 rounded-lg border border-[var(--appkit-color-border)] dark:border-slate-700", children: (order.items ?? []).map((item, i) => (_jsxs("div", { className: "flex items-center justify-between px-3 py-2.5 gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx(Text, { size: "sm", className: "font-medium truncate", children: item.title ?? item.productId ?? "Item" }), _jsxs(Text, { size: "xs", className: "text-[var(--appkit-color-text-secondary)]", children: ["Qty: ", item.quantity ?? 1] })] }), _jsx(Text, { size: "sm", className: "shrink-0 font-medium", children: toRupees(item.price ?? 0) })] }, i))) })] })), _jsxs(Div, { className: "flex items-center justify-between rounded-lg bg-zinc-50 dark:bg-slate-800/60 px-4 py-3", children: [_jsx(Text, { size: "sm", className: "font-semibold", children: "Total" }), _jsx(Text, { size: "sm", className: "font-bold text-[var(--appkit-color-primary)]", children: toRupees(order.totalAmount ?? 0) })] }), addrLine && (_jsxs(Div, { children: [_jsx(Text, { size: "sm", className: "font-semibold mb-1", children: "Shipping address" }), _jsx(Text, { size: "sm", className: "text-[var(--appkit-color-text-secondary)]", children: [String(addr.fullName ?? ""), addrLine].filter(Boolean).join(" · ") })] })), order.paymentMethod && (_jsxs(Div, { children: [_jsx(Text, { size: "sm", className: "font-semibold mb-1", children: "Payment" }), _jsx(Text, { size: "sm", className: "text-[var(--appkit-color-text-secondary)] capitalize", children: order.paymentMethod })] })), _jsxs("div", { className: "border-t border-[var(--appkit-color-border)] dark:border-slate-700 pt-4 space-y-3", children: [_jsx(Heading, { level: 4, className: "text-sm font-semibold", children: "Update order" }), _jsx(Select, { label: "New status", value: newStatus, options: UPDATE_STATUS_OPTIONS, onChange: (e) => setNewStatus(e.target.value) }), _jsx(Input, { label: "Tracking number", value: trackingNumber, onChange: (e) => setTrackingNumber(e.target.value), placeholder: "e.g. 12345678901234" }), _jsx(Input, { label: "Carrier", value: carrier, onChange: (e) => setCarrier(e.target.value), placeholder: "e.g. Delhivery, Bluedart" }), _jsx(Input, { label: "Tracking URL (optional)", value: trackingUrl, onChange: (e) => setTrackingUrl(e.target.value), placeholder: "https://...", type: "url" }), saveError && (_jsx(Div, { className: "rounded-lg border border-red-200 bg-error-surface dark:border-red-900/60 px-3 py-2 text-xs text-error", children: saveError }))] })] }), _jsxs("div", { className: "border-t border-[var(--appkit-color-border)] dark:border-slate-700 px-4 py-3.5 flex items-center justify-end gap-3", children: [_jsx(Button, { variant: "outline", onClick: onClose, disabled: saving, children: "Close" }), _jsx(Button, { onClick: handleSave, isLoading: saving, disabled: saving, children: "Save" })] })] }))] }));
114
115
  }
115
116
  // ---------------------------------------------------------------------------
116
117
  // Main view
@@ -292,28 +293,13 @@ export function SellerOrdersView({ orderDetailApiBase = SELLER_ENDPOINTS.ORDERS,
292
293
  }
293
294
  }, [selection, showToast]);
294
295
  const bulkActions = [
295
- {
296
- id: ACTIONS.STORE["print-packing-slips"].id,
297
- label: ACTIONS.STORE["print-packing-slips"].label,
298
- icon: _jsx(Printer, { className: "w-4 h-4" }),
299
- onClick: handlePrintPackingSlips,
300
- },
301
- {
302
- id: ACTIONS.STORE["set-location"].id,
303
- label: ACTIONS.STORE["set-location"].label,
304
- icon: _jsx(MapPin, { className: "w-4 h-4" }),
305
- onClick: () => setSetLocationOpen(true),
306
- },
307
- {
308
- id: ACTIONS.STORE["request-payout"].id,
309
- label: ACTIONS.STORE["request-payout"].label,
310
- onClick: () => void requestPayoutForSelection(),
311
- variant: "primary",
312
- },
296
+ buildBulkAction(ACTIONS.STORE["print-packing-slips"], handlePrintPackingSlips, { icon: _jsx(Printer, { className: "w-4 h-4" }) }),
297
+ buildBulkAction(ACTIONS.STORE["set-location"], () => setSetLocationOpen(true), { icon: _jsx(MapPin, { className: "w-4 h-4" }) }),
298
+ buildBulkAction(ACTIONS.STORE["request-payout"], () => void requestPayoutForSelection(), { variant: "primary" }),
313
299
  ];
314
300
  if (hasChildren) {
315
301
  return _jsx(ListingViewShell, { portal: "seller", ...props, children: children });
316
302
  }
317
303
  useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: bulkActions } } : {});
318
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search by order ID or buyer name", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("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) }) })), selection.selectedIds.length > 0 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+88px)] z-20 px-3 sm:px-4 py-2 bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700", children: _jsx(BulkActionBar, { selectedCount: selection.selectedIds.length, onClearSelection: selection.clearSelection, actions: bulkActions }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx(Div, { className: "mb-4 rounded-xl border border-red-200 bg-red-50 dark:bg-red-950/40 dark:border-red-900/60 px-4 py-3 text-sm text-red-700 dark:text-red-200", children: errorMessage })), _jsx(DataTable, { rows: rows, columns: columns, isLoading: isLoading, emptyLabel: "No orders yet", selectedIds: selection.selectedIdSet, onToggleSelect: selection.toggle, onToggleSelectAll: () => selection.toggleAll(), renderRowActions: renderRowActions })] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 dark:text-zinc-400 hover:text-rose-500 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-[var(--appkit-color-primary)] py-2.5 text-sm font-semibold text-white transition-colors active:scale-[0.98]", children: ["Apply", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] })), selectedOrderId && (_jsx(OrderDetailDrawer, { orderId: selectedOrderId, apiBase: orderDetailApiBase, onClose: () => setSelectedOrderId(null) })), setLocationOpen && (_jsx(PhysicalLocationModal, { count: selection.selectedIds.length, onSave: handleSetLocation, onClose: () => setSetLocationOpen(false) }))] }));
304
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search by order ID or buyer name", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("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) }) })), selection.selectedIds.length > 0 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+88px)] z-20 px-3 sm:px-4 py-2 bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700", children: _jsx(BulkActionBar, { selectedCount: selection.selectedIds.length, onClearSelection: selection.clearSelection, actions: bulkActions }) })), _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 dark:border-red-900/60 px-4 py-3 text-sm text-error", children: errorMessage })), _jsx(DataTable, { rows: rows, columns: columns, isLoading: isLoading, emptyLabel: "No orders yet", selectedIds: selection.selectedIdSet, onToggleSelect: selection.toggle, onToggleSelectAll: () => selection.toggleAll(), renderRowActions: renderRowActions })] }), _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 })) }) }), selectedOrderId && (_jsx(OrderDetailDrawer, { orderId: selectedOrderId, apiBase: orderDetailApiBase, onClose: () => setSelectedOrderId(null) })), setLocationOpen && (_jsx(PhysicalLocationModal, { count: selection.selectedIds.length, onSave: handleSetLocation, onClose: () => setSetLocationOpen(false) }))] }));
319
305
  }
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useCallback } from "react";
4
+ import { useEntityDelete } from "../../../react/hooks/useEntityDelete";
4
5
  import { Plus } from "lucide-react";
5
6
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
7
  import { Button, ConfirmDeleteModal, Div, ListingToolbar, Text, useToast, } from "../../../ui";
@@ -32,7 +33,13 @@ export function SellerPayoutMethodsView({ onCreateClick, onEditClick, onDelete,
32
33
  const table = useUrlTable({ defaults: { sort: DEFAULT_SORT } });
33
34
  const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
34
35
  const [deleteTargetId, setDeleteTargetId] = useState(null);
35
- const [deletingId, setDeletingId] = useState(null);
36
+ const { deletingId, handleDelete: performDelete } = useEntityDelete({
37
+ endpoint: SELLER_ENDPOINTS.PAYOUT_METHOD_BY_ID,
38
+ deleteFn: onDelete,
39
+ successMessage: "Payout method deleted.",
40
+ onSuccess: () => { refetch?.(); },
41
+ fetchOptions: { credentials: "include" },
42
+ });
36
43
  const [settingDefaultId, setSettingDefaultId] = useState(null);
37
44
  const { showToast } = useToast();
38
45
  const commitSearch = useCallback(() => {
@@ -61,28 +68,9 @@ export function SellerPayoutMethodsView({ onCreateClick, onEditClick, onDelete,
61
68
  })),
62
69
  });
63
70
  const handleDelete = useCallback(async (id) => {
64
- setDeletingId(id);
65
- try {
66
- if (onDelete) {
67
- await onDelete(id);
68
- }
69
- else {
70
- await fetch(SELLER_ENDPOINTS.PAYOUT_METHOD_BY_ID(id), {
71
- method: "DELETE",
72
- credentials: "include",
73
- });
74
- }
75
- refetch?.();
76
- showToast("Payout method deleted.", "success");
77
- }
78
- catch (err) {
79
- showToast(err instanceof Error ? err.message : "Failed to delete payout method.", "error");
80
- }
81
- finally {
82
- setDeletingId(null);
83
- setDeleteTargetId(null);
84
- }
85
- }, [onDelete, refetch, showToast]);
71
+ await performDelete(id);
72
+ setDeleteTargetId(null);
73
+ }, [performDelete]);
86
74
  const handleSetDefault = useCallback(async (id) => {
87
75
  setSettingDefaultId(id);
88
76
  try {
@@ -123,7 +111,7 @@ export function SellerPayoutMethodsView({ onCreateClick, onEditClick, onDelete,
123
111
  window.location.href = String(ROUTES.STORE.PAYOUT_METHODS_EDIT(id));
124
112
  }
125
113
  }, [onEditClick]);
126
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: 0, searchValue: searchInput, searchPlaceholder: "Search payout methods...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: handleCreate, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: "New Method" })] }) }), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx(Div, { className: "mb-4 rounded-xl border border-red-200 bg-red-50 dark:bg-red-950/40 dark:border-red-900/60 px-4 py-3 text-sm text-red-700 dark:text-red-200", children: errorMessage })), isLoading ? (_jsx(Div, { className: "space-y-3", children: Array.from({ length: 3 }).map((_, i) => (_jsx(Div, { className: "h-20 animate-pulse rounded-xl border border-zinc-100 dark:border-slate-700 bg-zinc-50 dark:bg-slate-800" }, i))) })) : rows.length === 0 ? (_jsxs(Div, { className: "py-16 text-center", children: [_jsx(Text, { className: "text-zinc-400 dark:text-zinc-400", children: "No payout methods yet \u2014 add a UPI VPA or bank account to receive payouts" }), _jsx("div", { className: "mt-4", children: _jsx(Button, { size: "sm", onClick: handleCreate, children: "Add payout method" }) })] })) : (_jsx("div", { className: "space-y-3", children: rows.map((row) => (_jsx("div", { className: "rounded-xl border border-zinc-200 dark:border-slate-700 bg-white dark:bg-slate-900 px-4 py-3", children: _jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsx("div", { className: "flex items-start gap-3 min-w-0", children: _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx(Text, { className: "text-sm font-medium", children: row.label }), _jsx(TypeBadge, { type: row.type }), row.isDefault && (_jsx("span", { className: "inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300", children: "Default" })), _jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${row.isActive
127
- ? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300"
114
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: 0, searchValue: searchInput, searchPlaceholder: "Search payout methods...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: handleCreate, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: "New Method" })] }) }), _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 dark:border-red-900/60 px-4 py-3 text-sm text-error", children: errorMessage })), isLoading ? (_jsx(Div, { className: "space-y-3", children: Array.from({ length: 3 }).map((_, i) => (_jsx(Div, { className: "h-20 animate-pulse rounded-xl border border-zinc-100 dark:border-slate-700 bg-zinc-50 dark:bg-slate-800" }, i))) })) : rows.length === 0 ? (_jsxs(Div, { className: "py-16 text-center", children: [_jsx(Text, { className: "text-zinc-400 dark:text-zinc-400", children: "No payout methods yet \u2014 add a UPI VPA or bank account to receive payouts" }), _jsx("div", { className: "mt-4", children: _jsx(Button, { size: "sm", onClick: handleCreate, children: "Add payout method" }) })] })) : (_jsx("div", { className: "space-y-3", children: rows.map((row) => (_jsx("div", { className: "rounded-xl border border-zinc-200 dark:border-slate-700 bg-white dark:bg-slate-900 px-4 py-3", children: _jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsx("div", { className: "flex items-start gap-3 min-w-0", children: _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx(Text, { className: "text-sm font-medium", children: row.label }), _jsx(TypeBadge, { type: row.type }), row.isDefault && (_jsx("span", { className: "inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium bg-success-surface text-success", children: "Default" })), _jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${row.isActive
115
+ ? "bg-success-surface text-success"
128
116
  : "bg-zinc-100 text-zinc-600 dark:bg-slate-800 dark:text-slate-400"}`, children: row.isActive ? "Active" : "Inactive" })] }), _jsx(Text, { className: "mt-1 text-xs text-zinc-500 dark:text-zinc-400 font-mono", children: row.maskedIdentifier })] }) }), _jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [!row.isDefault && (_jsx(Button, { size: "sm", variant: "ghost", isLoading: settingDefaultId === row.id, onClick: () => handleSetDefault(row.id), children: "Set Default" })), _jsx(Button, { size: "sm", variant: "outline", onClick: () => handleEdit(row.id), children: "Edit" }), _jsx(Button, { size: "sm", variant: "danger", disabled: deletingId === row.id, onClick: () => setDeleteTargetId(row.id), children: "Delete" })] })] }) }, row.id))) }))] }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Payout Method", message: "Are you sure you want to delete this payout method? This cannot be undone.", onConfirm: () => handleDelete(deleteTargetId), onClose: () => setDeleteTargetId(null), isDeleting: deletingId === deleteTargetId }))] }));
129
117
  }
@@ -1,11 +1,10 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import React, { useState, useCallback } from "react";
4
- import { X } from "lucide-react";
5
4
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
5
  import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
7
6
  import { AdminViewCards } from "../../admin/components/AdminViewCards";
8
- import { FilterChipGroup, ListingToolbar, Pagination, ListingViewShell, RowActionMenu } from "../../../ui";
7
+ import { FilterChipGroup, ListingFilterDrawer, ListingToolbar, Pagination, ListingViewShell, RowActionMenu } from "../../../ui";
9
8
  import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
10
9
  import { ADMIN_PAYOUT_STATUS_TABS } from "../../admin/constants/filter-tabs";
11
10
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
@@ -80,8 +79,8 @@ export function SellerPayoutsView({ children, onViewClick, onExportClick, ...pro
80
79
  if (hasChildren) {
81
80
  return _jsx(ListingViewShell, { portal: "seller", ...props, children: children });
82
81
  }
83
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search payouts by payout # or amount", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("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-red-50 px-4 py-3 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-200", children: errorMessage })), view === "table" ? (_jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No payouts found", renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
82
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search payouts by payout # or amount", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("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 payouts found", renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
84
83
  ...(onViewClick ? [{ label: ACTIONS.STORE["view-payout"].label, onClick: () => onViewClick(row.id) }] : []),
85
84
  ...(onExportClick ? [{ label: ACTIONS.STORE["export-payout"].label, onClick: () => onExportClick(row.id) }] : []),
86
- ] })) })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No payouts found", onRowClick: undefined, selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }))] }));
85
+ ] })) })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No payouts found", onRowClick: undefined, 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 })) }) })] }));
87
86
  }