@mohasinac/appkit 4.61.0 → 4.62.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (281) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +19 -3
  3. package/dist/_internal/client/features/maintenance/views/AnalysisRunnerView.js +1 -1
  4. package/dist/_internal/client/features/maintenance/views/CloudLogsListView.js +1 -1
  5. package/dist/_internal/server/features/checkout/actions.d.ts +80 -0
  6. package/dist/_internal/server/features/checkout/actions.js +542 -26
  7. package/dist/_internal/server/features/invoicing/allocate.d.ts +63 -0
  8. package/dist/_internal/server/features/invoicing/allocate.js +162 -0
  9. package/dist/_internal/server/features/invoicing/credit-note.d.ts +57 -0
  10. package/dist/_internal/server/features/invoicing/credit-note.js +126 -0
  11. package/dist/_internal/server/features/invoicing/gstr1.d.ts +74 -0
  12. package/dist/_internal/server/features/invoicing/gstr1.js +251 -0
  13. package/dist/_internal/server/features/invoicing/issue.d.ts +96 -0
  14. package/dist/_internal/server/features/invoicing/issue.js +202 -0
  15. package/dist/_internal/server/features/orders/actions.d.ts +8 -1
  16. package/dist/_internal/server/features/orders/actions.js +81 -8
  17. package/dist/_internal/server/features/orders/adapters.js +33 -0
  18. package/dist/_internal/server/features/orders/cancellation-refund.d.ts +15 -9
  19. package/dist/_internal/server/features/orders/cancellation-refund.js +15 -9
  20. package/dist/_internal/server/features/points/award.js +46 -4
  21. package/dist/_internal/server/features/refunds/actions.js +26 -0
  22. package/dist/_internal/server/features/shipping/courier-block.d.ts +69 -0
  23. package/dist/_internal/server/features/shipping/courier-block.js +239 -0
  24. package/dist/_internal/server/features/site-settings/adapters.d.ts +1 -1
  25. package/dist/_internal/server/features/site-settings/adapters.js +15 -0
  26. package/dist/_internal/server/features/stores/adapters.d.ts +2 -2
  27. package/dist/_internal/server/features/stores/adapters.js +51 -0
  28. package/dist/_internal/server/functions/scheduled.js +38 -1
  29. package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +9 -2
  30. package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +4 -0
  31. package/dist/_internal/server/jobs/core/dailyStatusDigest.js +19 -2
  32. package/dist/_internal/server/jobs/core/index.d.ts +2 -1
  33. package/dist/_internal/server/jobs/core/index.js +2 -1
  34. package/dist/_internal/server/jobs/core/onJobCreated.d.ts +30 -7
  35. package/dist/_internal/server/jobs/core/onJobCreated.js +78 -45
  36. package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +7 -0
  37. package/dist/_internal/server/jobs/core/onOrderStatusChange.js +62 -0
  38. package/dist/_internal/server/jobs/core/paymentReconcile.js +87 -97
  39. package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +33 -0
  40. package/dist/_internal/server/jobs/core/runJobOnce.d.ts +48 -0
  41. package/dist/_internal/server/jobs/core/runJobOnce.js +195 -0
  42. package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +10 -2
  43. package/dist/_internal/server/jobs/handlers/onOrderStatusChange.js +17 -0
  44. package/dist/_internal/server/notifications/channel-health.d.ts +26 -3
  45. package/dist/_internal/shared/actions/action-registry.js +177 -9
  46. package/dist/_internal/shared/checkout/coupon-discount.d.ts +43 -1
  47. package/dist/_internal/shared/checkout/coupon-discount.js +26 -1
  48. package/dist/_internal/shared/checkout/order-math.d.ts +145 -0
  49. package/dist/_internal/shared/checkout/order-math.js +173 -0
  50. package/dist/_internal/shared/checkout/refundable-base.d.ts +25 -0
  51. package/dist/_internal/shared/checkout/refundable-base.js +13 -1
  52. package/dist/_internal/shared/checkout/split.d.ts +87 -0
  53. package/dist/_internal/shared/checkout/split.js +100 -0
  54. package/dist/_internal/shared/content/disclaimers.d.ts +88 -0
  55. package/dist/_internal/shared/content/disclaimers.js +217 -0
  56. package/dist/_internal/shared/content/published-values.d.ts +88 -0
  57. package/dist/_internal/shared/content/published-values.js +198 -0
  58. package/dist/_internal/shared/features/admin/integrations.d.ts +109 -0
  59. package/dist/_internal/shared/features/admin/integrations.js +253 -0
  60. package/dist/_internal/shared/features/orders/dispute-reasons.d.ts +113 -0
  61. package/dist/_internal/shared/features/orders/dispute-reasons.js +181 -0
  62. package/dist/_internal/shared/features/orders/refund-copy.d.ts +1 -1
  63. package/dist/_internal/shared/features/orders/refund-copy.js +18 -1
  64. package/dist/_internal/shared/features/points/accepts.d.ts +36 -0
  65. package/dist/_internal/shared/features/points/accepts.js +43 -0
  66. package/dist/_internal/shared/features/shipping/shared-purchase.d.ts +91 -0
  67. package/dist/_internal/shared/features/shipping/shared-purchase.js +108 -0
  68. package/dist/_internal/shared/features/site-settings/types.d.ts +11 -0
  69. package/dist/_internal/shared/fees/calculator.d.ts +33 -1
  70. package/dist/_internal/shared/fees/calculator.js +32 -2
  71. package/dist/_internal/shared/media/limits.d.ts +10 -0
  72. package/dist/_internal/shared/media/limits.js +10 -0
  73. package/dist/_internal/shared/types/action-result.js +15 -1
  74. package/dist/client/api/surface-error.js +16 -2
  75. package/dist/client/api/useApiMutation.js +17 -1
  76. package/dist/client.d.ts +12 -1
  77. package/dist/client.js +31 -1
  78. package/dist/constants/api-endpoints.d.ts +45 -0
  79. package/dist/constants/api-endpoints.js +15 -0
  80. package/dist/constants/field-names.d.ts +18 -0
  81. package/dist/constants/field-names.js +28 -0
  82. package/dist/contracts/index.d.ts +1 -1
  83. package/dist/contracts/shipping.d.ts +45 -0
  84. package/dist/contracts/shipping.js +15 -0
  85. package/dist/core/server-action.js +19 -3
  86. package/dist/errors/error-mapping.js +26 -1
  87. package/dist/features/about/components/AboutView.js +1 -1
  88. package/dist/features/account/components/BuyerAuctionsGuideView.js +4 -1
  89. package/dist/features/account/components/UserOffersPanel.js +5 -3
  90. package/dist/features/account/components/UserOrdersView.js +19 -33
  91. package/dist/features/admin/components/AdminActionIndexView.js +100 -5
  92. package/dist/features/admin/components/AdminAddressClustersView.js +21 -2
  93. package/dist/features/admin/components/AdminBlogEditorView.js +8 -8
  94. package/dist/features/admin/components/AdminCarouselEditorView.js +1 -1
  95. package/dist/features/admin/components/AdminCarouselView.js +96 -4
  96. package/dist/features/admin/components/AdminCouponEditorView.js +17 -0
  97. package/dist/features/admin/components/AdminFulfillmentView.js +3 -2
  98. package/dist/features/admin/components/AdminInvoicingView.d.ts +2 -0
  99. package/dist/features/admin/components/AdminInvoicingView.js +65 -0
  100. package/dist/features/admin/components/AdminMediaView.js +36 -3
  101. package/dist/features/admin/components/AdminNavigationView.js +4 -1
  102. package/dist/features/admin/components/AdminOffersView.js +2 -1
  103. package/dist/features/admin/components/AdminOrderEditorView.d.ts +18 -1
  104. package/dist/features/admin/components/AdminOrderEditorView.js +11 -2
  105. package/dist/features/admin/components/AdminOrdersGuideView.js +23 -2
  106. package/dist/features/admin/components/AdminOrdersView.js +67 -5
  107. package/dist/features/admin/components/AdminPaymentClustersView.js +19 -2
  108. package/dist/features/admin/components/AdminProductEditorView.js +2 -2
  109. package/dist/features/admin/components/AdminSectionsView.d.ts +10 -0
  110. package/dist/features/admin/components/AdminSectionsView.js +486 -224
  111. package/dist/features/admin/components/OwnerQuickActions.js +24 -2
  112. package/dist/features/admin/components/ReferenceRecordEditor.js +1 -1
  113. package/dist/features/admin/constants/filter-tabs.d.ts +6 -0
  114. package/dist/features/admin/constants/filter-tabs.js +6 -0
  115. package/dist/features/admin/constants/site-settings-tabs.d.ts +1 -1
  116. package/dist/features/admin/hooks/useAdminListingData.js +16 -0
  117. package/dist/features/admin/hooks/useOptimisticRowFlag.d.ts +33 -0
  118. package/dist/features/admin/hooks/useOptimisticRowFlag.js +87 -0
  119. package/dist/features/admin/repository/notification.repository.d.ts +15 -0
  120. package/dist/features/admin/repository/notification.repository.js +32 -0
  121. package/dist/features/admin/schemas/action-index-form.d.ts +34 -0
  122. package/dist/features/admin/schemas/action-index-form.js +115 -0
  123. package/dist/features/admin/schemas/admin-user-form.d.ts +2 -2
  124. package/dist/features/admin/schemas/firestore.d.ts +30 -0
  125. package/dist/features/admin/schemas/firestore.js +5 -0
  126. package/dist/features/audit-log/schemas/firestore.d.ts +30 -0
  127. package/dist/features/audit-log/schemas/firestore.js +15 -0
  128. package/dist/features/auth/components/RegisterForm.js +2 -1
  129. package/dist/features/auth/permissions/constants.js +13 -0
  130. package/dist/features/cart/components/CartPriceBreakdown.d.ts +13 -0
  131. package/dist/features/cart/components/CartPriceBreakdown.js +6 -2
  132. package/dist/features/cart/components/PointsTenderPicker.d.ts +61 -0
  133. package/dist/features/cart/components/PointsTenderPicker.js +15 -0
  134. package/dist/features/cart/components/StoreAddonsPicker.js +2 -1
  135. package/dist/features/cart/components/index.d.ts +2 -0
  136. package/dist/features/cart/components/index.js +1 -0
  137. package/dist/features/cart/repository/cart.repository.d.ts +19 -0
  138. package/dist/features/cart/repository/cart.repository.js +27 -0
  139. package/dist/features/cart/schemas/firestore.d.ts +92 -0
  140. package/dist/features/catalogue/components/CatalogueItemEditorView.js +3 -3
  141. package/dist/features/contact/email.d.ts +27 -10
  142. package/dist/features/contact/email.js +20 -3
  143. package/dist/features/dispute-reasons/repository/dispute-reasons.repository.d.ts +38 -0
  144. package/dist/features/dispute-reasons/repository/dispute-reasons.repository.js +80 -0
  145. package/dist/features/dispute-reasons/schemas/firestore.d.ts +64 -0
  146. package/dist/features/dispute-reasons/schemas/firestore.js +40 -0
  147. package/dist/features/events/components/AdminEventEditorView.js +8 -6
  148. package/dist/features/faq/components/FAQAccordion.d.ts +13 -1
  149. package/dist/features/faq/components/FAQAccordion.js +29 -4
  150. package/dist/features/invoicing/schemas/firestore.d.ts +112 -0
  151. package/dist/features/invoicing/schemas/firestore.js +45 -0
  152. package/dist/features/invoicing/utils/financial-year.d.ts +43 -0
  153. package/dist/features/invoicing/utils/financial-year.js +53 -0
  154. package/dist/features/jobs/actions/enqueue-job.js +18 -1
  155. package/dist/features/jobs/repository/jobs.repository.d.ts +62 -1
  156. package/dist/features/jobs/repository/jobs.repository.js +84 -1
  157. package/dist/features/jobs/schemas/firestore.d.ts +80 -0
  158. package/dist/features/jobs/schemas/firestore.js +37 -0
  159. package/dist/features/layout/hooks/useFormBottomActions.js +20 -1
  160. package/dist/features/lottery/schemas/zod.d.ts +6 -6
  161. package/dist/features/media/MediaImage.js +22 -1
  162. package/dist/features/media/upload/ImageUpload.js +1 -1
  163. package/dist/features/obligations/constants/policies.js +24 -1
  164. package/dist/features/orders/components/EmiInstallmentsPanel.js +25 -7
  165. package/dist/features/orders/components/OrderPaymentSummary.js +10 -1
  166. package/dist/features/orders/components/OrderProvenanceCard.d.ts +8 -0
  167. package/dist/features/orders/components/OrderProvenanceCard.js +185 -0
  168. package/dist/features/orders/components/RaiseDisputeForm.d.ts +14 -0
  169. package/dist/features/orders/components/RaiseDisputeForm.js +111 -0
  170. package/dist/features/orders/components/RefundRequestView.js +22 -4
  171. package/dist/features/orders/components/index.d.ts +4 -0
  172. package/dist/features/orders/components/index.js +2 -0
  173. package/dist/features/orders/constants/order-lane-tabs.d.ts +69 -0
  174. package/dist/features/orders/constants/order-lane-tabs.js +88 -0
  175. package/dist/features/orders/repository/orders.repository.d.ts +57 -0
  176. package/dist/features/orders/repository/orders.repository.js +145 -0
  177. package/dist/features/orders/schemas/firestore.d.ts +196 -1
  178. package/dist/features/orders/schemas/index.d.ts +60 -12
  179. package/dist/features/orders/schemas/index.js +12 -0
  180. package/dist/features/orders/types/index.d.ts +26 -0
  181. package/dist/features/orders/utils/courier-block.d.ts +25 -0
  182. package/dist/features/orders/utils/courier-block.js +23 -0
  183. package/dist/features/payment-cases/schemas/firestore.d.ts +26 -1
  184. package/dist/features/payment-cases/schemas/firestore.js +1 -0
  185. package/dist/features/products/components/GroupMemberPicker.js +4 -1
  186. package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -2
  187. package/dist/features/products/components/PrizeDrawEntryActions.js +2 -1
  188. package/dist/features/products/components/ProductDetailActions.js +2 -1
  189. package/dist/features/products/components/ProductDetailPageView.d.ts +17 -1
  190. package/dist/features/products/components/ProductDetailPageView.js +2 -2
  191. package/dist/features/products/schemas/product-features.validators.d.ts +10 -10
  192. package/dist/features/promotions/actions/coupon-stacking.d.ts +30 -3
  193. package/dist/features/promotions/actions/coupon-stacking.js +21 -2
  194. package/dist/features/promotions/components/CouponCard.js +13 -0
  195. package/dist/features/promotions/constants/coupon-help.d.ts +2 -2
  196. package/dist/features/promotions/constants/coupon-help.js +9 -1
  197. package/dist/features/promotions/schemas/firestore.d.ts +24 -0
  198. package/dist/features/promotions/schemas/firestore.js +4 -0
  199. package/dist/features/promotions/types/index.d.ts +19 -1
  200. package/dist/features/scams/components/ScamProfileView.js +2 -2
  201. package/dist/features/scams/components/ScamRegistryView.js +2 -2
  202. package/dist/features/search/action-index/tab-entries.js +1 -1
  203. package/dist/features/seller/actions/seller-actions.js +33 -3
  204. package/dist/features/seller/components/FulfillmentView.js +3 -2
  205. package/dist/features/seller/components/SellerAddressesView.js +32 -4
  206. package/dist/features/seller/components/SellerAnalyticsAlertsView.js +62 -3
  207. package/dist/features/seller/components/SellerBundlesView.js +53 -14
  208. package/dist/features/seller/components/SellerGroupedListingsView.js +23 -3
  209. package/dist/features/seller/components/SellerListingTypeView.js +56 -10
  210. package/dist/features/seller/components/SellerOrdersView.js +129 -27
  211. package/dist/features/seller/components/SellerPayoutMethodsView.js +33 -1
  212. package/dist/features/seller/components/SellerPayoutSettingsView.js +48 -9
  213. package/dist/features/seller/components/SellerProductsView.js +5 -1
  214. package/dist/features/seller/components/SellerShippingConfigsView.js +33 -1
  215. package/dist/features/seller/components/SellerShippingView.js +2 -1
  216. package/dist/features/seller/components/SellerStoreCategoriesView.js +33 -1
  217. package/dist/features/seller/components/SellerSupportView.js +69 -2
  218. package/dist/features/seller/hooks/useSellerListingData.js +25 -0
  219. package/dist/features/shell/SectionForm.js +20 -16
  220. package/dist/features/shell/build-sections.js +14 -1
  221. package/dist/features/shipments/components/AdminShipmentLotItemsView.js +54 -1
  222. package/dist/features/shipments/components/AdminShipmentProjectionsView.js +3 -2
  223. package/dist/features/shipments/schemas/validation.d.ts +4 -4
  224. package/dist/features/shipping-boxes/repository/shipping-boxes.repository.d.ts +43 -0
  225. package/dist/features/shipping-boxes/repository/shipping-boxes.repository.js +90 -0
  226. package/dist/features/shipping-boxes/schemas/firestore.d.ts +82 -0
  227. package/dist/features/shipping-boxes/schemas/firestore.js +53 -0
  228. package/dist/features/sticker-trace/components/StickerCommitPanel.js +2 -1
  229. package/dist/features/sticker-trace/components/StickerPrintPanel.js +2 -1
  230. package/dist/features/sticker-trace/components/StickerRetryPanel.js +24 -4
  231. package/dist/features/sticker-trace/components/StickerTraceStudio.js +2 -1
  232. package/dist/features/store-extensions/schemas/report-create-form.d.ts +2 -2
  233. package/dist/features/store-extensions/schemas/shipping-config-form.d.ts +2 -2
  234. package/dist/features/stores/components/StoreOrdersGuideView.js +6 -1
  235. package/dist/features/stores/schemas/firestore.d.ts +71 -0
  236. package/dist/features/stores/types/index.d.ts +19 -0
  237. package/dist/features/support/schemas/index.d.ts +6 -6
  238. package/dist/features/tester/components/AdminTesterFeedbackIssuesView.js +3 -2
  239. package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
  240. package/dist/index.d.ts +11 -2
  241. package/dist/index.js +17 -2
  242. package/dist/next/routing/route-map.d.ts +24 -0
  243. package/dist/next/routing/route-map.js +19 -0
  244. package/dist/providers/shipping-shiprocket/index.d.ts +27 -1
  245. package/dist/providers/shipping-shiprocket/index.js +84 -1
  246. package/dist/schemas/registry.d.ts +51 -22
  247. package/dist/schemas/sieve.d.ts +5 -5
  248. package/dist/server-entry.d.ts +2 -2
  249. package/dist/server-entry.js +8 -1
  250. package/dist/server.d.ts +11 -2
  251. package/dist/server.js +40 -2
  252. package/dist/styles.css +64 -80
  253. package/dist/tailwind-utilities.css +1 -1
  254. package/dist/tokens/themes/default-dark.js +1 -0
  255. package/dist/tokens/themes/default-light.js +1 -0
  256. package/dist/tokens/themes/required.d.ts +1 -1
  257. package/dist/tokens/themes/required.js +1 -0
  258. package/dist/tokens/tokens.css +15 -0
  259. package/dist/ui/components/Checkbox.js +10 -2
  260. package/dist/ui/components/DateInput.js +8 -1
  261. package/dist/ui/components/Disclaimer.d.ts +19 -0
  262. package/dist/ui/components/Disclaimer.js +74 -0
  263. package/dist/ui/components/Input.js +22 -2
  264. package/dist/ui/components/PaginatedSelect.d.ts +8 -19
  265. package/dist/ui/components/PaginatedSelect.js +43 -9
  266. package/dist/ui/components/Radio.js +8 -1
  267. package/dist/ui/components/Select.js +10 -2
  268. package/dist/ui/components/TagInput.d.ts +8 -1
  269. package/dist/ui/components/TagInput.js +4 -3
  270. package/dist/ui/components/Textarea.js +10 -2
  271. package/dist/ui/components/tabs-overflow.js +64 -11
  272. package/dist/ui/forms/FieldCheckbox.js +1 -1
  273. package/dist/ui/forms/FormErrorList.d.ts +0 -16
  274. package/dist/ui/forms/FormErrorList.js +34 -1
  275. package/dist/ui/forms/apply-zod-issues.d.ts +19 -1
  276. package/dist/ui/forms/apply-zod-issues.js +23 -1
  277. package/dist/ui/index.d.ts +2 -0
  278. package/dist/ui/index.js +6 -0
  279. package/dist/ui/rich-text/RichText.style.css +48 -79
  280. package/package.json +1 -1
  281. package/scripts/seed-cli.mjs +1831 -1822
@@ -1,11 +1,12 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import React from "react";
4
- import { Alert, Button, Div, Grid, Input, Row, Select, Stack, StackedViewShell, Text, useToast } from "../../../ui/index.js";
4
+ import { Alert, Button, ConfirmDeleteModal, Div, Grid, Input, Row, Select, Stack, StackedViewShell, Text, TextLink, useToast } from "../../../ui/index.js";
5
5
  import { normalizeError } from "../../../errors/normalize.js";
6
6
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry.js";
7
7
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints.js";
8
8
  import { MediaImage, MediaUploadField, MediaUploadList, useMediaCleanup, useMediaUpload, } from "../../media/index.js";
9
+ import { toUserMessage } from "../../../errors/error-display-map.js";
9
10
  const __P = {
10
11
  p4: "p-[var(--appkit-space-4)]",
11
12
  };
@@ -28,6 +29,9 @@ function MediaBrowser({ onCopy }) {
28
29
  const [nextPageToken, setNextPageToken] = React.useState(null);
29
30
  const [isLoading, setIsLoading] = React.useState(false);
30
31
  const [error, setError] = React.useState(null);
32
+ const [deleteTarget, setDeleteTarget] = React.useState(null);
33
+ const [isDeleting, setIsDeleting] = React.useState(false);
34
+ const toast = useToast();
31
35
  const load = React.useCallback(async (token) => {
32
36
  setIsLoading(true);
33
37
  setError(null);
@@ -54,6 +58,33 @@ function MediaBrowser({ onCopy }) {
54
58
  setIsLoading(false);
55
59
  }
56
60
  }, [prefix]);
61
+ const onDelete = React.useCallback((file) => setDeleteTarget(file), []);
62
+ const confirmDelete = React.useCallback(async () => {
63
+ if (!deleteTarget)
64
+ return;
65
+ setIsDeleting(true);
66
+ try {
67
+ const res = await fetch(`${ADMIN_ENDPOINTS.MEDIA_LIST}?path=${encodeURIComponent(deleteTarget.name)}`, { method: "DELETE", credentials: "include" });
68
+ if (!res.ok)
69
+ throw new Error("Failed to delete file");
70
+ /*
71
+ * Drop it from local state rather than refetching: this list is
72
+ * token-paginated and accumulates pages, so a reload would discard
73
+ * every page past the first and silently scroll the admin back to the
74
+ * top of a library they were partway through.
75
+ */
76
+ setFiles((prev) => prev.filter((f) => f.name !== deleteTarget.name));
77
+ toast.showToast("File deleted.", "success");
78
+ }
79
+ catch (err) {
80
+ const normalized = normalizeError(err);
81
+ toast.showToast(toUserMessage(normalized.code, undefined, { fallback: "Failed to delete file." }), "error");
82
+ }
83
+ finally {
84
+ setIsDeleting(false);
85
+ setDeleteTarget(null);
86
+ }
87
+ }, [deleteTarget, toast]);
57
88
  React.useEffect(() => {
58
89
  void load(null);
59
90
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -66,8 +97,10 @@ function MediaBrowser({ onCopy }) {
66
97
  }, [files, search]);
67
98
  return (_jsxs(Stack, { className: `${__P.p4}`, gap: "3", rounded: "xl", surface: "default", border: "default", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "primary", children: "Browse existing media" }), _jsxs(Row, { align: "center", gap: "sm", wrap: true, children: [_jsx(Select, { value: prefix, onChange: (e) => setPrefix(e.target.value), options: PREFIX_OPTIONS, "aria-label": "Prefix filter", wrapperClassName: "min-w-[140px]" }), _jsx(Input, { type: "text", placeholder: "Search filename\u2026", value: search, onChange: (e) => setSearch(e.target.value), className: "flex-1 min-w-[160px]" })] }), error && (_jsx(Alert, { variant: "error", title: "Load failed", children: error })), _jsxs(Grid, { cols: "navTiles", gap: "sm", children: [filtered.map((f) => {
68
99
  const isImage = (f.contentType ?? "").startsWith("image/");
69
- return (_jsxs(Div, { className: "group overflow-hidden", surface: "muted", rounded: "lg", border: "default", children: [_jsx(Row, { color: "muted", textSize: "xs", className: "relative aspect-square", surface: "subtle", align: "center", justify: "center", children: isImage ? (_jsx(MediaImage, { src: f.downloadURL, alt: f.name, size: "thumbnail" })) : (_jsx(Text, { align: "center", paddingX: "x-xs", className: "break-all", children: f.contentType ?? "file" })) }), _jsxs(Div, { className: "p-[0.375rem]", children: [_jsx(Text, { className: "truncate text-[10px] font-mono", color: "muted", children: f.name.split("/").pop() }), _jsx(Button, { type: "button", variant: "ghost", textSize: "xs", className: "mt-1 w-full", onClick: () => onCopy(f.downloadURL), children: ACTIONS.MEDIA["copy-url"].label })] })] }, f.name));
70
- }), filtered.length === 0 && !isLoading && (_jsx(Text, { paddingY: "lg", className: "col-span-full", color: "muted", size: "sm", align: "center", children: "No files found." }))] }), _jsxs(Row, { align: "center", justify: "between", children: [_jsxs(Text, { size: "xs", color: "muted", children: [filtered.length, " file(s)", nextPageToken ? " · more available" : ""] }), nextPageToken && (_jsx(Button, { type: "button", variant: "outline", onClick: () => void load(nextPageToken), disabled: isLoading, children: isLoading ? "Loading…" : "Load more" }))] })] }));
100
+ return (_jsxs(Div, { className: "group overflow-hidden", surface: "muted", rounded: "lg", border: "default", children: [_jsx(Row, { color: "muted", textSize: "xs", className: "relative aspect-square", surface: "subtle", align: "center", justify: "center", children: isImage ? (_jsx(MediaImage, { src: f.downloadURL, alt: f.name, size: "thumbnail" })) : (_jsx(Text, { align: "center", paddingX: "x-xs", className: "break-all", children: f.contentType ?? "file" })) }), _jsxs(Div, { className: "p-[0.375rem]", children: [_jsx(TextLink, { href: f.downloadURL, target: "_blank", rel: "noopener noreferrer", title: f.name, children: _jsx(Text, { className: "truncate text-[10px] font-mono", color: "muted", children: f.name.split("/").pop() }) }), _jsxs(Row, { gap: "xs", className: "mt-1", children: [_jsx(Button, { type: "button", variant: "ghost", textSize: "xs", className: "flex-1", onClick: () => onCopy(f.downloadURL), children: ACTIONS.MEDIA["copy-url"].label }), _jsx(Button, { type: "button", variant: "ghost", textSize: "xs", "aria-label": `${ACTIONS.MEDIA["delete-media"].ariaLabel}: ${f.name}`, onClick: () => onDelete(f), children: ACTIONS.MEDIA["delete-media"].label })] })] })] }, f.name));
101
+ }), filtered.length === 0 && !isLoading && (_jsx(Text, { paddingY: "lg", className: "col-span-full", color: "muted", size: "sm", align: "center", children: "No files found." }))] }), deleteTarget && (_jsx(ConfirmDeleteModal, { isOpen: true,
102
+ /* Rule #7: the copy lives on the ActionDef, not here. */
103
+ title: ACTIONS.MEDIA["delete-media"].confirmation?.title, message: `${deleteTarget.name}\n\n${ACTIONS.MEDIA["delete-media"].confirmation?.body ?? ""}`, confirmText: ACTIONS.MEDIA["delete-media"].confirmation?.confirmLabel, isDeleting: isDeleting, onConfirm: () => void confirmDelete(), onClose: () => setDeleteTarget(null) })), _jsxs(Row, { align: "center", justify: "between", children: [_jsxs(Text, { size: "xs", color: "muted", children: [filtered.length, " file(s)", nextPageToken ? " · more available" : ""] }), nextPageToken && (_jsx(Button, { type: "button", variant: "outline", onClick: () => void load(nextPageToken), disabled: isLoading, children: isLoading ? "Loading…" : "Load more" }))] })] }));
71
104
  }
72
105
  function MediaUploaderPanel({ onUpload, isUploadPending, isCleanupPending, heroAssetUrl, setHeroAssetUrl, galleryAssets, setGalleryAssets, stagedUrls, setHeroStagedUrls, setGalleryStagedUrls, handleAbort, copiedUrl, onCopy, onClearPreviews, onDiscardStaged, }) {
73
106
  return (_jsxs(Stack, { surface: "default", rounded: "xl", padding: "md", border: "default", gap: "5", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "primary", children: "Upload & Copy URL" }), _jsx(MediaUploadField, { label: "Primary media asset", value: heroAssetUrl, onChange: setHeroAssetUrl, onUpload: onUpload, helperText: "Uploads via signed URL (sign \u2192 PUT \u2192 finalize) and previews the returned URL.", onAbort: handleAbort, onStagedUrlsChange: setHeroStagedUrls }), heroAssetUrl && (_jsxs(Row, { surface: "muted", padding: "inlineSm", align: "center", gap: "sm", rounded: "lg", border: "default", children: [_jsx(Text, { className: "flex-1 truncate font-mono", color: "muted", size: "xs", children: heroAssetUrl }), _jsx(Button, { type: "button", variant: "outline", onClick: () => onCopy(heroAssetUrl), children: copiedUrl === heroAssetUrl ? "Copied!" : ACTIONS.MEDIA["copy-url"].label })] })), _jsx(MediaUploadList, { label: "Gallery assets", value: galleryAssets, onChange: setGalleryAssets, onUpload: onUpload, helperText: "Attach multiple images or videos for batch checks.", onAbort: handleAbort, onStagedUrlsChange: setGalleryStagedUrls, maxItems: 12 }), galleryAssets.length > 0 && (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", weight: "medium", color: "muted", children: "Gallery URLs" }), galleryAssets.map((asset, i) => (_jsxs(Row, { paddingY: "y-2xs", padding: "x-xs", surface: "muted", rounded: "default", align: "center", gap: "sm", border: "default", children: [_jsx(Text, { className: "flex-1 truncate font-mono", color: "muted", size: "xs", children: asset.url }), _jsx(Button, { type: "button", variant: "ghost", onClick: () => onCopy(asset.url), children: copiedUrl === asset.url ? "Copied!" : "Copy" })] }, i)))] })), _jsxs(Row, { align: "center", gap: "sm", wrap: true, children: [_jsx(Button, { type: "button", variant: "outline", onClick: onClearPreviews, disabled: isUploadPending || isCleanupPending, children: ACTIONS.MEDIA["clear-previews"].label }), _jsx(Button, { type: "button", variant: "outline", onClick: onDiscardStaged, disabled: isUploadPending || isCleanupPending || stagedUrls.length === 0, children: isCleanupPending ? "Discarding…" : ACTIONS.MEDIA["discard-staged"].label }), _jsxs(Text, { size: "xs", color: "muted", children: [stagedUrls.length, " staged upload(s)"] })] })] }));
@@ -8,11 +8,14 @@ import { apiClient } from "../../../http/index.js";
8
8
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints.js";
9
9
  import { AdminNavEditorView } from "./AdminNavEditorView.js";
10
10
  import { ROW_ACTION_META, ROW_ACTION_ID } from "../../../features/products/constants/action-defs.js";
11
+ import { ACTIONS } from "../../../_internal/shared/actions/action-registry.js";
11
12
  const __O = {
12
13
  hidden: "overflow-hidden",
13
14
  };
14
15
  function NavItemRow({ item, idx, total, reorderPending, onMoveUp, onMoveDown, onVisibilityChange, onEdit, onDelete, }) {
15
- return (_jsxs(Row, { surface: "default", padding: "inline", align: "center", gap: "3", children: [_jsxs(Stack, { className: "shrink-0 gap-[0.125rem]", children: [_jsx(Button, { variant: "ghost", type: "button", onClick: () => onMoveUp(idx), disabled: idx === 0 || reorderPending, className: "text-zinc-400 hover:text-[var(--appkit-color-text)] disabled:opacity-30 leading-none text-[length:var(--appkit-text-xs)] p-[var(--appkit-space-0)] min-h-0 h-auto rounded-none", "aria-label": "Move up", children: "\u25B2" }), _jsx(Button, { variant: "ghost", type: "button", onClick: () => onMoveDown(idx), disabled: idx >= total - 1 || reorderPending, className: "text-zinc-400 hover:text-[var(--appkit-color-text)] disabled:opacity-30 leading-none text-[length:var(--appkit-text-xs)] p-[var(--appkit-space-0)] min-h-0 h-auto rounded-none", "aria-label": "Move down", children: "\u25BC" })] }), _jsxs(Div, { className: "flex-1 min-w-0", children: [_jsxs(Text, { className: "truncate", color: "primary", size: "sm", weight: "medium", children: [item.parentId ? _jsx(Span, { className: "mr-1", color: "faint", children: "\u21B3" }) : null, item.label] }), _jsx(Text, { className: "truncate", color: "muted", size: "xs", children: item.href })] }), _jsx(Toggle, { checked: item.isVisible ?? true, onChange: (val) => onVisibilityChange(item.id, val), label: "" }), _jsx(RowActionMenu, { actions: [
16
+ return (_jsxs(Row, { surface: "default", padding: "inline", align: "center", gap: "3", children: [_jsxs(Stack, { className: "shrink-0 gap-[0.125rem]", children: [_jsx(Button, { variant: "ghost", type: "button", onClick: () => onMoveUp(idx), disabled: idx === 0 || reorderPending, className: "text-zinc-400 hover:text-[var(--appkit-color-text)] disabled:opacity-30 leading-none text-[length:var(--appkit-text-xs)] p-[var(--appkit-space-0)] min-h-0 h-auto rounded-none", "aria-label": "Move up", children: "\u25B2" }), _jsx(Button, { variant: "ghost", type: "button", onClick: () => onMoveDown(idx), disabled: idx >= total - 1 || reorderPending, className: "text-zinc-400 hover:text-[var(--appkit-color-text)] disabled:opacity-30 leading-none text-[length:var(--appkit-text-xs)] p-[var(--appkit-space-0)] min-h-0 h-auto rounded-none", "aria-label": "Move down", children: "\u25BC" })] }), _jsxs(Div, { className: "flex-1 min-w-0", children: [_jsxs(Text, { className: "truncate", color: "primary", size: "sm", weight: "medium", children: [item.parentId ? _jsx(Span, { className: "mr-1", color: "faint", children: "\u21B3" }) : null, item.label] }), _jsx(Text, { className: "truncate", color: "muted", size: "xs", children: item.href })] }), _jsx(Toggle, { checked: item.isVisible ?? true, onChange: (val) => onVisibilityChange(item.id, val), ariaLabel: (item.isVisible ?? true)
17
+ ? `${ACTIONS.ADMIN["hide-nav-item"].ariaLabel}: ${item.label}`
18
+ : `${ACTIONS.ADMIN["show-nav-item"].ariaLabel}: ${item.label}` }), _jsx(RowActionMenu, { actions: [
16
19
  { label: ROW_ACTION_META[ROW_ACTION_ID.EDIT].label, onClick: () => onEdit(item) },
17
20
  { label: ROW_ACTION_META[ROW_ACTION_ID.DELETE].label, destructive: true, onClick: () => onDelete(item) },
18
21
  ] })] }));
@@ -47,6 +47,7 @@ import { toRecordArray, toRelativeDate, toCurrency, toStringValue, } from "../ho
47
47
  import { DataListingView } from "./DataListingView.js";
48
48
  import { apiClient } from "../../../http/index.js";
49
49
  import { normalizeError } from "../../../errors/normalize.js";
50
+ import { toUserMessage } from "../../../errors/error-display-map.js";
50
51
  /** Terminal states — an offer here has nothing left to cancel. */
51
52
  const TERMINAL_STATUSES = new Set(["paid", "declined", "expired", "withdrawn"]);
52
53
  export function AdminOffersView({ children, ...props }) {
@@ -79,7 +80,7 @@ export function AdminOffersView({ children, ...props }) {
79
80
  // The row's own data is already on screen, so this degrades to "no
80
81
  // chain" rather than to an empty modal. Say so instead of failing silently.
81
82
  const normalized = normalizeError(err);
82
- showToast(normalized.message || "Couldn't load the full offer history.", "error");
83
+ showToast(toUserMessage(normalized.code, undefined, { fallback: "Couldn't load the full offer history." }), "error");
83
84
  }
84
85
  };
85
86
  const cancelMutation = useApiMutation({
@@ -1,4 +1,5 @@
1
1
  import { type OrderAddonBadgesOrder } from "../../orders/components/OrderAddonBadges";
2
+ import type { OrderSourceContext } from "../../orders/schemas/firestore";
2
3
  import React from "react";
3
4
  export interface AdminOrderItemRow {
4
5
  productId: string;
@@ -7,6 +8,10 @@ export interface AdminOrderItemRow {
7
8
  quantity: number;
8
9
  unitPrice: number;
9
10
  totalPrice: number;
11
+ groupSlug?: string;
12
+ groupTitle?: string;
13
+ bundleCategorySlug?: string;
14
+ bundleProductIds?: string[];
10
15
  }
11
16
  export interface AdminOrderEditorViewProps {
12
17
  open: boolean;
@@ -36,5 +41,17 @@ export interface AdminOrderEditorViewProps {
36
41
  * coupon is what an admin needs when reconciling a discounted order.
37
42
  */
38
43
  addons?: OrderAddonBadgesOrder;
44
+ /**
45
+ * How the buyer earned this price — a won auction, a buyout, an agreed
46
+ * offer, a pre-order deposit, prize-draw entries.
47
+ *
48
+ * Support is the surface that needs this most: a buyer disputing "I agreed
49
+ * ₹X" is otherwise unanswerable from the admin side, because the negotiated
50
+ * amount lives only in `sourceContext` and nothing rendered it anywhere.
51
+ * `GET /api/admin/orders/[id]` already returns it via `maskedOrder`.
52
+ */
53
+ sourceContext?: OrderSourceContext;
54
+ /** For the provenance card's money formatting; falls back to the default. */
55
+ currency?: string;
39
56
  }
40
- export declare function AdminOrderEditorView({ open, onClose, orderId, orderLabel, currentStatus, items, paymentProofUrl, paymentTransactionId, paymentMethod, paymentStatus, displayedUpiId, buyerReportedUpiId, paymentUpiMismatch, buyerMarkedPaid, buyerFraudAgreementAccepted, paymentReviewOutcome, addons, }: AdminOrderEditorViewProps): React.JSX.Element;
57
+ export declare function AdminOrderEditorView({ open, onClose, orderId, orderLabel, currentStatus, items, sourceContext, currency, paymentProofUrl, paymentTransactionId, paymentMethod, paymentStatus, displayedUpiId, buyerReportedUpiId, paymentUpiMismatch, buyerMarkedPaid, buyerFraudAgreementAccepted, paymentReviewOutcome, addons, }: AdminOrderEditorViewProps): React.JSX.Element;
@@ -1,6 +1,8 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { OrderAddonBadges } from "../../orders/components/OrderAddonBadges.js";
4
+ import { OrderProvenanceCard } from "../../orders/components/OrderProvenanceCard.js";
5
+ import { groupOrderItemsByLine } from "../../orders/utils/bundle-grouping.js";
4
6
  import { isManualPaymentMethod } from "../../orders/constants/payment-window.js";
5
7
  import { useApiMutation } from "@mohasinac/appkit/client";
6
8
  import React, { useState } from "react";
@@ -18,6 +20,13 @@ import { useFormShellState, FormShellContext } from "../../../ui/forms/index.js"
18
20
  import { applyZodIssues } from "../../../ui/forms/apply-zod-issues.js";
19
21
  import { FormErrorSummary } from "../../../ui/forms/FormErrorSummary.js";
20
22
  import { ValidationError } from "../../../errors/validation-error.js";
23
+ /**
24
+ * One item row. Extracted so the single and grouped render paths share exactly
25
+ * one piece of markup rather than two that can drift.
26
+ */
27
+ function adminOrderItemRow(item, key) {
28
+ return (_jsxs(Div, { layout: "flex", align: "center", gap: "3", padding: "sm", children: [_jsx(Div, { className: "h-10 w-10 shrink-0", rounded: "md", overflow: "hidden", children: _jsx(MediaImage, { src: item.image, alt: item.title, size: "thumbnail" }) }), _jsxs(Div, { className: "min-w-0 flex-1", children: [_jsx(Text, { size: "sm", className: "truncate", weight: "medium", children: item.title }), _jsxs(Text, { size: "xs", color: "muted", children: ["Qty: ", item.quantity, " \u00D7 ", toCurrency(item.unitPrice)] })] }), _jsx(Text, { size: "sm", className: "shrink-0", weight: "semibold", children: toCurrency(item.totalPrice) })] }, key));
29
+ }
21
30
  const STATUS_OPTIONS = [
22
31
  { label: "Pending", value: "pending" },
23
32
  { label: "Processing", value: "processing" },
@@ -37,7 +46,7 @@ const CARRIER_OPTIONS = [
37
46
  { label: "Other", value: "Other" },
38
47
  ];
39
48
  // --- Component ---------------------------------------------------------------
40
- export function AdminOrderEditorView({ open, onClose, orderId, orderLabel, currentStatus, items, paymentProofUrl, paymentTransactionId, paymentMethod, paymentStatus, displayedUpiId, buyerReportedUpiId, paymentUpiMismatch, buyerMarkedPaid, buyerFraudAgreementAccepted, paymentReviewOutcome, addons, }) {
49
+ export function AdminOrderEditorView({ open, onClose, orderId, orderLabel, currentStatus, items, sourceContext, currency, paymentProofUrl, paymentTransactionId, paymentMethod, paymentStatus, displayedUpiId, buyerReportedUpiId, paymentUpiMismatch, buyerMarkedPaid, buyerFraudAgreementAccepted, paymentReviewOutcome, addons, }) {
41
50
  const queryClient = useQueryClient();
42
51
  const { showToast } = useToast();
43
52
  const [draft, setDraft] = React.useState({
@@ -207,7 +216,7 @@ export function AdminOrderEditorView({ open, onClose, orderId, orderLabel, curre
207
216
  setIsRejectingFraud(false);
208
217
  }
209
218
  };
210
- return (_jsx(SideDrawer, { isOpen: open, onClose: onClose, title: orderLabel ? `Order: ${orderLabel}` : "Update Order", children: _jsx(FormShellContext.Provider, { value: form.shellCtx, children: _jsxs(Stack, { gap: "md", padding: "md", children: [_jsx(FormErrorSummary, {}), addons && _jsx(OrderAddonBadges, { order: addons, variant: "detail" }), items && items.length > 0 && (_jsxs(Stack, { gap: "xs", children: [_jsxs(Label, { size: "sm", weight: "medium", color: "primary", children: ["Items (", items.length, ")"] }), _jsx(Div, { className: "divide-y divide-[var(--appkit-color-border)] border border-[var(--appkit-color-border)]", rounded: "lg", children: items.map((item, i) => (_jsxs(Div, { layout: "flex", align: "center", gap: "3", padding: "sm", children: [_jsx(Div, { className: "h-10 w-10 shrink-0", rounded: "md", overflow: "hidden", children: _jsx(MediaImage, { src: item.image, alt: item.title, size: "thumbnail" }) }), _jsxs(Div, { className: "min-w-0 flex-1", children: [_jsx(Text, { size: "sm", className: "truncate", weight: "medium", children: item.title }), _jsxs(Text, { size: "xs", color: "muted", children: ["Qty: ", item.quantity, " \u00D7 ", toCurrency(item.unitPrice)] })] }), _jsx(Text, { size: "sm", className: "shrink-0", weight: "semibold", children: toCurrency(item.totalPrice) })] }, item.productId || i))) })] })), _jsx(SectionForm, { sections: sections, values: draft, onChange: (partial) => setDraft((d) => ({ ...d, ...partial })), onSubmit: () => {
219
+ return (_jsx(SideDrawer, { isOpen: open, onClose: onClose, title: orderLabel ? `Order: ${orderLabel}` : "Update Order", children: _jsx(FormShellContext.Provider, { value: form.shellCtx, children: _jsxs(Stack, { gap: "md", padding: "md", children: [_jsx(FormErrorSummary, {}), addons && _jsx(OrderAddonBadges, { order: addons, variant: "detail" }), _jsx(OrderProvenanceCard, { sourceContext: sourceContext, currency: currency }), items && items.length > 0 && (_jsxs(Stack, { gap: "xs", children: [_jsxs(Label, { size: "sm", weight: "medium", color: "primary", children: ["Items (", items.length, ")"] }), _jsx(Div, { className: "divide-y divide-[var(--appkit-color-border)] border border-[var(--appkit-color-border)]", rounded: "lg", children: groupOrderItemsByLine(items).map((group, gi) => group.kind === "single" ? (adminOrderItemRow(group.item, `s-${group.index}`)) : (_jsxs(Div, { children: [_jsxs(Div, { layout: "flex", align: "center", gap: "2", padding: "x-sm", surface: "muted", children: [_jsx(Text, { size: "xs", weight: "semibold", children: group.groupTitle ?? "Grouped purchase" }), _jsx(Text, { size: "xs", color: "muted", children: `${group.memberCount} ${group.memberCount === 1 ? "item" : "items"} · one line` })] }), _jsx(Div, { className: "pl-4", children: group.items.map(({ item, index }) => adminOrderItemRow(item, `m-${index}`)) })] }, `g-${gi}`))) })] })), _jsx(SectionForm, { sections: sections, values: draft, onChange: (partial) => setDraft((d) => ({ ...d, ...partial })), onSubmit: () => {
211
220
  // SectionForm surfaces errors and then submits regardless, so the
212
221
  // guard is here.
213
222
  form.clearErrors();
@@ -2,6 +2,16 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { ShoppingBag, Hash, Scale, Wallet, RotateCcw, DollarSign, Gavel } from "lucide-react";
3
3
  import { Code, Div, Heading, Li, Row, Section, Span, Stack, Text, Ul } from "../../../ui/index.js";
4
4
  import { GC } from "../../_guide-cls.js";
5
+ import { resolvePublishedValues } from "../../../_internal/shared/content/published-values.js";
6
+ /*
7
+ * Phase 9 — read from the published-value registry rather than restated.
8
+ *
9
+ * 🛑 No settings argument, deliberately: this is the OBLIGATION-derived window
10
+ * and it has no settings override, so passing settings would imply an
11
+ * admin-editable number that does not exist (the 18-dead-settings pattern,
12
+ * from the "control that appears to do something the code ignores" direction).
13
+ */
14
+ const { returnRespondHours: RETURN_RESPOND_HOURS, refundBusinessDaysMin: REFUND_DAYS_MIN, refundBusinessDaysMax: REFUND_DAYS_MAX, } = resolvePublishedValues();
5
15
  export function AdminOrdersGuideView() {
6
16
  return (_jsxs(Stack, { className: "max-w-3xl mx-auto", padding: "b-2xl", gap: "xl", children: [_jsxs(Section, { children: [_jsxs(Row, { className: "mb-2", align: "center", gap: "3", children: [_jsx(Row, { className: "flex-shrink-0 w-10 h-10 [background:linear-gradient(135deg,var(--appkit-color-primary-700)_0%,var(--appkit-color-cobalt)_100%)]", align: "center", justify: "center", rounded: "xl", children: _jsx(ShoppingBag, { className: "w-5 h-5 text-white" }) }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)] tracking-widest", size: "sm", weight: "semibold", transform: "uppercase", children: "Admin Guide" })] }), _jsx(Heading, { level: 1, className: "text-[var(--appkit-color-text)] mb-2", mdSize: "3xl", size: "2xl", weight: "bold", children: "Orders & Finance" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: "Order statuses, payouts, disputes, returns, and commission math on LetItRip." })] }), [
7
17
  {
@@ -11,7 +21,18 @@ export function AdminOrdersGuideView() {
11
21
  ["PROCESSING", "Seller has acknowledged and is packing."],
12
22
  ["SHIPPED", "Dispatched. Tracking number provided by seller."],
13
23
  ["DELIVERED", "Carrier confirmed delivery."],
14
- ["RETURN_REQUESTED", "Buyer opened a return. Seller has 3 days to respond."],
24
+ /*
25
+ * 🛑 Phase 9, decision 23 — this said "3 days" while the FAQ
26
+ * said 48 hours, and the FAQ WINS: it is the buyer-facing
27
+ * promise and the one a buyer has already read. The number now
28
+ * comes from `OBLIGATION_POLICIES["return-respond"]`, which is
29
+ * what actually closes the window — so a staff-facing guide can
30
+ * no longer quietly contradict what the buyer was told.
31
+ */
32
+ [
33
+ "RETURN_REQUESTED",
34
+ `Buyer opened a return. Seller has ${RETURN_RESPOND_HOURS} hours to respond.`,
35
+ ],
15
36
  ["REFUNDED", "Return accepted and refund issued via Razorpay."],
16
37
  ["CANCELLED", "Cancelled before shipping. Payment returned."],
17
38
  ].map(([status, note]) => (_jsxs(Row, { gap: "3", children: [_jsx(Text, { className: "flex-shrink-0 font-mono text-[var(--appkit-color-primary)] w-40", size: "xs", weight: "semibold", children: status }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: note })] }, status))), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)] pt-[0.5rem]", size: "sm", children: "Admin-only transitions: force-cancel (any status before DELIVERED), force-refund (post-DELIVERED dispute)." })] })),
@@ -30,7 +51,7 @@ export function AdminOrdersGuideView() {
30
51
  },
31
52
  {
32
53
  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(Span, { weight: "bold", 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." })] })),
54
+ 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", 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."] }), _jsxs(Li, { children: ["After admin override: the refund is issued automatically (", REFUND_DAYS_MIN, "\u2013", REFUND_DAYS_MAX, " business days for card, 1\u20132 for UPI). Seller payout for that order is withheld."] })] })),
34
55
  },
35
56
  {
36
57
  Icon: DollarSign, title: "Commission & Settlement Math",
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { groupOrderItemsByLine } from "../../orders/utils/bundle-grouping.js";
3
4
  import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit/client";
4
5
  import { sortBy } from "@mohasinac/appkit/client";
5
6
  import React, { useState, useCallback } from "react";
@@ -61,14 +62,70 @@ function toOrderItemRows(item) {
61
62
  quantity: typeof entry.quantity === "number" ? entry.quantity : 1,
62
63
  unitPrice: typeof entry.unitPrice === "number" ? entry.unitPrice : 0,
63
64
  totalPrice: typeof entry.totalPrice === "number" ? entry.totalPrice : 0,
65
+ /*
66
+ * The collapse keys, carried so the editor can group a bundle or
67
+ * buyer-assembled group back into one line the way the buyer's receipt
68
+ * does. Narrowed by `typeof` like every field above rather than cast —
69
+ * this function's whole job is turning a loose record into a typed row,
70
+ * and a cast here is how `title`/`price` once slipped through (RC#45).
71
+ */
72
+ groupSlug: typeof entry.groupSlug === "string" ? entry.groupSlug : undefined,
73
+ groupTitle: typeof entry.groupTitle === "string" ? entry.groupTitle : undefined,
74
+ bundleCategorySlug: typeof entry.bundleCategorySlug === "string" ? entry.bundleCategorySlug : undefined,
75
+ bundleProductIds: Array.isArray(entry.bundleProductIds)
76
+ ? entry.bundleProductIds.filter((v) => typeof v === "string")
77
+ : undefined,
64
78
  }));
65
79
  }
80
+ /*
81
+ * The row's headline, counted in LINES rather than item rows.
82
+ *
83
+ * 🛑 `extraCount` deliberately changed meaning when grouping landed: it was
84
+ * `items.length - 1`, so a bundle of four read "Dranzer S +3 more" — naming an
85
+ * arbitrary member and implying four separate things were bought. It is now
86
+ * `groups.length - 1`, so the same order reads "Starter Bundle +0" and a
87
+ * bundle plus one standalone reads "+1 more". The number a buyer or admin
88
+ * reads on a row should match the number of lines they will see inside it.
89
+ */
90
+ /*
91
+ * `sourceContext` arrives as JsonValue off the raw admin-list doc, so it can
92
+ * be a string, an array or null — none of which `OrderProvenanceCard` can
93
+ * switch on. This narrows to "an object carrying a `path` tag" and nothing
94
+ * further: that is deliberately NOT the card's own switch duplicated, it only
95
+ * establishes that there is a tag to switch on, which is what makes the single
96
+ * cast true instead of hopeful. `as unknown as OrderSourceContext` would
97
+ * assert exactly the same thing while checking nothing (Root Cause #98).
98
+ */
99
+ function toSourceContext(value) {
100
+ if (!value || typeof value !== "object" || Array.isArray(value))
101
+ return undefined;
102
+ /*
103
+ * Via `object` rather than straight off the JsonValue union, for two
104
+ * reasons that pull the same way. `Array.isArray` does not narrow
105
+ * `JsonArray | JsonObject` apart, so `value.path` does not resolve; and
106
+ * `OrderSourceContext` is not assignable to `JsonObject` (its optional
107
+ * members admit `undefined`, which is not a JsonValue), so TS refuses that
108
+ * conversion outright. Probing as `{ path?: string }` keeps both the probe
109
+ * and the assertion legal without an `unknown` anywhere.
110
+ */
111
+ const obj = value;
112
+ return typeof obj.path === "string"
113
+ ? obj
114
+ : undefined;
115
+ }
66
116
  function firstOrderItem(item) {
67
- const items = toOrderItemRows(item);
117
+ const groups = groupOrderItemsByLine(toOrderItemRows(item));
118
+ const first = groups[0];
119
+ const extraCount = Math.max(0, groups.length - 1);
120
+ if (!first)
121
+ return { extraCount: 0 };
122
+ if (first.kind === "single") {
123
+ return { image: first.item.image, title: first.item.title, extraCount };
124
+ }
68
125
  return {
69
- image: items[0]?.image,
70
- title: items[0]?.title,
71
- extraCount: Math.max(0, items.length - 1),
126
+ image: first.items[0]?.item.image,
127
+ title: first.groupTitle ?? "Grouped purchase",
128
+ extraCount,
72
129
  };
73
130
  }
74
131
  /**
@@ -206,6 +263,11 @@ export function AdminOrdersView({ children, ...props }) {
206
263
  couponCode: toStringValue(item.couponCode) || undefined,
207
264
  couponDiscount: Number(item.couponDiscount ?? 0) || undefined,
208
265
  },
266
+ // Raw doc in, so no serializer entry — but unlike `addons` above,
267
+ // which coerces every field by hand, this one needs a tag check
268
+ // before it can be trusted. See `toSourceContext`.
269
+ sourceContext: toSourceContext(item.sourceContext),
270
+ currency: toStringValue(item.currency, "") || undefined,
209
271
  };
210
272
  }),
211
273
  getTotal: (response, mappedRows) => typeof response.meta?.total === "number" ? response.meta.total : mappedRows.length,
@@ -289,5 +351,5 @@ export function AdminOrdersView({ children, ...props }) {
289
351
  ] })),
290
352
  renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(_Fragment, { children: [_jsx(FilterChipGroup, { label: "Status", tabs: ADMIN_ORDER_STATUS_TABS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id, paymentReview: "" })) }), _jsx(FilterChipGroup, { label: "Manual payment", tabs: ADMIN_ORDER_PAYMENT_REVIEW_TABS, value: pendingFilters.paymentReview ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, paymentReview: id, status: "" })) })] })),
291
353
  };
292
- return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(AdminOrderEditorView, { open: drawerOpen, onClose: () => setDrawerOpen(false), orderId: selectedRow?.id, orderLabel: selectedRow?.primary, currentStatus: selectedRow?.status, items: selectedRow?.items, paymentProofUrl: selectedRow?.paymentProofUrl, paymentTransactionId: selectedRow?.paymentTransactionId, paymentMethod: selectedRow?.paymentMethod, paymentStatus: selectedRow?.paymentStatus, displayedUpiId: selectedRow?.displayedUpiId, buyerReportedUpiId: selectedRow?.buyerReportedUpiId, paymentUpiMismatch: selectedRow?.paymentUpiMismatch, buyerMarkedPaid: selectedRow?.buyerMarkedPaid, buyerFraudAgreementAccepted: selectedRow?.buyerFraudAgreementAccepted, paymentReviewOutcome: selectedRow?.paymentReviewOutcome, addons: selectedRow?.addons })] }));
354
+ return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(AdminOrderEditorView, { open: drawerOpen, onClose: () => setDrawerOpen(false), orderId: selectedRow?.id, orderLabel: selectedRow?.primary, currentStatus: selectedRow?.status, items: selectedRow?.items, paymentProofUrl: selectedRow?.paymentProofUrl, paymentTransactionId: selectedRow?.paymentTransactionId, paymentMethod: selectedRow?.paymentMethod, paymentStatus: selectedRow?.paymentStatus, displayedUpiId: selectedRow?.displayedUpiId, buyerReportedUpiId: selectedRow?.buyerReportedUpiId, paymentUpiMismatch: selectedRow?.paymentUpiMismatch, buyerMarkedPaid: selectedRow?.buyerMarkedPaid, buyerFraudAgreementAccepted: selectedRow?.buyerFraudAgreementAccepted, paymentReviewOutcome: selectedRow?.paymentReviewOutcome, addons: selectedRow?.addons, sourceContext: selectedRow?.sourceContext, currency: selectedRow?.currency })] }));
293
355
  }
@@ -2,7 +2,8 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useQuery } from "@tanstack/react-query";
4
4
  import { useQueryClient } from "@tanstack/react-query";
5
- import { Badge, Button, Div, Heading, Row, Span, Stack, Text, useToast } from "../../../ui/index.js";
5
+ import { Badge, Button, Div, Heading, Row, Span, Stack, Text, TextLink, useToast } from "../../../ui/index.js";
6
+ import { ROUTES } from "../../../next/routing/route-map.js";
6
7
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints.js";
7
8
  import { apiClient } from "../../../http/index.js";
8
9
  import { useApiMutation } from "@mohasinac/appkit/client";
@@ -30,6 +31,22 @@ export function AdminPaymentClustersView(_props) {
30
31
  void queryClient.invalidateQueries({ queryKey: ["admin", "payment-clusters"] });
31
32
  },
32
33
  });
34
+ /*
35
+ * 🛑 "Flag Suspicious" was ONE-WAY here too: no unflag, so a wrong call
36
+ * left a permanent mark on a real buyer with no way back from this
37
+ * screen. `clear_ban` is already in the route's action enum and calls
38
+ * `clearBanById`; only the control was missing.
39
+ */
40
+ const clearFlagMutation = useApiMutation({
41
+ errorMessage: "Failed to clear that flag.",
42
+ mutationFn: async (id) => {
43
+ await apiClient.patch(ADMIN_ENDPOINTS.PAYMENT_METHOD_BY_ID(id), { action: "clear_ban" });
44
+ },
45
+ onSuccess: () => {
46
+ showToast("Flag cleared.", "success");
47
+ void queryClient.invalidateQueries({ queryKey: ["admin", "payment-clusters"] });
48
+ },
49
+ });
33
50
  const clusters = data?.clusters ?? [];
34
- return (_jsxs(Stack, { gap: "lg", padding: "page", children: [_jsxs(Stack, { gap: "none", children: [_jsx(Heading, { level: 2, size: "lg", weight: "semibold", color: "primary", children: "Payment Method Clusters" }), _jsx(Text, { size: "sm", color: "muted", className: "mt-1", children: "Multiple accounts sharing the same payment identifier. Flagging is informational only \u2014 users are not blocked." })] }), isLoading && (_jsx(Row, { justify: "center", padding: "y-4xl", children: _jsx(Div, { className: "h-6 w-6 animate-spin border-2 border-[var(--appkit-color-primary)] border-t-transparent", rounded: "full" }) })), error && (_jsx(Div, { surface: "danger-surface", color: "error", padding: "inline", rounded: "xl", textSize: "sm", children: "Failed to load payment clusters." })), !isLoading && clusters.length === 0 && (_jsx(Div, { surface: "muted", padding: "y-4xl", rounded: "xl", className: "text-center", children: _jsx(Text, { color: "muted", size: "sm", children: "No shared payment identifiers found." }) })), clusters.map((cluster) => (_jsxs(Stack, { surface: "card", padding: "md", gap: "md", rounded: "xl", border: "default", children: [_jsxs(Row, { justify: "between", align: "start", gap: "sm", children: [_jsxs(Stack, { gap: "none", children: [_jsx(Text, { size: "xs", color: "muted", weight: "medium", children: "Identifier Hash" }), _jsx(Span, { size: "xs", color: "muted", className: "font-mono truncate max-w-xs", children: cluster.identifierHash })] }), _jsxs(Badge, { variant: "secondary", size: "sm", children: [cluster.methods.length, " accounts"] })] }), _jsx(Stack, { gap: "xs", children: cluster.methods.map((m) => (_jsxs(Row, { justify: "between", align: "center", gap: "sm", surface: "muted", padding: "inlineSm", rounded: "lg", children: [_jsxs(Stack, { gap: "none", className: "min-w-0", children: [_jsxs(Text, { size: "sm", weight: "medium", color: "primary", className: "truncate", children: [m.type.toUpperCase(), " \u00B7 ", m.displayLabel] }), _jsxs(Text, { size: "xs", color: "muted", children: ["User: ", m.userId] })] }), _jsxs(Row, { gap: "xs", align: "center", children: [m.banStatus && (_jsx(Badge, { variant: BAN_BADGE[m.banStatus] ?? "secondary", size: "sm", children: m.banStatus.replace(/_/g, " ") })), m.banStatus !== "suspicious" && (_jsx(Button, { size: "sm", variant: "ghost", onClick: () => flagMutation.mutate(m.id), disabled: flagMutation.isPending, children: "Flag Suspicious" }))] })] }, m.id))) })] }, cluster.identifierHash)))] }));
51
+ return (_jsxs(Stack, { gap: "lg", padding: "page", children: [_jsxs(Stack, { gap: "none", children: [_jsx(Heading, { level: 2, size: "lg", weight: "semibold", color: "primary", children: "Payment Method Clusters" }), _jsx(Text, { size: "sm", color: "muted", className: "mt-1", children: "Multiple accounts sharing the same payment identifier. Flagging is informational only \u2014 users are not blocked." })] }), isLoading && (_jsx(Row, { justify: "center", padding: "y-4xl", children: _jsx(Div, { className: "h-6 w-6 animate-spin border-2 border-[var(--appkit-color-primary)] border-t-transparent", rounded: "full" }) })), error && (_jsx(Div, { surface: "danger-surface", color: "error", padding: "inline", rounded: "xl", textSize: "sm", children: "Failed to load payment clusters." })), !isLoading && clusters.length === 0 && (_jsx(Div, { surface: "muted", padding: "y-4xl", rounded: "xl", className: "text-center", children: _jsx(Text, { color: "muted", size: "sm", children: "No shared payment identifiers found." }) })), clusters.map((cluster) => (_jsxs(Stack, { surface: "card", padding: "md", gap: "md", rounded: "xl", border: "default", children: [_jsxs(Row, { justify: "between", align: "start", gap: "sm", children: [_jsxs(Stack, { gap: "none", children: [_jsx(Text, { size: "xs", color: "muted", weight: "medium", children: "Identifier Hash" }), _jsx(Span, { size: "xs", color: "muted", className: "font-mono truncate max-w-xs", children: cluster.identifierHash })] }), _jsxs(Badge, { variant: "secondary", size: "sm", children: [cluster.methods.length, " accounts"] })] }), _jsx(Stack, { gap: "xs", children: cluster.methods.map((m) => (_jsxs(Row, { justify: "between", align: "center", gap: "sm", surface: "muted", padding: "inlineSm", rounded: "lg", children: [_jsxs(Stack, { gap: "none", className: "min-w-0", children: [_jsxs(Text, { size: "sm", weight: "medium", color: "primary", className: "truncate", children: [m.type.toUpperCase(), " \u00B7 ", m.displayLabel] }), _jsxs(TextLink, { href: String(ROUTES.ADMIN.USER_DETAIL(m.userId)), size: "xs", children: ["User: ", m.userId] })] }), _jsxs(Row, { gap: "xs", align: "center", children: [m.banStatus && (_jsx(Badge, { variant: BAN_BADGE[m.banStatus] ?? "secondary", size: "sm", children: m.banStatus.replace(/_/g, " ") })), m.banStatus === "suspicious" ? (_jsx(Button, { size: "sm", variant: "ghost", onClick: () => clearFlagMutation.mutate(m.id), disabled: clearFlagMutation.isPending, children: "Clear flag" })) : (_jsx(Button, { size: "sm", variant: "ghost", onClick: () => flagMutation.mutate(m.id), disabled: flagMutation.isPending, children: "Flag Suspicious" }))] })] }, m.id))) })] }, cluster.identifierHash)))] }));
35
52
  }
@@ -194,7 +194,7 @@ export function AdminProductEditorView({ productId, onSaved, onDeleted, embedded
194
194
  label: "Details",
195
195
  required: true,
196
196
  fields: ["title", "price", "storeId", "categorySlug", "brandSlug"],
197
- render: () => (_jsx(Stack, { gap: "md", children: _jsxs(Card, { variant: "outlined", padding: "lg", children: [_jsx(Text, { className: __P.sectionLabel, color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: "Classification" }), _jsxs(Stack, { gap: "md", children: [_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "medium", color: "primary", children: "Store" }), _jsx(PaginatedSelect, { value: product.storeId ?? null, onChange: handleStoreSelect, loadOptions: loadStoreOptions, placeholder: "Search stores\u2026", searchPlaceholder: "Type store name\u2026", noResultsText: "No stores found", ariaLabel: "Store" })] }), _jsx(ProductForm, { product: product, onChange: setProduct,
197
+ render: () => (_jsx(Stack, { gap: "md", children: _jsxs(Card, { variant: "outlined", padding: "lg", children: [_jsx(Text, { className: __P.sectionLabel, color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: "Classification" }), _jsxs(Stack, { gap: "md", children: [_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "medium", color: "primary", children: "Store" }), _jsx(PaginatedSelect, { name: "storeId", value: product.storeId ?? null, onChange: handleStoreSelect, loadOptions: loadStoreOptions, placeholder: "Search stores\u2026", searchPlaceholder: "Type store name\u2026", noResultsText: "No stores found", ariaLabel: "Store" })] }), _jsx(ProductForm, { product: product, onChange: setProduct,
198
198
  /*
199
199
  * The ONLY place the Tax & GST section is shown. LetItRip
200
200
  * invoices under its own GSTIN, so the rate is an admin
@@ -217,7 +217,7 @@ export function AdminProductEditorView({ productId, onSaved, onDeleted, embedded
217
217
  groupRequiredMemberIds: p.groupRequiredMemberIds,
218
218
  groupDiscountPercent: p.groupDiscountPercent,
219
219
  }, isAuction: modeFromProduct(p) === "auction", storeProductsEndpoint: ADMIN_ENDPOINTS.PRODUCTS, onGroupChanged: () => productQuery.refetch() }))
220
- : undefined, renderGroupJoinField: ({ label, value, onChange, disabled }) => (_jsx(GroupInlineSelect, { scope: "admin", value: value ?? "", onChange: (id) => onChange(id || undefined), disabled: disabled, label: label, placeholder: "None (standalone product)", allowCreate: false })), renderCategorySelector: ({ label, value, onChange, disabled }) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "medium", color: "primary", children: label }), _jsx(PaginatedSelect, { value: value || null, onChange: (v) => onChange(v ?? ""), loadOptions: loadCategoryOptions, placeholder: "Search categories\u2026", searchPlaceholder: "Type category name\u2026", noResultsText: "No categories found", ariaLabel: label, disabled: disabled, createLabel: "Category", renderCreateForm: ({ onCreated, onCancel }) => (_jsx(CategoryQuickCreateForm, { onSaved: (id, name) => onCreated({ value: id, label: name }), onCancel: onCancel })) })] })), renderBrandSelector: (args) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "medium", color: "primary", children: args.label }), _jsx(PaginatedSelect, { value: args.multi ? null : (args.value || null), onChange: (v) => args.onValueChange(v ?? ""), loadOptions: loadBrandOptions, placeholder: "Search brands\u2026", searchPlaceholder: "Type brand name\u2026", noResultsText: "No brands found", ariaLabel: args.label, disabled: args.disabled, createLabel: "Brand", renderCreateForm: ({ onCreated, onCancel }) => (_jsx(BrandQuickCreateForm, { onSaved: (id, name) => onCreated({ value: id, label: name }), onCancel: onCancel })) })] })) })] })] }) })),
220
+ : undefined, renderGroupJoinField: ({ label, value, onChange, disabled }) => (_jsx(GroupInlineSelect, { scope: "admin", value: value ?? "", onChange: (id) => onChange(id || undefined), disabled: disabled, label: label, placeholder: "None (standalone product)", allowCreate: false })), renderCategorySelector: ({ label, value, onChange, disabled }) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "medium", color: "primary", children: label }), _jsx(PaginatedSelect, { name: "categorySlug", value: value || null, onChange: (v) => onChange(v ?? ""), loadOptions: loadCategoryOptions, placeholder: "Search categories\u2026", searchPlaceholder: "Type category name\u2026", noResultsText: "No categories found", ariaLabel: label, disabled: disabled, createLabel: "Category", renderCreateForm: ({ onCreated, onCancel }) => (_jsx(CategoryQuickCreateForm, { onSaved: (id, name) => onCreated({ value: id, label: name }), onCancel: onCancel })) })] })), renderBrandSelector: (args) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "medium", color: "primary", children: args.label }), _jsx(PaginatedSelect, { name: "brandSlug", value: args.multi ? null : (args.value || null), onChange: (v) => args.onValueChange(v ?? ""), loadOptions: loadBrandOptions, placeholder: "Search brands\u2026", searchPlaceholder: "Type brand name\u2026", noResultsText: "No brands found", ariaLabel: args.label, disabled: args.disabled, createLabel: "Brand", renderCreateForm: ({ onCreated, onCancel }) => (_jsx(BrandQuickCreateForm, { onSaved: (id, name) => onCreated({ value: id, label: name }), onCancel: onCancel })) })] })) })] })] }) })),
221
221
  },
222
222
  {
223
223
  id: "inventory",
@@ -2,4 +2,14 @@ import React from "react";
2
2
  export interface AdminSectionsViewProps {
3
3
  children?: React.ReactNode;
4
4
  }
5
+ /**
6
+ * The homepage/surface sections listing.
7
+ *
8
+ * Was a bare `<DataTable rows>` with no `columns`, no `renderRowActions`, no
9
+ * `onRowClick` and no `rowHrefTemplate` — so `isInteractive` was false and
10
+ * every row was inert, including the blank avatar circles that come from
11
+ * `buildDefaultColumns(undefined)`. The only way to edit a section was a
12
+ * toolbar button, a "Mode" dropdown, and a second dropdown to re-find the row
13
+ * you had just clicked past.
14
+ */
5
15
  export declare function AdminSectionsView({ children }: AdminSectionsViewProps): React.JSX.Element;