@mohasinac/appkit 4.60.1 → 4.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/auctions/actions.d.ts +1 -1
- package/dist/_internal/server/features/auctions/actions.js +12 -1
- package/dist/_internal/server/features/blog/actions.d.ts +1 -1
- package/dist/_internal/server/features/blog/actions.js +12 -1
- package/dist/_internal/server/features/brands/actions.d.ts +1 -1
- package/dist/_internal/server/features/brands/actions.js +12 -1
- package/dist/_internal/server/features/cart/actions.d.ts +1 -1
- package/dist/_internal/server/features/cart/actions.js +12 -1
- package/dist/_internal/server/features/checkout/actions.js +0 -1
- package/dist/_internal/server/features/events/actions.d.ts +1 -1
- package/dist/_internal/server/features/events/actions.js +12 -1
- package/dist/_internal/server/features/gateway-events/redact.js +14 -2
- package/dist/_internal/server/features/history/actions.d.ts +1 -1
- package/dist/_internal/server/features/history/actions.js +12 -1
- package/dist/_internal/server/features/lottery/actions.d.ts +1 -1
- package/dist/_internal/server/features/lottery/actions.js +12 -1
- package/dist/_internal/server/features/orders/actions.d.ts +1 -1
- package/dist/_internal/server/features/orders/actions.js +12 -1
- package/dist/_internal/server/features/orders/cancellation-refund.js +0 -1
- package/dist/_internal/server/features/orders/service.js +31 -1
- package/dist/_internal/server/features/payouts/actions.d.ts +1 -1
- package/dist/_internal/server/features/payouts/actions.js +12 -1
- package/dist/_internal/server/features/points/award.js +9 -1
- package/dist/_internal/server/features/pre-orders/actions.d.ts +1 -1
- package/dist/_internal/server/features/pre-orders/actions.js +12 -1
- package/dist/_internal/server/features/prize-draws/actions.d.ts +1 -1
- package/dist/_internal/server/features/prize-draws/actions.js +12 -1
- package/dist/_internal/server/features/products/actions.d.ts +1 -1
- package/dist/_internal/server/features/products/actions.js +12 -1
- package/dist/_internal/server/features/promotions/actions.d.ts +1 -1
- package/dist/_internal/server/features/promotions/actions.js +12 -1
- package/dist/_internal/server/features/protection-claims/actions.d.ts +2 -2
- package/dist/_internal/server/features/protection-claims/actions.js +21 -12
- package/dist/_internal/server/features/raffle/actions.d.ts +1 -1
- package/dist/_internal/server/features/raffle/actions.js +12 -1
- package/dist/_internal/server/features/refunds/actions.d.ts +1 -3
- package/dist/_internal/server/features/refunds/actions.js +14 -2
- package/dist/_internal/server/features/reviews/actions.d.ts +1 -1
- package/dist/_internal/server/features/reviews/actions.js +12 -1
- package/dist/_internal/server/features/wishlist/actions.d.ts +1 -1
- package/dist/_internal/server/features/wishlist/actions.js +12 -1
- package/dist/_internal/server/jobs/core/obligationSweep.js +0 -1
- package/dist/_internal/server/jobs/core/paymentReconcile.js +93 -76
- package/dist/_internal/server/jobs/core/testDataCleanup.d.ts +1 -1
- package/dist/_internal/server/jobs/core/testDataCleanup.js +22 -1
- package/dist/_internal/server/jobs/handlers/onShipmentAllocationSync.js +16 -4
- package/dist/_internal/shared/actions/action-registry.js +149 -9
- package/dist/_internal/shared/features/promotions/schema.d.ts +66 -0
- package/dist/_internal/shared/features/promotions/schema.js +7 -0
- package/dist/_internal/shared/media/limits.d.ts +10 -0
- package/dist/_internal/shared/media/limits.js +10 -0
- package/dist/_internal/shared/obligations/deadlines.js +11 -1
- package/dist/_internal/shared/tester/window.d.ts +25 -0
- package/dist/_internal/shared/tester/window.js +66 -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 +1 -1
- package/dist/client.js +1 -1
- package/dist/constants/api-endpoints.d.ts +3 -0
- package/dist/constants/api-endpoints.js +1 -0
- package/dist/constants/field-names.d.ts +17 -0
- package/dist/constants/field-names.js +23 -0
- package/dist/core/server-action.js +19 -3
- package/dist/core/unit-of-work.js +15 -1
- package/dist/errors/error-mapping.js +26 -1
- package/dist/errors/firestore-codes.d.ts +37 -0
- package/dist/errors/firestore-codes.js +52 -0
- package/dist/errors/index.d.ts +0 -1
- package/dist/errors/index.js +12 -2
- package/dist/features/account/components/UserOffersPanel.js +5 -3
- 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 +8 -0
- package/dist/features/admin/components/AdminFulfillmentView.js +3 -2
- package/dist/features/admin/components/AdminGatewayEventsView.js +2 -2
- 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/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/DataListingView.js +2 -0
- package/dist/features/admin/components/ReferenceRecordEditor.js +1 -1
- package/dist/features/admin/components/analytics/AdminStatCard.js +4 -1
- 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/repository/site-settings.repository.d.ts +2 -1
- package/dist/features/admin/repository/site-settings.repository.js +7 -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/auctions/components/MarketplaceAuctionCard.js +1 -1
- package/dist/features/auth/components/RegisterForm.js +2 -1
- package/dist/features/catalogue/actions/approve-catalogue-listing.d.ts +1 -1
- package/dist/features/catalogue/actions/approve-catalogue-listing.js +12 -1
- package/dist/features/catalogue/actions/list-from-catalogue.d.ts +1 -1
- package/dist/features/catalogue/actions/list-from-catalogue.js +12 -1
- package/dist/features/catalogue/actions/submit-for-approval.d.ts +1 -1
- package/dist/features/catalogue/actions/submit-for-approval.js +12 -1
- package/dist/features/catalogue/components/CatalogueItemEditorView.js +3 -3
- package/dist/features/categories/repository/price-observation.repository.d.ts +19 -0
- package/dist/features/categories/repository/price-observation.repository.js +21 -2
- package/dist/features/events/actions/event-actions.js +4 -1
- package/dist/features/events/components/AdminEventEditorView.js +79 -50
- package/dist/features/events/components/EventsListPageView.js +2 -1
- package/dist/features/events/schemas/firestore.d.ts +17 -0
- package/dist/features/events/schemas/firestore.js +1 -0
- package/dist/features/events/utils/sort-pinned.d.ts +33 -0
- package/dist/features/events/utils/sort-pinned.js +46 -0
- package/dist/features/gateway-events/repository/gateway-events.repository.js +3 -40
- package/dist/features/gateway-events/schemas/index.d.ts +2 -2
- package/dist/features/inventory/components/AdminStorageBoxesView.js +55 -39
- package/dist/features/inventory/components/ReceiveStationView.js +61 -17
- package/dist/features/inventory/repository/storage-boxes.repository.d.ts +3 -1
- package/dist/features/inventory/repository/storage-boxes.repository.js +36 -3
- package/dist/features/layout/hooks/useFormBottomActions.js +20 -1
- package/dist/features/obligations/repository/obligations.repository.js +10 -1
- package/dist/features/orders/components/EmiInstallmentsPanel.js +25 -7
- package/dist/features/orders/components/RefundRequestView.js +4 -4
- package/dist/features/orders/schemas/firestore.d.ts +19 -0
- package/dist/features/orders/schemas/firestore.js +19 -0
- package/dist/features/orders/schemas/index.d.ts +6 -6
- package/dist/features/payment-cases/repository/payment-cases.repository.d.ts +1 -0
- package/dist/features/payment-cases/repository/payment-cases.repository.js +3 -14
- package/dist/features/pre-orders/components/MarketplacePreorderCard.js +1 -1
- package/dist/features/products/components/GroupMemberPicker.js +4 -1
- package/dist/features/products/components/MarketplaceBundleCard.js +1 -1
- package/dist/features/products/components/MarketplacePrizeDrawCard.js +1 -1
- package/dist/features/products/components/PrizeDrawEntryActions.js +2 -1
- package/dist/features/products/components/ProductDetailActions.js +2 -1
- package/dist/features/products/components/ProductForm.js +2 -2
- package/dist/features/products/components/ProductGrid.js +1 -1
- package/dist/features/promotions/repository/claimed-coupons.repository.js +31 -1
- package/dist/features/promotions/schemas/firestore.d.ts +22 -0
- package/dist/features/promotions/schemas/firestore.js +22 -0
- package/dist/features/promotions/schemas/index.d.ts +479 -6
- package/dist/features/promotions/schemas/index.js +153 -0
- package/dist/features/protection-claims/repository/protection-claims.repository.js +22 -15
- 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/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/schemas/coupon-form.d.ts +5 -0
- package/dist/features/seller/schemas/coupon-form.js +18 -0
- package/dist/features/shell/SectionForm.js +35 -9
- 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/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/sticker-trace/server.d.ts +2 -0
- package/dist/features/tester/components/AdminTesterFeedbackIssuesView.js +3 -2
- package/dist/http/api-handler.js +4 -1
- package/dist/index.d.ts +8 -4
- package/dist/index.js +6 -4
- package/dist/next/routing/route-map.d.ts +4 -2
- package/dist/next/routing/route-map.js +19 -1
- package/dist/schemas/registry.d.ts +15 -10
- package/dist/schemas/sieve.d.ts +3 -3
- package/dist/server.d.ts +1 -2
- package/dist/server.js +6 -4
- package/dist/styles.css +51 -0
- package/dist/ui/components/Checkbox.js +10 -2
- package/dist/ui/components/DateInput.js +8 -1
- package/dist/ui/components/Input.js +22 -2
- package/dist/ui/components/PaginatedSelect.d.ts +8 -19
- package/dist/ui/components/PaginatedSelect.js +0 -0
- 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/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/package.json +1 -1
- package/scripts/seed-cli.mjs +1822 -1812
- package/dist/features/tester/utils/phases.d.ts +0 -48
- package/dist/features/tester/utils/phases.js +0 -139
|
@@ -9,7 +9,8 @@ import { PaginatedSelect } from "../../../ui/components/PaginatedSelect.js";
|
|
|
9
9
|
import { apiClient } from "../../../http/index.js";
|
|
10
10
|
import { ADMIN_ENDPOINTS, SELLER_ENDPOINTS } from "../../../constants/api-endpoints.js";
|
|
11
11
|
import { normalizeError } from "../../../errors/normalize.js";
|
|
12
|
-
import { useToast } from "../../../ui/index.js";
|
|
12
|
+
import { useToast, TextLink } from "../../../ui/index.js";
|
|
13
|
+
import { ROUTES } from "../../../next/routing/route-map.js";
|
|
13
14
|
async function loadStoreOptions(query, page) {
|
|
14
15
|
const params = new URLSearchParams({ page: String(page), pageSize: "25" });
|
|
15
16
|
if (query)
|
|
@@ -105,5 +106,5 @@ export function AdminFulfillmentView({ initialStoreId, initialStoreName, }) {
|
|
|
105
106
|
setStoreId(null);
|
|
106
107
|
setOrders([]);
|
|
107
108
|
}, children: "Change Store" }))] }), !storeId && (_jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", color: "muted", children: "Select a store to view its fulfilment queue." }), _jsx(PaginatedSelect, { value: null, onChange: (v) => { if (v)
|
|
108
|
-
setStoreId(v); }, loadOptions: loadStoreOptions, placeholder: "Search stores\u2026", searchPlaceholder: "Type store name\u2026", noResultsText: "No stores found", ariaLabel: "Store" })] })), storeId && (_jsxs(Stack, { gap: "sm", children: [isLoading && (_jsx(Text, { size: "sm", color: "muted", children: "Loading orders\u2026" })), !isLoading && orders.length === 0 && (_jsx(Text, { color: "muted", children: "No orders in the fulfillment queue \u2014 great work!" })), orders.map((order) => (_jsxs(Stack, { surface: "card", padding: "sm", rounded: "md", gap: "xs", children: [_jsxs(Row, { align: "center", gap: "xs", wrap: true, children: [_jsxs(
|
|
109
|
+
setStoreId(v); }, loadOptions: loadStoreOptions, placeholder: "Search stores\u2026", searchPlaceholder: "Type store name\u2026", noResultsText: "No stores found", ariaLabel: "Store" })] })), storeId && (_jsxs(Stack, { gap: "sm", children: [isLoading && (_jsx(Text, { size: "sm", color: "muted", children: "Loading orders\u2026" })), !isLoading && orders.length === 0 && (_jsx(Text, { color: "muted", children: "No orders in the fulfillment queue \u2014 great work!" })), orders.map((order) => (_jsxs(Stack, { surface: "card", padding: "sm", rounded: "md", gap: "xs", children: [_jsxs(Row, { align: "center", gap: "xs", wrap: true, children: [_jsxs(TextLink, { href: String(ROUTES.ADMIN.ORDER_DETAIL(order.id)), size: "sm", weight: "medium", children: ["#", order.id] }), _jsx(Badge, { variant: statusBadgeVariant(order.status), children: order.status }), order.pickedAt && _jsx(Badge, { variant: "success", children: "Picked" }), order.packedAt && _jsx(Badge, { variant: "success", children: "Packed" })] }), _jsxs(Text, { size: "xs", color: "muted", children: [order.userName, order.items && order.items.length > 0 && (_jsxs(_Fragment, { children: [" \u00B7 ", order.items.map((i) => i.productTitle).join(", ")] }))] }), order.assignedWorkerId && (_jsxs(Text, { size: "xs", color: "muted", children: ["Assigned to: ", order.assignedWorkerId] })), _jsxs(Row, { gap: "xs", children: [!order.pickedAt && (_jsx(Button, { size: "sm", variant: "secondary", onClick: () => handleMarkPicked(order.id), isLoading: actionLoadingId === order.id + ":picked", children: "Mark Picked" })), order.pickedAt && !order.packedAt && (_jsx(Button, { size: "sm", variant: "secondary", onClick: () => handleMarkPacked(order.id), isLoading: actionLoadingId === order.id + ":packed", children: "Mark Packed" })), order.assignedWorkerId && (_jsx(Button, { size: "sm", variant: "secondary", onClick: () => handleUnassign(order.id), isLoading: actionLoadingId === order.id + ":unassign", children: "Unassign" }))] })] }, order.id)))] })), initialStoreName && !storeId && (_jsxs(Text, { size: "xs", color: "muted", children: ["Previously viewing: ", initialStoreName] }))] }));
|
|
109
110
|
}
|
|
@@ -52,7 +52,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
52
52
|
*/
|
|
53
53
|
import React, { useState } from "react";
|
|
54
54
|
import { sieveFilter, SIEVE_OP, sortBy, } from "@mohasinac/appkit/client";
|
|
55
|
-
import { FilterChipGroup, ListingLayout, Modal, RecordDetailModal, Row, RowActionMenu, Stack, Text, Button, } from "../../../ui/index.js";
|
|
55
|
+
import { FilterChipGroup, ListingLayout, Modal, RecordDetailModal, Row, RowActionMenu, Span, Stack, Text, Button, } from "../../../ui/index.js";
|
|
56
56
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints.js";
|
|
57
57
|
import { ADMIN_GATEWAY_EVENT_KIND_TABS, ADMIN_GATEWAY_EVENT_STATUS_TABS, } from "../constants/filter-tabs.js";
|
|
58
58
|
import { toRecordArray, toRelativeDate, toStringValue, } from "../hooks/useAdminListingData.js";
|
|
@@ -205,5 +205,5 @@ export function AdminGatewayEventsView({ children, ...props }) {
|
|
|
205
205
|
*/
|
|
206
206
|
metadata: detail && detail.payload && typeof detail.payload === "object"
|
|
207
207
|
? detail.payload
|
|
208
|
-
: undefined, footer: detail ? (_jsx(Button, { variant: "outline", size: "sm", onClick: () => setReopenId(toStringValue(detail.id, "")), children: "Reopen for redelivery" })) : undefined }), _jsx(Modal, { isOpen: reopenId !== null, onClose: () => setReopenId(null), title: "Reopen this event for redelivery", size: "sm", children: _jsxs(Stack, { gap: "md", children: [_jsxs(Text, { size: "sm", children: ["This clears the terminal flag and the attempt count so the inbox will ", _jsx("
|
|
208
|
+
: undefined, footer: detail ? (_jsx(Button, { variant: "outline", size: "sm", onClick: () => setReopenId(toStringValue(detail.id, "")), children: "Reopen for redelivery" })) : undefined }), _jsx(Modal, { isOpen: reopenId !== null, onClose: () => setReopenId(null), title: "Reopen this event for redelivery", size: "sm", children: _jsxs(Stack, { gap: "md", children: [_jsxs(Text, { size: "sm", children: ["This clears the terminal flag and the attempt count so the inbox will ", _jsx(Span, { weight: "semibold", children: "accept" }), " the next delivery of this event instead of refusing it as a duplicate."] }), _jsx(Row, { surface: "warning-surface", padding: "sm", rounded: "default", children: _jsxs(Text, { size: "sm", color: "warning", children: ["It does not reprocess anything by itself. Nothing outside the webhook route knows how to handle an event, so after this you still need to press ", _jsx(Span, { weight: "semibold", children: "Resend" }), " on this delivery in the gateway dashboard \u2014 or wait for the gateway\u2019s own retry."] }) }), _jsxs(Row, { justify: "end", gap: "sm", children: [_jsx(Button, { variant: "ghost", onClick: () => setReopenId(null), disabled: busy, children: "Cancel" }), _jsx(Button, { variant: "primary", isLoading: busy, disabled: busy, onClick: () => reopen(reopenId), children: "Reopen" })] })] }) })] }));
|
|
209
209
|
}
|
|
@@ -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({
|
|
@@ -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;
|