@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.
- package/dist/.build-stamp.json +3 -3
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +19 -3
- package/dist/_internal/client/features/maintenance/views/AnalysisRunnerView.js +1 -1
- package/dist/_internal/client/features/maintenance/views/CloudLogsListView.js +1 -1
- package/dist/_internal/server/features/checkout/actions.d.ts +80 -0
- package/dist/_internal/server/features/checkout/actions.js +542 -26
- package/dist/_internal/server/features/invoicing/allocate.d.ts +63 -0
- package/dist/_internal/server/features/invoicing/allocate.js +162 -0
- package/dist/_internal/server/features/invoicing/credit-note.d.ts +57 -0
- package/dist/_internal/server/features/invoicing/credit-note.js +126 -0
- package/dist/_internal/server/features/invoicing/gstr1.d.ts +74 -0
- package/dist/_internal/server/features/invoicing/gstr1.js +251 -0
- package/dist/_internal/server/features/invoicing/issue.d.ts +96 -0
- package/dist/_internal/server/features/invoicing/issue.js +202 -0
- package/dist/_internal/server/features/orders/actions.d.ts +8 -1
- package/dist/_internal/server/features/orders/actions.js +81 -8
- package/dist/_internal/server/features/orders/adapters.js +33 -0
- package/dist/_internal/server/features/orders/cancellation-refund.d.ts +15 -9
- package/dist/_internal/server/features/orders/cancellation-refund.js +15 -9
- package/dist/_internal/server/features/points/award.js +46 -4
- package/dist/_internal/server/features/refunds/actions.js +26 -0
- package/dist/_internal/server/features/shipping/courier-block.d.ts +69 -0
- package/dist/_internal/server/features/shipping/courier-block.js +239 -0
- package/dist/_internal/server/features/site-settings/adapters.d.ts +1 -1
- package/dist/_internal/server/features/site-settings/adapters.js +15 -0
- package/dist/_internal/server/features/stores/adapters.d.ts +2 -2
- package/dist/_internal/server/features/stores/adapters.js +51 -0
- package/dist/_internal/server/functions/scheduled.js +38 -1
- package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +9 -2
- package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +4 -0
- package/dist/_internal/server/jobs/core/dailyStatusDigest.js +19 -2
- package/dist/_internal/server/jobs/core/index.d.ts +2 -1
- package/dist/_internal/server/jobs/core/index.js +2 -1
- package/dist/_internal/server/jobs/core/onJobCreated.d.ts +30 -7
- package/dist/_internal/server/jobs/core/onJobCreated.js +78 -45
- package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +7 -0
- package/dist/_internal/server/jobs/core/onOrderStatusChange.js +62 -0
- package/dist/_internal/server/jobs/core/paymentReconcile.js +87 -97
- package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +33 -0
- package/dist/_internal/server/jobs/core/runJobOnce.d.ts +48 -0
- package/dist/_internal/server/jobs/core/runJobOnce.js +195 -0
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +10 -2
- package/dist/_internal/server/jobs/handlers/onOrderStatusChange.js +17 -0
- package/dist/_internal/server/notifications/channel-health.d.ts +26 -3
- package/dist/_internal/shared/actions/action-registry.js +177 -9
- package/dist/_internal/shared/checkout/coupon-discount.d.ts +43 -1
- package/dist/_internal/shared/checkout/coupon-discount.js +26 -1
- package/dist/_internal/shared/checkout/order-math.d.ts +145 -0
- package/dist/_internal/shared/checkout/order-math.js +173 -0
- package/dist/_internal/shared/checkout/refundable-base.d.ts +25 -0
- package/dist/_internal/shared/checkout/refundable-base.js +13 -1
- package/dist/_internal/shared/checkout/split.d.ts +87 -0
- package/dist/_internal/shared/checkout/split.js +100 -0
- package/dist/_internal/shared/content/disclaimers.d.ts +88 -0
- package/dist/_internal/shared/content/disclaimers.js +217 -0
- package/dist/_internal/shared/content/published-values.d.ts +88 -0
- package/dist/_internal/shared/content/published-values.js +198 -0
- package/dist/_internal/shared/features/admin/integrations.d.ts +109 -0
- package/dist/_internal/shared/features/admin/integrations.js +253 -0
- package/dist/_internal/shared/features/orders/dispute-reasons.d.ts +113 -0
- package/dist/_internal/shared/features/orders/dispute-reasons.js +181 -0
- package/dist/_internal/shared/features/orders/refund-copy.d.ts +1 -1
- package/dist/_internal/shared/features/orders/refund-copy.js +18 -1
- package/dist/_internal/shared/features/points/accepts.d.ts +36 -0
- package/dist/_internal/shared/features/points/accepts.js +43 -0
- package/dist/_internal/shared/features/shipping/shared-purchase.d.ts +91 -0
- package/dist/_internal/shared/features/shipping/shared-purchase.js +108 -0
- package/dist/_internal/shared/features/site-settings/types.d.ts +11 -0
- package/dist/_internal/shared/fees/calculator.d.ts +33 -1
- package/dist/_internal/shared/fees/calculator.js +32 -2
- package/dist/_internal/shared/media/limits.d.ts +10 -0
- package/dist/_internal/shared/media/limits.js +10 -0
- package/dist/_internal/shared/types/action-result.js +15 -1
- package/dist/client/api/surface-error.js +16 -2
- package/dist/client/api/useApiMutation.js +17 -1
- package/dist/client.d.ts +12 -1
- package/dist/client.js +31 -1
- package/dist/constants/api-endpoints.d.ts +45 -0
- package/dist/constants/api-endpoints.js +15 -0
- package/dist/constants/field-names.d.ts +18 -0
- package/dist/constants/field-names.js +28 -0
- package/dist/contracts/index.d.ts +1 -1
- package/dist/contracts/shipping.d.ts +45 -0
- package/dist/contracts/shipping.js +15 -0
- package/dist/core/server-action.js +19 -3
- package/dist/errors/error-mapping.js +26 -1
- package/dist/features/about/components/AboutView.js +1 -1
- package/dist/features/account/components/BuyerAuctionsGuideView.js +4 -1
- package/dist/features/account/components/UserOffersPanel.js +5 -3
- package/dist/features/account/components/UserOrdersView.js +19 -33
- package/dist/features/admin/components/AdminActionIndexView.js +100 -5
- package/dist/features/admin/components/AdminAddressClustersView.js +21 -2
- package/dist/features/admin/components/AdminBlogEditorView.js +8 -8
- package/dist/features/admin/components/AdminCarouselEditorView.js +1 -1
- package/dist/features/admin/components/AdminCarouselView.js +96 -4
- package/dist/features/admin/components/AdminCouponEditorView.js +17 -0
- package/dist/features/admin/components/AdminFulfillmentView.js +3 -2
- package/dist/features/admin/components/AdminInvoicingView.d.ts +2 -0
- package/dist/features/admin/components/AdminInvoicingView.js +65 -0
- package/dist/features/admin/components/AdminMediaView.js +36 -3
- package/dist/features/admin/components/AdminNavigationView.js +4 -1
- package/dist/features/admin/components/AdminOffersView.js +2 -1
- package/dist/features/admin/components/AdminOrderEditorView.d.ts +18 -1
- package/dist/features/admin/components/AdminOrderEditorView.js +11 -2
- package/dist/features/admin/components/AdminOrdersGuideView.js +23 -2
- package/dist/features/admin/components/AdminOrdersView.js +67 -5
- package/dist/features/admin/components/AdminPaymentClustersView.js +19 -2
- package/dist/features/admin/components/AdminProductEditorView.js +2 -2
- package/dist/features/admin/components/AdminSectionsView.d.ts +10 -0
- package/dist/features/admin/components/AdminSectionsView.js +486 -224
- package/dist/features/admin/components/OwnerQuickActions.js +24 -2
- package/dist/features/admin/components/ReferenceRecordEditor.js +1 -1
- package/dist/features/admin/constants/filter-tabs.d.ts +6 -0
- package/dist/features/admin/constants/filter-tabs.js +6 -0
- package/dist/features/admin/constants/site-settings-tabs.d.ts +1 -1
- package/dist/features/admin/hooks/useAdminListingData.js +16 -0
- package/dist/features/admin/hooks/useOptimisticRowFlag.d.ts +33 -0
- package/dist/features/admin/hooks/useOptimisticRowFlag.js +87 -0
- package/dist/features/admin/repository/notification.repository.d.ts +15 -0
- package/dist/features/admin/repository/notification.repository.js +32 -0
- package/dist/features/admin/schemas/action-index-form.d.ts +34 -0
- package/dist/features/admin/schemas/action-index-form.js +115 -0
- package/dist/features/admin/schemas/admin-user-form.d.ts +2 -2
- package/dist/features/admin/schemas/firestore.d.ts +30 -0
- package/dist/features/admin/schemas/firestore.js +5 -0
- package/dist/features/audit-log/schemas/firestore.d.ts +30 -0
- package/dist/features/audit-log/schemas/firestore.js +15 -0
- package/dist/features/auth/components/RegisterForm.js +2 -1
- package/dist/features/auth/permissions/constants.js +13 -0
- package/dist/features/cart/components/CartPriceBreakdown.d.ts +13 -0
- package/dist/features/cart/components/CartPriceBreakdown.js +6 -2
- package/dist/features/cart/components/PointsTenderPicker.d.ts +61 -0
- package/dist/features/cart/components/PointsTenderPicker.js +15 -0
- package/dist/features/cart/components/StoreAddonsPicker.js +2 -1
- package/dist/features/cart/components/index.d.ts +2 -0
- package/dist/features/cart/components/index.js +1 -0
- package/dist/features/cart/repository/cart.repository.d.ts +19 -0
- package/dist/features/cart/repository/cart.repository.js +27 -0
- package/dist/features/cart/schemas/firestore.d.ts +92 -0
- package/dist/features/catalogue/components/CatalogueItemEditorView.js +3 -3
- package/dist/features/contact/email.d.ts +27 -10
- package/dist/features/contact/email.js +20 -3
- package/dist/features/dispute-reasons/repository/dispute-reasons.repository.d.ts +38 -0
- package/dist/features/dispute-reasons/repository/dispute-reasons.repository.js +80 -0
- package/dist/features/dispute-reasons/schemas/firestore.d.ts +64 -0
- package/dist/features/dispute-reasons/schemas/firestore.js +40 -0
- package/dist/features/events/components/AdminEventEditorView.js +8 -6
- package/dist/features/faq/components/FAQAccordion.d.ts +13 -1
- package/dist/features/faq/components/FAQAccordion.js +29 -4
- package/dist/features/invoicing/schemas/firestore.d.ts +112 -0
- package/dist/features/invoicing/schemas/firestore.js +45 -0
- package/dist/features/invoicing/utils/financial-year.d.ts +43 -0
- package/dist/features/invoicing/utils/financial-year.js +53 -0
- package/dist/features/jobs/actions/enqueue-job.js +18 -1
- package/dist/features/jobs/repository/jobs.repository.d.ts +62 -1
- package/dist/features/jobs/repository/jobs.repository.js +84 -1
- package/dist/features/jobs/schemas/firestore.d.ts +80 -0
- package/dist/features/jobs/schemas/firestore.js +37 -0
- package/dist/features/layout/hooks/useFormBottomActions.js +20 -1
- package/dist/features/lottery/schemas/zod.d.ts +6 -6
- package/dist/features/media/MediaImage.js +22 -1
- package/dist/features/media/upload/ImageUpload.js +1 -1
- package/dist/features/obligations/constants/policies.js +24 -1
- package/dist/features/orders/components/EmiInstallmentsPanel.js +25 -7
- package/dist/features/orders/components/OrderPaymentSummary.js +10 -1
- package/dist/features/orders/components/OrderProvenanceCard.d.ts +8 -0
- package/dist/features/orders/components/OrderProvenanceCard.js +185 -0
- package/dist/features/orders/components/RaiseDisputeForm.d.ts +14 -0
- package/dist/features/orders/components/RaiseDisputeForm.js +111 -0
- package/dist/features/orders/components/RefundRequestView.js +22 -4
- package/dist/features/orders/components/index.d.ts +4 -0
- package/dist/features/orders/components/index.js +2 -0
- package/dist/features/orders/constants/order-lane-tabs.d.ts +69 -0
- package/dist/features/orders/constants/order-lane-tabs.js +88 -0
- package/dist/features/orders/repository/orders.repository.d.ts +57 -0
- package/dist/features/orders/repository/orders.repository.js +145 -0
- package/dist/features/orders/schemas/firestore.d.ts +196 -1
- package/dist/features/orders/schemas/index.d.ts +60 -12
- package/dist/features/orders/schemas/index.js +12 -0
- package/dist/features/orders/types/index.d.ts +26 -0
- package/dist/features/orders/utils/courier-block.d.ts +25 -0
- package/dist/features/orders/utils/courier-block.js +23 -0
- package/dist/features/payment-cases/schemas/firestore.d.ts +26 -1
- package/dist/features/payment-cases/schemas/firestore.js +1 -0
- package/dist/features/products/components/GroupMemberPicker.js +4 -1
- package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -2
- package/dist/features/products/components/PrizeDrawEntryActions.js +2 -1
- package/dist/features/products/components/ProductDetailActions.js +2 -1
- package/dist/features/products/components/ProductDetailPageView.d.ts +17 -1
- package/dist/features/products/components/ProductDetailPageView.js +2 -2
- package/dist/features/products/schemas/product-features.validators.d.ts +10 -10
- package/dist/features/promotions/actions/coupon-stacking.d.ts +30 -3
- package/dist/features/promotions/actions/coupon-stacking.js +21 -2
- package/dist/features/promotions/components/CouponCard.js +13 -0
- package/dist/features/promotions/constants/coupon-help.d.ts +2 -2
- package/dist/features/promotions/constants/coupon-help.js +9 -1
- package/dist/features/promotions/schemas/firestore.d.ts +24 -0
- package/dist/features/promotions/schemas/firestore.js +4 -0
- package/dist/features/promotions/types/index.d.ts +19 -1
- package/dist/features/scams/components/ScamProfileView.js +2 -2
- package/dist/features/scams/components/ScamRegistryView.js +2 -2
- package/dist/features/search/action-index/tab-entries.js +1 -1
- package/dist/features/seller/actions/seller-actions.js +33 -3
- package/dist/features/seller/components/FulfillmentView.js +3 -2
- package/dist/features/seller/components/SellerAddressesView.js +32 -4
- package/dist/features/seller/components/SellerAnalyticsAlertsView.js +62 -3
- package/dist/features/seller/components/SellerBundlesView.js +53 -14
- package/dist/features/seller/components/SellerGroupedListingsView.js +23 -3
- package/dist/features/seller/components/SellerListingTypeView.js +56 -10
- package/dist/features/seller/components/SellerOrdersView.js +129 -27
- package/dist/features/seller/components/SellerPayoutMethodsView.js +33 -1
- package/dist/features/seller/components/SellerPayoutSettingsView.js +48 -9
- package/dist/features/seller/components/SellerProductsView.js +5 -1
- package/dist/features/seller/components/SellerShippingConfigsView.js +33 -1
- package/dist/features/seller/components/SellerShippingView.js +2 -1
- package/dist/features/seller/components/SellerStoreCategoriesView.js +33 -1
- package/dist/features/seller/components/SellerSupportView.js +69 -2
- package/dist/features/seller/hooks/useSellerListingData.js +25 -0
- package/dist/features/shell/SectionForm.js +20 -16
- package/dist/features/shell/build-sections.js +14 -1
- package/dist/features/shipments/components/AdminShipmentLotItemsView.js +54 -1
- package/dist/features/shipments/components/AdminShipmentProjectionsView.js +3 -2
- package/dist/features/shipments/schemas/validation.d.ts +4 -4
- package/dist/features/shipping-boxes/repository/shipping-boxes.repository.d.ts +43 -0
- package/dist/features/shipping-boxes/repository/shipping-boxes.repository.js +90 -0
- package/dist/features/shipping-boxes/schemas/firestore.d.ts +82 -0
- package/dist/features/shipping-boxes/schemas/firestore.js +53 -0
- package/dist/features/sticker-trace/components/StickerCommitPanel.js +2 -1
- package/dist/features/sticker-trace/components/StickerPrintPanel.js +2 -1
- package/dist/features/sticker-trace/components/StickerRetryPanel.js +24 -4
- package/dist/features/sticker-trace/components/StickerTraceStudio.js +2 -1
- package/dist/features/store-extensions/schemas/report-create-form.d.ts +2 -2
- package/dist/features/store-extensions/schemas/shipping-config-form.d.ts +2 -2
- package/dist/features/stores/components/StoreOrdersGuideView.js +6 -1
- package/dist/features/stores/schemas/firestore.d.ts +71 -0
- package/dist/features/stores/types/index.d.ts +19 -0
- package/dist/features/support/schemas/index.d.ts +6 -6
- package/dist/features/tester/components/AdminTesterFeedbackIssuesView.js +3 -2
- package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
- package/dist/index.d.ts +11 -2
- package/dist/index.js +17 -2
- package/dist/next/routing/route-map.d.ts +24 -0
- package/dist/next/routing/route-map.js +19 -0
- package/dist/providers/shipping-shiprocket/index.d.ts +27 -1
- package/dist/providers/shipping-shiprocket/index.js +84 -1
- package/dist/schemas/registry.d.ts +51 -22
- package/dist/schemas/sieve.d.ts +5 -5
- package/dist/server-entry.d.ts +2 -2
- package/dist/server-entry.js +8 -1
- package/dist/server.d.ts +11 -2
- package/dist/server.js +40 -2
- package/dist/styles.css +64 -80
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/themes/default-dark.js +1 -0
- package/dist/tokens/themes/default-light.js +1 -0
- package/dist/tokens/themes/required.d.ts +1 -1
- package/dist/tokens/themes/required.js +1 -0
- package/dist/tokens/tokens.css +15 -0
- package/dist/ui/components/Checkbox.js +10 -2
- package/dist/ui/components/DateInput.js +8 -1
- package/dist/ui/components/Disclaimer.d.ts +19 -0
- package/dist/ui/components/Disclaimer.js +74 -0
- package/dist/ui/components/Input.js +22 -2
- package/dist/ui/components/PaginatedSelect.d.ts +8 -19
- package/dist/ui/components/PaginatedSelect.js +43 -9
- package/dist/ui/components/Radio.js +8 -1
- package/dist/ui/components/Select.js +10 -2
- package/dist/ui/components/TagInput.d.ts +8 -1
- package/dist/ui/components/TagInput.js +4 -3
- package/dist/ui/components/Textarea.js +10 -2
- package/dist/ui/components/tabs-overflow.js +64 -11
- package/dist/ui/forms/FieldCheckbox.js +1 -1
- package/dist/ui/forms/FormErrorList.d.ts +0 -16
- package/dist/ui/forms/FormErrorList.js +34 -1
- package/dist/ui/forms/apply-zod-issues.d.ts +19 -1
- package/dist/ui/forms/apply-zod-issues.js +23 -1
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +6 -0
- package/dist/ui/rich-text/RichText.style.css +48 -79
- package/package.json +1 -1
- 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: "
|
|
70
|
-
}), filtered.length === 0 && !isLoading && (_jsx(Text, { paddingY: "lg", className: "col-span-full", color: "muted", size: "sm", align: "center", children: "No files found." }))] }),
|
|
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),
|
|
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.
|
|
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((
|
|
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
|
-
|
|
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."] }),
|
|
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
|
|
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:
|
|
71
|
-
extraCount
|
|
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(
|
|
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;
|