@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
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import React from "react";
4
4
  import { useMutation, useQuery } from "@tanstack/react-query";
5
- import { Button, Form, Input, RichTextEditor, Select, StackedViewShell, TagInput, Text, Toggle, useToast } from "../../../ui";
5
+ import { Button, ConfirmDeleteModal, Form, Input, RichTextEditor, Select, StackedViewShell, TagInput, Text, Toggle, useToast } from "../../../ui";
6
6
  import { FieldInput, FormShellContext, useFormShellState } from "../../../ui/forms";
7
7
  import { apiClient } from "../../../http";
8
8
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
@@ -38,6 +38,7 @@ export function AdminFaqEditorView({ faqId, onSaved, onDeleted, embedded, ...res
38
38
  const [isPinned, setIsPinned] = React.useState(false);
39
39
  const [showOnHomepage, setShowOnHomepage] = React.useState(false);
40
40
  const [showInFooter, setShowInFooter] = React.useState(false);
41
+ const [deleteConfirmOpen, setDeleteConfirmOpen] = React.useState(false);
41
42
  const { showToast } = useToast();
42
43
  const { shellCtx, setFieldError, clearErrors } = useFormShellState();
43
44
  // --- load existing FAQ (edit mode) ---
@@ -114,22 +115,18 @@ export function AdminFaqEditorView({ faqId, onSaved, onDeleted, embedded, ...res
114
115
  });
115
116
  const isSubmitting = saveMutation.isPending || faqQuery.isLoading;
116
117
  const canSave = Boolean(question.trim()) && Boolean(answer.trim());
117
- const formSection = (_jsx(FormShellContext.Provider, { value: shellCtx, children: _jsxs(Form, { onSubmit: (e) => {
118
- e.preventDefault();
119
- clearErrors();
120
- if (!question.trim()) {
121
- setFieldError("question", "Question is required");
122
- return;
123
- }
124
- saveMutation.mutate();
125
- }, className: "space-y-5", children: [_jsx(FieldInput, { name: "question", label: "Question", value: question, onChange: (v) => handleQuestionChange(v), required: true, placeholder: "e.g. How does bidding work on LetItRip?" }), _jsx(Input, { label: "Slug", value: slug, onChange: (e) => {
126
- setSlug(e.target.value);
127
- setSlugManual(true);
128
- }, placeholder: "faq-how-does-bidding-work", helperText: "Auto-generated from question. Must start with 'faq-'." }), _jsxs("div", { className: "space-y-1", children: [_jsx(Text, { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Answer" }), _jsx(RichTextEditor, { value: answer, onChange: setAnswer, placeholder: "Write a clear, helpful answer...", minHeightClassName: "min-h-[200px]" })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Select, { label: "Category", options: CATEGORY_OPTIONS, value: category, onValueChange: setCategory }), _jsx(Input, { label: "Display order", value: String(order), onChange: (e) => setOrder(parseInt(e.target.value, 10) || 0), type: "number", min: 0, helperText: "Lower = shown first within category." })] }), _jsx(Input, { label: "Priority", value: String(priority), onChange: (e) => setPriority(parseInt(e.target.value, 10) || 0), type: "number", min: 0, helperText: "Higher priority FAQs appear first in search results." }), _jsx(TagInput, { label: "Tags", value: tags, onChange: setTags, placeholder: "e.g. shipping, pokemon, returns" }), _jsxs("div", { className: "space-y-3 rounded-lg border border-zinc-200 dark:border-zinc-700 p-4", children: [_jsx(Text, { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Visibility" }), _jsx(Toggle, { label: "Active (visible to users)", checked: isActive, onChange: setIsActive }), _jsx(Toggle, { label: "Pinned (always shown at top)", checked: isPinned, onChange: setIsPinned }), _jsx(Toggle, { label: "Show on homepage FAQ section", checked: showOnHomepage, onChange: setShowOnHomepage }), _jsx(Toggle, { label: "Show in footer FAQ links", checked: showInFooter, onChange: setShowInFooter })] }), _jsxs("div", { className: "flex gap-3 pt-2", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !canSave || isSubmitting, children: isEdit ? "Save changes" : "Create FAQ" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => {
129
- if (confirm("Delete this FAQ? This cannot be undone.")) {
130
- deleteMutation.mutate();
131
- }
132
- }, children: "Delete FAQ" }))] })] }, "faq-form") }));
118
+ const formSection = (_jsxs(FormShellContext.Provider, { value: shellCtx, children: [_jsxs(Form, { onSubmit: (e) => {
119
+ e.preventDefault();
120
+ clearErrors();
121
+ if (!question.trim()) {
122
+ setFieldError("question", "Question is required");
123
+ return;
124
+ }
125
+ saveMutation.mutate();
126
+ }, className: "space-y-5", children: [_jsx(FieldInput, { name: "question", label: "Question", value: question, onChange: (v) => handleQuestionChange(v), required: true, placeholder: "e.g. How does bidding work on LetItRip?" }), _jsx(Input, { label: "Slug", value: slug, onChange: (e) => {
127
+ setSlug(e.target.value);
128
+ setSlugManual(true);
129
+ }, placeholder: "faq-how-does-bidding-work", helperText: "Auto-generated from question. Must start with 'faq-'." }), _jsxs("div", { className: "space-y-1", children: [_jsx(Text, { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Answer" }), _jsx(RichTextEditor, { value: answer, onChange: setAnswer, placeholder: "Write a clear, helpful answer...", minHeightClassName: "min-h-[200px]" })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Select, { label: "Category", options: CATEGORY_OPTIONS, value: category, onValueChange: setCategory }), _jsx(Input, { label: "Display order", value: String(order), onChange: (e) => setOrder(parseInt(e.target.value, 10) || 0), type: "number", min: 0, helperText: "Lower = shown first within category." })] }), _jsx(Input, { label: "Priority", value: String(priority), onChange: (e) => setPriority(parseInt(e.target.value, 10) || 0), type: "number", min: 0, helperText: "Higher priority FAQs appear first in search results." }), _jsx(TagInput, { label: "Tags", value: tags, onChange: setTags, placeholder: "e.g. shipping, pokemon, returns" }), _jsxs("div", { className: "space-y-3 rounded-lg border border-zinc-200 dark:border-zinc-700 p-4", children: [_jsx(Text, { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Visibility" }), _jsx(Toggle, { label: "Active (visible to users)", checked: isActive, onChange: setIsActive }), _jsx(Toggle, { label: "Pinned (always shown at top)", checked: isPinned, onChange: setIsPinned }), _jsx(Toggle, { label: "Show on homepage FAQ section", checked: showOnHomepage, onChange: setShowOnHomepage }), _jsx(Toggle, { label: "Show in footer FAQ links", checked: showInFooter, onChange: setShowInFooter })] }), _jsxs("div", { className: "flex gap-3 pt-2", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !canSave || isSubmitting, children: isEdit ? "Save changes" : "Create FAQ" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => setDeleteConfirmOpen(true), children: "Delete FAQ" }))] })] }, "faq-form"), deleteConfirmOpen && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete FAQ", message: "Delete this FAQ? This cannot be undone.", onConfirm: () => { deleteMutation.mutate(); setDeleteConfirmOpen(false); }, onClose: () => setDeleteConfirmOpen(false), isDeleting: deleteMutation.isPending }))] }));
133
130
  if (embedded) {
134
131
  return _jsx("div", { className: "overflow-y-auto p-4", children: formSection });
135
132
  }
@@ -1,19 +1,17 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import React, { useState, useCallback } from "react";
4
- import { Plus, X } from "lucide-react";
5
- import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
- import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
7
- import { usePanelUrlSync } from "../../../react/hooks/use-panel-url-sync";
8
- import { BulkActionBar, Button, Heading, ListingToolbar, ListingViewShell, Pagination, SideDrawer, Text } from "../../../ui";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import React from "react";
4
+ import { Plus } from "lucide-react";
5
+ import { BulkActionBar, Button, Heading, ListingToolbar, ListingViewShell, Pagination, SideDrawer, Text, ListingFilterDrawer } from "../../../ui";
9
6
  import { useBottomActions } from "../../layout";
10
7
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
11
8
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
12
- import { toRecordArray, toRelativeDate, toStringValue, useAdminListingData, } from "../hooks/useAdminListingData";
9
+ import { buildBulkAction } from "../../../_internal/shared/actions/bulk-helpers";
10
+ import { toRecordArray, toRelativeDate, toStringValue, } from "../hooks/useAdminListingData";
11
+ import { useAdminListing } from "../hooks/useAdminListing";
13
12
  import { DataTable } from "./DataTable";
14
13
  import { AdminViewCards } from "./AdminViewCards";
15
14
  import { AdminFaqEditorView } from "./AdminFaqEditorView";
16
- const PAGE_SIZE = 25;
17
15
  const FILTER_KEYS = ["isActive"];
18
16
  const DEFAULT_SORT = "priority";
19
17
  const SORT_OPTIONS = [
@@ -21,55 +19,13 @@ const SORT_OPTIONS = [
21
19
  { value: "-createdAt", label: "Newest" },
22
20
  { value: "question", label: "Question A–Z" },
23
21
  ];
24
- function FaqsFilterDrawer({ filterOpen, setFilterOpen, activeFilterCount, clearFilters, pendingFilters, setPendingFilters, applyFilters, }) {
25
- if (!filterOpen)
26
- return null;
27
- return (_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: _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: "Published", value: "true" }, { label: "Draft", 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 ? "bg-primary text-white border-primary" : "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-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})` : ""] }) })] })] }));
28
- }
29
22
  export function AdminFaqsView({ children, getRowHref, onBulkArchive, onBulkDelete, ...props }) {
30
23
  const hasChildren = React.Children.count(children) > 0;
31
- const [view, setView] = useState("table");
32
- const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
33
- const { openCreatePanel, openEditPanel, closePanel, isCreateOpen, isEditOpen, editId } = usePanelUrlSync();
34
- const [searchInput, setSearchInput] = useState(table.get("q") || "");
35
- const [filterOpen, setFilterOpen] = useState(false);
36
- const [pendingFilters, setPendingFilters] = useState(() => Object.fromEntries(FILTER_KEYS.map((k) => [k, table.get(k)])));
37
- const openFilters = useCallback(() => {
38
- setPendingFilters(Object.fromEntries(FILTER_KEYS.map((k) => [k, table.get(k)])));
39
- setFilterOpen(true);
40
- }, [table]);
41
- const applyFilters = useCallback(() => {
42
- const updates = { page: "1" };
43
- for (const k of FILTER_KEYS)
44
- updates[k] = pendingFilters[k] ?? "";
45
- table.setMany(updates);
46
- setFilterOpen(false);
47
- }, [pendingFilters, table]);
48
- const clearFilters = useCallback(() => {
49
- setPendingFilters(Object.fromEntries(FILTER_KEYS.map((k) => [k, ""])));
50
- }, []);
51
- const resetAll = useCallback(() => {
52
- const updates = { q: "", sort: "" };
53
- for (const k of FILTER_KEYS)
54
- updates[k] = "";
55
- table.setMany(updates);
56
- setSearchInput("");
57
- }, [table]);
58
- const commitSearch = useCallback(() => {
59
- table.set("q", searchInput.trim());
60
- }, [searchInput, table]);
61
- const activeFilterCount = FILTER_KEYS.filter((k) => !!table.get(k)).length;
62
- const hasActiveState = !!table.get("q") || table.get("sort") !== DEFAULT_SORT || activeFilterCount > 0;
63
- const isActiveRaw = table.get("isActive");
64
- const filters = isActiveRaw ? `isActive==${isActiveRaw}` : undefined;
65
- const { rows, total, isLoading, errorMessage, refetch } = useAdminListingData({
24
+ const listing = useAdminListing({
25
+ filterKeys: FILTER_KEYS,
26
+ defaultSort: DEFAULT_SORT,
66
27
  queryKey: ["admin", "faqs", "listing"],
67
28
  endpoint: ADMIN_ENDPOINTS.FAQS,
68
- page: table.getNumber("page", 1),
69
- pageSize: PAGE_SIZE,
70
- sorts: table.get("sort") || DEFAULT_SORT,
71
- filters,
72
- q: table.get("q") || undefined,
73
29
  mapRows: (response) => toRecordArray(response.items).map((item, index) => ({
74
30
  id: toStringValue(item.id, `faq-${index}`),
75
31
  primary: toStringValue(item.question, "Untitled question"),
@@ -78,26 +34,19 @@ export function AdminFaqsView({ children, getRowHref, onBulkArchive, onBulkDelet
78
34
  updatedAt: toRelativeDate(item.updatedAt ?? item.createdAt),
79
35
  })),
80
36
  getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
37
+ buildFilters: (filterState) => {
38
+ const isActiveRaw = filterState.isActive;
39
+ return isActiveRaw ? `isActive==${isActiveRaw}` : undefined;
40
+ },
81
41
  });
82
- const currentPage = table.getNumber("page", 1);
83
- const totalPages = Math.ceil(total / PAGE_SIZE);
84
- const selection = useBulkSelection({ items: rows, keyExtractor: (r) => r.id });
42
+ const { view, setView, table, panel, searchInput, setSearchInput, commitSearch, filterOpen, setFilterOpen, openFilters, applyFilters, clearFilters, pendingFilters, setPendingFilters, activeFilterCount, hasActiveState, resetAll, rows, isLoading, errorMessage, refetch, currentPage, totalPages, selection } = listing;
85
43
  const bulkActions = [
86
- ...(onBulkArchive ? [{
87
- id: "bulk-archive",
88
- label: ACTIONS.ADMIN["archive-faq"].label,
89
- onClick: async () => { await onBulkArchive(selection.selectedIds); selection.clearSelection(); refetch?.(); },
90
- }] : []),
91
- ...(onBulkDelete ? [{
92
- id: "bulk-delete",
93
- label: ACTIONS.ADMIN["delete-faq"].label,
94
- variant: "danger",
95
- onClick: async () => { await onBulkDelete(selection.selectedIds); selection.clearSelection(); refetch?.(); },
96
- }] : []),
44
+ ...(onBulkArchive ? [buildBulkAction(ACTIONS.ADMIN["archive-faq"], async () => { await onBulkArchive(selection.selectedIds); selection.clearSelection(); refetch?.(); })] : []),
45
+ ...(onBulkDelete ? [buildBulkAction(ACTIONS.ADMIN["delete-faq"], async () => { await onBulkDelete(selection.selectedIds); selection.clearSelection(); refetch?.(); })] : []),
97
46
  ];
98
47
  useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: bulkActions } } : {});
99
48
  if (hasChildren) {
100
49
  return _jsx(ListingViewShell, { portal: "admin", ...props, children: children });
101
50
  }
102
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(Heading, { level: 1, className: "sr-only", children: "FAQs" }), _jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search questions, categories, or tokens", 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: _jsxs(Button, { size: "sm", onClick: openCreatePanel, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), "Add FAQ"] }) }), 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 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 FAQs found", onRowClick: (row) => openEditPanel(row.id) })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No FAQs found", onRowClick: undefined, selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] }), _jsx(FaqsFilterDrawer, { filterOpen: filterOpen, setFilterOpen: setFilterOpen, activeFilterCount: activeFilterCount, clearFilters: clearFilters, pendingFilters: pendingFilters, setPendingFilters: setPendingFilters, applyFilters: applyFilters }), _jsx(SideDrawer, { isOpen: isCreateOpen || isEditOpen, onClose: closePanel, title: isCreateOpen ? "Add FAQ" : "Edit FAQ", mode: isCreateOpen ? "create" : "edit", children: (isCreateOpen || isEditOpen) && (_jsx(AdminFaqEditorView, { faqId: editId ?? undefined, onSaved: closePanel, onDeleted: closePanel, embedded: true })) })] }));
51
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(Heading, { level: 1, className: "sr-only", children: "FAQs" }), _jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search questions, categories, or tokens", 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: _jsxs(Button, { size: "sm", onClick: panel.openCreatePanel, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), "Add FAQ"] }) }), 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 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 FAQs found", onRowClick: (row) => panel.openEditPanel(row.id) })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No FAQs found", onRowClick: undefined, selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] }), _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: "Published", value: "true" }, { label: "Draft", 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 ? "bg-primary text-white border-primary" : "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(SideDrawer, { isOpen: panel.isCreateOpen || panel.isEditOpen, onClose: panel.closePanel, title: panel.isCreateOpen ? "Add FAQ" : "Edit FAQ", mode: panel.isCreateOpen ? "create" : "edit", children: (panel.isCreateOpen || panel.isEditOpen) && (_jsx(AdminFaqEditorView, { faqId: panel.editId ?? undefined, onSaved: panel.closePanel, onDeleted: panel.closePanel, embedded: true })) })] }));
103
52
  }
@@ -1,8 +1,8 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import React from "react";
4
4
  import { useMutation, useQuery } from "@tanstack/react-query";
5
- import { Button, Div, Form, Grid, Input, Select, Stack, StackedViewShell, Text, Toggle, useToast, } from "../../../ui";
5
+ import { Button, ConfirmDeleteModal, Div, Form, Grid, Input, Select, Stack, StackedViewShell, Text, Toggle, useToast, } from "../../../ui";
6
6
  import { apiClient } from "../../../http";
7
7
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
8
8
  import { ERROR_MESSAGES } from "../../../errors/messages";
@@ -29,6 +29,7 @@ export function AdminFeatureEditorView({ featureId, fixedScope, fixedStoreId, em
29
29
  const [productTypes, setProductTypes] = React.useState(["all"]);
30
30
  const [storeId, setStoreId] = React.useState(fixedStoreId ?? "");
31
31
  const [isActive, setIsActive] = React.useState(true);
32
+ const [deleteConfirmOpen, setDeleteConfirmOpen] = React.useState(false);
32
33
  const [displayOrder, setDisplayOrder] = React.useState(String(PRODUCT_FEATURE_DEFAULT_DISPLAY_ORDER));
33
34
  const createEndpoint = endpointOverride?.create ?? ADMIN_ENDPOINTS.PRODUCT_FEATURES;
34
35
  const byIdEndpoint = endpointOverride?.byId ?? ADMIN_ENDPOINTS.PRODUCT_FEATURE_BY_ID;
@@ -138,13 +139,10 @@ export function AdminFeatureEditorView({ featureId, fixedScope, fixedStoreId, em
138
139
  const checked = productTypes.includes(opt.value);
139
140
  const pillClass = `${PILL_BASE_CLASS} ${checked ? PILL_CHECKED_CLASS : PILL_UNCHECKED_CLASS}`;
140
141
  return (_jsxs("label", { className: pillClass, children: [_jsx("input", { type: "checkbox", className: "sr-only", checked: checked, onChange: () => toggleProductType(opt.value) }), opt.label] }, opt.value));
141
- }) })] }), !fixedScope && (_jsx(Select, { label: "Scope", value: scope, onChange: (e) => setScope(e.target.value), options: PRODUCT_FEATURE_SCOPE_OPTIONS })), scope === "store" && !fixedStoreId && (_jsx(Select, { label: "Store", value: storeId, onChange: (e) => setStoreId(e.target.value), options: storeOptions, required: true, helperText: "Store-scope features are visible only on this store's listings." })), _jsx(Toggle, { label: "Active", checked: isActive, onChange: setIsActive }), _jsxs(Div, { className: "flex gap-3 pt-2", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: isDisabled, children: isEdit ? "Save changes" : "Create feature" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => {
142
- if (confirm(DELETE_CONFIRM_TEXT)) {
143
- deleteMutation.mutate();
144
- }
145
- }, children: "Delete" }))] })] }) }, "feature-form"));
142
+ }) })] }), !fixedScope && (_jsx(Select, { label: "Scope", value: scope, onChange: (e) => setScope(e.target.value), options: PRODUCT_FEATURE_SCOPE_OPTIONS })), scope === "store" && !fixedStoreId && (_jsx(Select, { label: "Store", value: storeId, onChange: (e) => setStoreId(e.target.value), options: storeOptions, required: true, helperText: "Store-scope features are visible only on this store's listings." })), _jsx(Toggle, { label: "Active", checked: isActive, onChange: setIsActive }), _jsxs(Div, { className: "flex gap-3 pt-2", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: isDisabled, children: isEdit ? "Save changes" : "Create feature" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => setDeleteConfirmOpen(true), children: "Delete" }))] })] }) }, "feature-form"));
143
+ const deleteModal = deleteConfirmOpen && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Feature", message: DELETE_CONFIRM_TEXT, onConfirm: () => { deleteMutation.mutate(); setDeleteConfirmOpen(false); }, onClose: () => setDeleteConfirmOpen(false), isDeleting: deleteMutation.isPending }));
146
144
  if (embedded) {
147
- return _jsx(Div, { className: "overflow-y-auto p-4", children: formSection });
145
+ return _jsxs(Div, { className: "overflow-y-auto p-4", children: [formSection, deleteModal] });
148
146
  }
149
- return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Feature" : "New Feature", sections: [formSection] }));
147
+ return (_jsxs(_Fragment, { children: [_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Feature" : "New Feature", sections: [formSection] }), deleteModal] }));
150
148
  }
@@ -41,7 +41,7 @@ function AccordionSection({ title, defaultOpen = true, children }) {
41
41
  return (_jsxs(Div, { className: "rounded-lg border border-zinc-200 dark:border-zinc-700 overflow-hidden", children: [_jsxs("button", { type: "button", onClick: () => setOpen((v) => !v), className: "w-full flex items-center justify-between px-4 py-3 bg-zinc-50 dark:bg-zinc-800/60 text-left", "aria-expanded": open, children: [_jsx(Text, { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: title }), _jsx("svg", { className: `h-4 w-4 text-zinc-400 transition-transform ${open ? "rotate-180" : ""}`, fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) })] }), open && (_jsx(Div, { className: "divide-y divide-zinc-100 dark:divide-zinc-800", children: children }))] }));
42
42
  }
43
43
  function FlagRow({ label, desc, checked, onChange, rollout, onRolloutChange, showRollout }) {
44
- return (_jsxs(Div, { className: "flex items-center justify-between gap-4 px-4 py-3 bg-white dark:bg-zinc-900", children: [_jsxs(Div, { className: "flex-1 min-w-0", children: [_jsx(Toggle, { checked: checked, onChange: onChange, label: label }), _jsx(Text, { className: "mt-0.5 ml-10 text-xs text-zinc-400 dark:text-zinc-400 truncate", children: desc })] }), showRollout && (_jsxs(Div, { className: "flex flex-col gap-1 w-28 shrink-0", children: [_jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Rollout %" }), _jsx(Input, { type: "number", min: 0, max: 100, value: rollout ?? 100, onChange: (e) => onRolloutChange?.(Math.min(100, Math.max(0, Number(e.target.value)))), disabled: !checked, className: "w-full" })] }))] }));
44
+ return (_jsxs(Div, { surface: "default", padding: "inline", className: "flex items-center justify-between gap-4", children: [_jsxs(Div, { className: "flex-1 min-w-0", children: [_jsx(Toggle, { checked: checked, onChange: onChange, label: label }), _jsx(Text, { className: "mt-0.5 ml-10 text-xs text-zinc-400 dark:text-zinc-400 truncate", children: desc })] }), showRollout && (_jsxs(Div, { className: "flex flex-col gap-1 w-28 shrink-0", children: [_jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Rollout %" }), _jsx(Input, { type: "number", min: 0, max: 100, value: rollout ?? 100, onChange: (e) => onRolloutChange?.(Math.min(100, Math.max(0, Number(e.target.value)))), disabled: !checked, className: "w-full" })] }))] }));
45
45
  }
46
46
  export function AdminFeatureFlagsView({ labels = {}, renderFlags, ...rest }) {
47
47
  const queryClient = useQueryClient();
@@ -27,7 +27,7 @@ const TAB_BASE_CLASS = "rounded-full px-3 py-1 text-xs font-medium border transi
27
27
  const TAB_ACTIVE_CLASS = "bg-primary text-white border-primary";
28
28
  const TAB_INACTIVE_CLASS = "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800";
29
29
  const PAGINATION_BAR_CLASS = "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";
30
- const ERROR_BANNER_CLASS = "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";
30
+ const ERROR_BANNER_CLASS = "mb-4 rounded-xl border border-red-200 bg-error-surface px-4 py-3 text-sm text-error dark:border-red-900/60";
31
31
  function mapFeatureRow(item, index) {
32
32
  const productTypes = Array.isArray(item.productTypes)
33
33
  ? item.productTypes
@@ -75,5 +75,5 @@ export function AdminGuideHubView({ permissions = [], isFullAdmin = false }) {
75
75
  background: "linear-gradient(135deg,var(--appkit-color-primary-700,#4f46e5) 0%,var(--appkit-color-cobalt,#2563eb) 60%,var(--appkit-color-secondary-400,#7c3aed) 100%)",
76
76
  }, children: [_jsxs(Div, { className: "flex items-center gap-3 mb-3", children: [_jsx(Div, { className: "flex-shrink-0 w-10 h-10 rounded-xl bg-white/20 flex items-center justify-center", children: _jsx(BookOpen, { className: "w-5 h-5 text-white" }) }), _jsx(Text, { className: "text-sm font-semibold text-white/80 uppercase tracking-widest", children: "Admin & Employee Guide" })] }), _jsx(Heading, { level: 1, className: "text-2xl md:text-3xl font-bold text-white mb-2", children: "LetItRip Internal Guide" }), _jsx(Text, { className: "text-white/80 text-base", children: "Everything you need to operate and manage LetItRip \u2014 India's largest collectibles marketplace." })] }) }), _jsx(Alert, { variant: "info", compact: true, children: "These guides describe expected platform behaviour. Real access to each section is enforced independently by the permission system \u2014 this page is reference only." }), !hasAny && (_jsx(Alert, { variant: "info", title: "Limited access", children: "Your permission set doesn't include read access to any admin sections yet. Contact your admin to request the permissions you need." })), hasAny && (_jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "text-lg font-semibold text-[var(--appkit-color-text)] mb-4", children: "Guides" }), _jsx(Div, { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children: visibleCards.map(({ Icon, title, description, href }) => (_jsxs("a", { href: href, className: "group flex flex-col gap-3 rounded-xl border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] p-5 hover:border-[var(--appkit-color-primary)] hover:shadow-md transition-all", children: [_jsxs(Div, { className: "flex items-center gap-3", children: [_jsx(Div, { className: "flex-shrink-0 w-9 h-9 rounded-lg flex items-center justify-center", style: {
77
77
  background: "linear-gradient(135deg,var(--appkit-color-primary-700,#4f46e5) 0%,var(--appkit-color-cobalt,#2563eb) 100%)",
78
- }, children: _jsx(Icon, { className: "w-4 h-4 text-white" }) }), _jsx(Text, { className: "font-semibold text-[var(--appkit-color-text)] group-hover:text-[var(--appkit-color-primary)] transition-colors", children: title })] }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)] leading-relaxed", children: description }), _jsx(Text, { className: "text-xs font-medium text-[var(--appkit-color-primary)] mt-auto", children: "Read guide \u2192" })] }, title))) })] })), _jsx(Section, { className: "rounded-2xl border border-amber-200 bg-amber-50 dark:bg-amber-950/20 dark:border-amber-800 p-6", children: _jsxs(Div, { className: "flex items-start gap-3", children: [_jsx(AlertTriangle, { className: "w-5 h-5 text-amber-600 dark:text-amber-400 flex-shrink-0 mt-0.5" }), _jsxs(Div, { children: [_jsx(Text, { className: "font-semibold text-amber-800 dark:text-amber-300 mb-1", children: "Remember: with great access comes responsibility" }), _jsx(Text, { className: "text-sm text-amber-700 dark:text-amber-400", children: "Admin actions are logged. Never access user PII (email, phone) without a legitimate support reason. Never grant capabilities or permissions without documented approval. When in doubt, escalate to a senior admin." })] })] }) })] }));
78
+ }, children: _jsx(Icon, { className: "w-4 h-4 text-white" }) }), _jsx(Text, { className: "font-semibold text-[var(--appkit-color-text)] group-hover:text-[var(--appkit-color-primary)] transition-colors", children: title })] }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)] leading-relaxed", children: description }), _jsx(Text, { className: "text-xs font-medium text-[var(--appkit-color-primary)] mt-auto", children: "Read guide \u2192" })] }, title))) })] })), _jsx(Section, { className: "rounded-2xl border border-amber-200 bg-warning-surface dark:border-amber-800 p-6", children: _jsxs(Div, { className: "flex items-start gap-3", children: [_jsx(AlertTriangle, { className: "w-5 h-5 text-warning flex-shrink-0 mt-0.5" }), _jsxs(Div, { children: [_jsx(Text, { className: "font-semibold text-amber-800 dark:text-amber-300 mb-1", children: "Remember: with great access comes responsibility" }), _jsx(Text, { className: "text-sm text-amber-700 dark:text-amber-400", children: "Admin actions are logged. Never access user PII (email, phone) without a legitimate support reason. Never grant capabilities or permissions without documented approval. When in doubt, escalate to a senior admin." })] })] }) })] }));
79
79
  }
@@ -57,5 +57,5 @@ export function AdminHistoryView({ children, ...props }) {
57
57
  if (hasChildren) {
58
58
  return _jsx(ListingViewShell, { portal: "admin", ...props, children: children });
59
59
  }
60
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: 0, searchValue: searchInput, searchPlaceholder: "Search by user ID", 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 user history records found" })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No user history records found", onRowClick: undefined, selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] })] }));
60
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: 0, searchValue: searchInput, searchPlaceholder: "Search by user ID", 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 user history records found" })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No user history records found", onRowClick: undefined, selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] })] }));
61
61
  }
@@ -64,5 +64,5 @@ export function AdminListingScaffold({ title, subtitle, actionLabel, actionHref,
64
64
  } })), sortSlot: sortSlot ?? (_jsx(Button, { type: "button", variant: "outline", size: "sm", children: "Newest first" })), actionsSlot: actionsSlot ??
65
65
  (actionLabel ? (actionHref ? (_jsx(Button, { type: "button", variant: "primary", size: "sm", onClick: () => {
66
66
  window.location.href = actionHref;
67
- }, children: actionLabel })) : (_jsx(Button, { type: "button", variant: "primary", size: "sm", children: actionLabel }))) : undefined), filterActiveCount: activeFilters?.length ?? 0, filterPendingCount: 0, errorSlot: errorMessage ? (_jsx(Div, { className: "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 })) : undefined, children: hasChildren ? (children) : (_jsx(DataTable, { columns: columns ?? buildColumns(), rows: rows, isLoading: isLoading, emptyLabel: emptyLabel, getRowHref: getRowHref, renderRowActions: renderRowActions })) }));
67
+ }, children: actionLabel })) : (_jsx(Button, { type: "button", variant: "primary", size: "sm", children: actionLabel }))) : undefined), filterActiveCount: activeFilters?.length ?? 0, filterPendingCount: 0, errorSlot: errorMessage ? (_jsx(Div, { className: "rounded-xl border border-red-200 bg-error-surface px-4 py-3 text-sm text-error dark:border-red-900/60", children: errorMessage })) : undefined, children: hasChildren ? (children) : (_jsx(DataTable, { columns: columns ?? buildColumns(), rows: rows, isLoading: isLoading, emptyLabel: emptyLabel, getRowHref: getRowHref, renderRowActions: renderRowActions })) }));
68
68
  }
@@ -1,14 +1,14 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import React, { useState, useCallback } from "react";
4
- import { X } from "lucide-react";
5
4
  import { useMutation, useQueryClient } from "@tanstack/react-query";
6
5
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
7
6
  import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
8
- import { BulkActionBar, Button, ConfirmDeleteModal, FilterChipGroup, ListingToolbar, ListingViewShell, Pagination, RowActionMenu, useToast, } from "../../../ui";
7
+ import { BulkActionBar, Button, ConfirmDeleteModal, FilterChipGroup, ListingToolbar, ListingViewShell, Pagination, RowActionMenu, useToast, ListingFilterDrawer } from "../../../ui";
9
8
  import { useBottomActions } from "../../layout";
10
9
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
11
10
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
11
+ import { buildBulkAction } from "../../../_internal/shared/actions/bulk-helpers";
12
12
  import { ADMIN_NEWSLETTER_STATUS_TABS } from "../constants/filter-tabs";
13
13
  import { toRecordArray, toRelativeDate, toStringValue, useAdminListingData, } from "../hooks/useAdminListingData";
14
14
  import { DataTable } from "./DataTable";
@@ -21,11 +21,6 @@ const SORT_OPTIONS = [
21
21
  { value: "subscribedAt", label: "Oldest" },
22
22
  ];
23
23
  const STATUS_OPTIONS = ADMIN_NEWSLETTER_STATUS_TABS;
24
- function NewsletterFilterDrawer({ filterOpen, setFilterOpen, activeFilterCount, clearFilters, pendingFilters, setPendingFilters, applyFilters, }) {
25
- if (!filterOpen)
26
- return null;
27
- return (_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})` : ""] }) })] })] }));
28
- }
29
24
  export function AdminNewsletterView({ children, onBulkUnsubscribe, ...props }) {
30
25
  const hasChildren = React.Children.count(children) > 0;
31
26
  const [view, setView] = useState("table");
@@ -126,18 +121,13 @@ export function AdminNewsletterView({ children, onBulkUnsubscribe, ...props }) {
126
121
  const totalPages = Math.ceil(total / PAGE_SIZE);
127
122
  const selection = useBulkSelection({ items: rows, keyExtractor: (r) => r.id });
128
123
  const bulkActions = [
129
- ...(onBulkUnsubscribe ? [{
130
- id: "bulk-unsubscribe",
131
- label: ACTIONS.ADMIN["unsubscribe-newsletter"].label,
132
- variant: "danger",
133
- onClick: async () => { await onBulkUnsubscribe(selection.selectedIds); selection.clearSelection(); },
134
- }] : []),
124
+ ...(onBulkUnsubscribe ? [buildBulkAction(ACTIONS.ADMIN["unsubscribe-newsletter"], async () => { await onBulkUnsubscribe(selection.selectedIds); selection.clearSelection(); })] : []),
135
125
  ];
136
126
  useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: bulkActions } } : {});
137
127
  if (hasChildren) {
138
128
  return _jsx(ListingViewShell, { portal: "admin", ...props, children: children });
139
129
  }
140
- return (_jsxs(_Fragment, { children: [selection.selectedCount > 0 && bulkActions.length > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), _jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search by email or source", 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: _jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: handleExportCsv, children: ACTIONS.ADMIN["export-csv"].label }) }), 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 })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No subscribers found", renderRowActions: (row) => {
130
+ return (_jsxs(_Fragment, { children: [selection.selectedCount > 0 && bulkActions.length > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), _jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search by email or source", 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: _jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: handleExportCsv, children: ACTIONS.ADMIN["export-csv"].label }) }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-error-surface px-4 py-3 text-sm text-error dark:border-red-900/60", children: errorMessage })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No subscribers found", renderRowActions: (row) => {
141
131
  const nr = row;
142
132
  return (_jsx(RowActionMenu, { actions: [
143
133
  {
@@ -147,6 +137,6 @@ export function AdminNewsletterView({ children, onBulkUnsubscribe, ...props }) {
147
137
  onClick: () => { setSelectedRow(nr); setUnsubscribeOpen(true); },
148
138
  },
149
139
  ] }));
150
- } })] }), _jsx(NewsletterFilterDrawer, { filterOpen: filterOpen, setFilterOpen: setFilterOpen, activeFilterCount: activeFilterCount, clearFilters: clearFilters, pendingFilters: pendingFilters, setPendingFilters: setPendingFilters, applyFilters: applyFilters })] }), _jsx(ConfirmDeleteModal, { isOpen: unsubscribeOpen, onClose: () => { setUnsubscribeOpen(false); setSelectedRow(null); }, onConfirm: () => { if (selectedRow)
140
+ } })] }), _jsx(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearFilters, activeCount: activeFilterCount, children: _jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }) })] }), _jsx(ConfirmDeleteModal, { isOpen: unsubscribeOpen, onClose: () => { setUnsubscribeOpen(false); setSelectedRow(null); }, onConfirm: () => { if (selectedRow)
151
141
  unsubscribeMutation.mutate(selectedRow.id); }, isDeleting: unsubscribeMutation.isPending, title: `Unsubscribe ${selectedRow?.primary ?? "subscriber"}?`, message: "The subscriber will be marked as unsubscribed and will no longer receive newsletter emails.", confirmText: "Unsubscribe", variant: "warning" })] }));
152
142
  }
@@ -1,11 +1,10 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import React, { useState, useCallback } from "react";
4
- import { X } from "lucide-react";
5
4
  import { useMutation, useQueryClient } from "@tanstack/react-query";
6
5
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
7
6
  import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
8
- import { BulkActionBar, ConfirmDeleteModal, ListingToolbar, ListingViewShell, Pagination, RowActionMenu, Text, useToast } from "../../../ui";
7
+ import { BulkActionBar, ConfirmDeleteModal, ListingToolbar, ListingViewShell, Pagination, RowActionMenu, Text, useToast, ListingFilterDrawer } from "../../../ui";
9
8
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
10
9
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
11
10
  import { ROW_ACTION_META, ROW_ACTION_ID } from "../../products/constants/action-defs";
@@ -24,11 +23,6 @@ const NOTIF_TYPES = [
24
23
  "All", "order_placed", "order_shipped", "order_delivered", "order_cancelled",
25
24
  "bid_placed", "bid_outbid", "bid_won", "review_posted", "payout_processed",
26
25
  ];
27
- function NotificationsFilterDrawer({ filterOpen, setFilterOpen, activeFilterCount, clearFilters, pendingFilters, setPendingFilters, applyFilters, }) {
28
- if (!filterOpen)
29
- return null;
30
- return (_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: _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: "Type" }), _jsx("div", { className: "flex flex-wrap gap-2", children: NOTIF_TYPES.map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, type: opt === "All" ? "" : opt })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.type || "All") === opt ? "bg-primary text-white border-primary" : "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 }, opt))) })] }) }), _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})` : ""] }) })] })] }));
31
- }
32
26
  export function AdminNotificationsView({ children, ...props }) {
33
27
  const hasChildren = React.Children.count(children) > 0;
34
28
  const [view, setView] = useState("table");
@@ -122,7 +116,7 @@ export function AdminNotificationsView({ children, ...props }) {
122
116
  return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search by title or user ID", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), _jsx(BulkActionBar, { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [
123
117
  { id: ROW_ACTION_ID.MARK_READ, label: ACTIONS.ADMIN["mark-read"].label, variant: "primary", onClick: () => { selection.clearSelection(); } },
124
118
  { id: ROW_ACTION_ID.DELETE, label: ACTIONS.ADMIN["delete-notification"].label, variant: "secondary", onClick: () => { selection.clearSelection(); } },
125
- ] }), 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 })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No notifications found", renderRowActions: (row) => {
119
+ ] }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-error-surface px-4 py-3 text-sm text-error dark:border-red-900/60", children: errorMessage })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No notifications found", renderRowActions: (row) => {
126
120
  const nr = row;
127
121
  useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [
128
122
  { id: ROW_ACTION_ID.MARK_READ, label: ACTIONS.ADMIN["mark-read"].label, variant: "primary", onClick: () => { selection.clearSelection(); } },
@@ -132,6 +126,6 @@ export function AdminNotificationsView({ children, ...props }) {
132
126
  { label: ACTIONS.ADMIN["resend-notification"].label, onClick: () => resendMutation.mutate(nr.id) },
133
127
  { label: ROW_ACTION_META[ROW_ACTION_ID.DELETE].label, destructive: ROW_ACTION_META[ROW_ACTION_ID.DELETE].destructive, onClick: () => setDeleteTarget(nr) },
134
128
  ] }));
135
- } })] }), _jsx(NotificationsFilterDrawer, { filterOpen: filterOpen, setFilterOpen: setFilterOpen, activeFilterCount: activeFilterCount, clearFilters: clearFilters, pendingFilters: pendingFilters, setPendingFilters: setPendingFilters, applyFilters: applyFilters })] }), _jsx(ConfirmDeleteModal, { isOpen: Boolean(deleteTarget), onClose: () => setDeleteTarget(null), onConfirm: () => { if (deleteTarget)
129
+ } })] }), _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: "Type" }), _jsx("div", { className: "flex flex-wrap gap-2", children: NOTIF_TYPES.map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, type: opt === "All" ? "" : opt })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.type || "All") === opt ? "bg-primary text-white border-primary" : "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 }, opt))) })] }) })] }), _jsx(ConfirmDeleteModal, { isOpen: Boolean(deleteTarget), onClose: () => setDeleteTarget(null), onConfirm: () => { if (deleteTarget)
136
130
  deleteMutation.mutate(deleteTarget.id); }, isDeleting: deleteMutation.isPending, title: "Delete notification?", message: "This notification will be permanently removed.", confirmText: "Delete", variant: "danger" })] }));
137
131
  }
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { ShoppingBag, Hash, Scale, Wallet, RotateCcw, DollarSign, Gavel } from "lucide-react";
3
- import { Div, Heading, Text, Section } from "../../../ui";
3
+ import { Div, Heading, Span, Text, Section } from "../../../ui";
4
4
  import { GC } from "../../_guide-cls";
5
5
  export function AdminOrdersGuideView() {
6
6
  return (_jsxs(Div, { className: "space-y-8 pb-10 max-w-3xl mx-auto", children: [_jsxs(Section, { children: [_jsxs(Div, { className: "flex items-center gap-3 mb-2", children: [_jsx(Div, { className: "flex-shrink-0 w-10 h-10 rounded-xl flex items-center justify-center", style: { background: "linear-gradient(135deg,var(--appkit-color-primary-700,#4f46e5) 0%,var(--appkit-color-cobalt,#2563eb) 100%)" }, children: _jsx(ShoppingBag, { className: "w-5 h-5 text-white" }) }), _jsx(Text, { className: "text-sm font-semibold text-[var(--appkit-color-text-muted)] uppercase tracking-widest", children: "Admin Guide" })] }), _jsx(Heading, { level: 1, className: "text-2xl md:text-3xl font-bold text-[var(--appkit-color-text)] mb-2", children: "Orders & Finance" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: "Order statuses, payouts, disputes, returns, and commission math on LetItRip." })] }), [
@@ -22,19 +22,19 @@ export function AdminOrdersGuideView() {
22
22
  },
23
23
  {
24
24
  Icon: Scale, title: "Intervening in a Dispute",
25
- content: (_jsxs("ul", { className: GC.listMuted, children: [_jsx("li", { children: "Admin steps in when: seller is unresponsive for 3+ days on a return, or buyer escalates via support ticket." }), _jsxs("li", { children: ["Admin dispute tools: ", _jsx("strong", { children: "force-accept return" }), " (moves to REFUNDED and withholds seller payout), ", _jsx("strong", { children: "platform credit" }), " (future feature)."] }), _jsx("li", { children: "Document your reasoning in the support ticket before taking any force action." })] })),
25
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsx("li", { children: "Admin steps in when: seller is unresponsive for 3+ days on a return, or buyer escalates via support ticket." }), _jsxs("li", { children: ["Admin dispute tools: ", _jsx(Span, { weight: "bold", children: "force-accept return" }), " (moves to REFUNDED and withholds seller payout), ", _jsx(Span, { weight: "bold", children: "platform credit" }), " (future feature)."] }), _jsx("li", { children: "Document your reasoning in the support ticket before taking any force action." })] })),
26
26
  },
27
27
  {
28
28
  Icon: Wallet, title: "Payouts",
29
- content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Payout cycle" }), ": Weekly. All DELIVERED orders (minus platform commission) are batched into a single payout per store."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Status flow" }), ": PENDING \u2192 PROCESSING \u2192 PAID / FAILED."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "FAILED payout" }), ": Check the store's ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "payoutDetails" }), " \u2014 UPI VPA or bank details may be stale. Contact the seller via their store email before retrying."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "ordersIncluded" }), ": Array of order IDs bundled in this payout batch \u2014 use to audit which orders are covered."] })] })),
29
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Payout cycle" }), ": Weekly. All DELIVERED orders (minus platform commission) are batched into a single payout per store."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Status flow" }), ": PENDING \u2192 PROCESSING \u2192 PAID / FAILED."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "FAILED payout" }), ": Check the store's ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "payoutDetails" }), " \u2014 UPI VPA or bank details may be stale. Contact the seller via their store email before retrying."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "ordersIncluded" }), ": Array of order IDs bundled in this payout batch \u2014 use to audit which orders are covered."] })] })),
30
30
  },
31
31
  {
32
32
  Icon: RotateCcw, title: "Return Requests",
33
- content: (_jsxs("ul", { className: GC.listMuted, children: [_jsx("li", { children: "Admin can view the return reason and attached photos on the order detail page." }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "When to override a seller rejection" }), ": Only when photographic evidence clearly supports the buyer's claim of a significant not-as-described defect. Do not override for buyer's remorse."] }), _jsx("li", { children: "After admin override: refund is issued automatically via Razorpay (3\u20137 business days for card, 1\u20132 for UPI). Seller payout for that order is withheld." })] })),
33
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsx("li", { children: "Admin can view the return reason and attached photos on the order detail page." }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "When to override a seller rejection" }), ": Only when photographic evidence clearly supports the buyer's claim of a significant not-as-described defect. Do not override for buyer's remorse."] }), _jsx("li", { children: "After admin override: refund is issued automatically via Razorpay (3\u20137 business days for card, 1\u20132 for UPI). Seller payout for that order is withheld." })] })),
34
34
  },
35
35
  {
36
36
  Icon: DollarSign, title: "Commission & Settlement Math",
37
- content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "platformFee" }), ": Set in ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "siteSettings.fees.platformFee" }), " (percentage). Applied to the order's item subtotal."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "customCommissionRate" }), ": Stored on ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "StoreDocument" }), " for stores with the ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "lower_commission_rate" }), " capability. Overrides the platform default for that store."] }), _jsx("li", { children: "Payout = order subtotal \u00D7 (1 \u2212 commission rate). Shipping fees are passed through to the seller at cost." })] })),
37
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "platformFee" }), ": Set in ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "siteSettings.fees.platformFee" }), " (percentage). Applied to the order's item subtotal."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "customCommissionRate" }), ": Stored on ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "StoreDocument" }), " for stores with the ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "lower_commission_rate" }), " capability. Overrides the platform default for that store."] }), _jsx("li", { children: "Payout = order subtotal \u00D7 (1 \u2212 commission rate). Shipping fees are passed through to the seller at cost." })] })),
38
38
  },
39
39
  {
40
40
  Icon: Gavel, title: "Auction Settlement",
@@ -1,10 +1,9 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import React, { useState, useCallback } from "react";
4
- import { X } from "lucide-react";
5
4
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
5
  import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
7
- import { BulkActionBar, FilterChipGroup, ListingToolbar, Pagination, ListingViewShell, useToast } from "../../../ui";
6
+ import { BulkActionBar, FilterChipGroup, ListingToolbar, Pagination, ListingViewShell, useToast, ListingFilterDrawer } from "../../../ui";
8
7
  import { apiClient } from "../../../http";
9
8
  import { QuickEditMenu } from "./QuickEditMenu";
10
9
  import { AdminViewCards } from "./AdminViewCards";
@@ -23,11 +22,6 @@ const SORT_OPTIONS = [
23
22
  { value: "createdAt", label: "Oldest" },
24
23
  ];
25
24
  const STATUS_OPTIONS = ADMIN_ORDER_STATUS_TABS;
26
- function OrdersFilterDrawer({ filterOpen, setFilterOpen, activeFilterCount, clearFilters, pendingFilters, setPendingFilters, applyFilters, }) {
27
- if (!filterOpen)
28
- return null;
29
- return (_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})` : ""] }) })] })] }));
30
- }
31
25
  export function AdminOrdersView({ children, ...props }) {
32
26
  const hasChildren = React.Children.count(children) > 0;
33
27
  const { showToast } = useToast();
@@ -118,7 +112,7 @@ export function AdminOrdersView({ children, ...props }) {
118
112
  void handleQuickStatus(id, "DELIVERED"); selection.clearSelection(); } },
119
113
  { id: "mark-cancelled", label: ACTIONS.ADMIN["cancel-order"].label, variant: "danger", onClick: () => { for (const id of selection.selectedIds)
120
114
  void handleQuickStatus(id, "CANCELLED"); selection.clearSelection(); } },
121
- ] }), 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 orders found", selectedIds: selection.selectedIdSet, onToggleSelect: selection.toggle, onToggleSelectAll: (next) => next ? selection.setSelectedIds(rows.map(r => r.id)) : selection.clearSelection(), renderRowActions: (row) => (_jsx(QuickEditMenu, { actions: [
115
+ ] }), 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 orders found", selectedIds: selection.selectedIdSet, onToggleSelect: selection.toggle, onToggleSelectAll: (next) => next ? selection.setSelectedIds(rows.map(r => r.id)) : selection.clearSelection(), renderRowActions: (row) => (_jsx(QuickEditMenu, { actions: [
122
116
  {
123
117
  label: "View full details",
124
118
  onClick: () => { setSelectedRow(row); setDrawerOpen(true); },
@@ -135,5 +129,5 @@ export function AdminOrdersView({ children, ...props }) {
135
129
  onSubmit: (vals) => handleQuickStatus(row.id, String(vals.status ?? "")),
136
130
  submitLabel: "Update",
137
131
  },
138
- ] })) })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No orders found", onRowClick: (row) => { setSelectedRow(row); setDrawerOpen(true); }, selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] }), _jsx(OrdersFilterDrawer, { filterOpen: filterOpen, setFilterOpen: setFilterOpen, activeFilterCount: activeFilterCount, clearFilters: clearFilters, pendingFilters: pendingFilters, setPendingFilters: setPendingFilters, applyFilters: applyFilters })] }), _jsx(AdminOrderEditorView, { open: drawerOpen, onClose: () => setDrawerOpen(false), orderId: selectedRow?.id, orderLabel: selectedRow?.primary, currentStatus: selectedRow?.status })] }));
132
+ ] })) })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No orders found", onRowClick: (row) => { setSelectedRow(row); setDrawerOpen(true); }, selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] }), _jsx(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearFilters, activeCount: activeFilterCount, children: _jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }) })] }), _jsx(AdminOrderEditorView, { open: drawerOpen, onClose: () => setDrawerOpen(false), orderId: selectedRow?.id, orderLabel: selectedRow?.primary, currentStatus: selectedRow?.status })] }));
139
133
  }