@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
|
@@ -37,6 +37,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
37
37
|
*/
|
|
38
38
|
import React, { useCallback, useState } from "react";
|
|
39
39
|
import { Badge, ConfirmDeleteModal, RowActionMenu, Span, Text } from "../../../ui/index.js";
|
|
40
|
+
import { apiClient } from "../../../http/index.js";
|
|
40
41
|
import { useEntityDelete } from "../../../react/hooks/useEntityDelete.js";
|
|
41
42
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints.js";
|
|
42
43
|
import { ACTIONS } from "../../../_internal/shared/actions/action-registry.js";
|
|
@@ -46,6 +47,7 @@ import { PRODUCT_FIELDS } from "../../../constants/field-names.js";
|
|
|
46
47
|
import { SIEVE_OP, sieveFilter } from "../../../utils/sieve-builder.js";
|
|
47
48
|
import { pluginFor } from "../../../_internal/shared/listing-types/_registry.js";
|
|
48
49
|
import { toCurrency, toRecordArray, toRelativeDate, toStringValue, } from "../../admin/hooks/useAdminListingData.js";
|
|
50
|
+
import { useOptimisticRowFlag } from "../../admin/hooks/useOptimisticRowFlag.js";
|
|
49
51
|
import { DataListingView } from "../../admin/components/DataListingView.js";
|
|
50
52
|
import { ROW_ACTION_META, SELLER_BULK_ACTIONS } from "../../products/constants/action-defs.js";
|
|
51
53
|
import { useAvailabilityScope } from "../../products/hooks/useAvailabilityScope.js";
|
|
@@ -204,6 +206,17 @@ export function SellerListingTypeView({ type, onCreateClick, onEditClick, onDele
|
|
|
204
206
|
await performDelete(id);
|
|
205
207
|
setDeleteTargetId(null);
|
|
206
208
|
}, [performDelete]);
|
|
209
|
+
/*
|
|
210
|
+
* Optimistic status, via the shared hook — see its header for why a
|
|
211
|
+
* rollback must DELETE the override key rather than write back a captured
|
|
212
|
+
* value, and why the key is cleared on success too.
|
|
213
|
+
*/
|
|
214
|
+
const statusFlag = useOptimisticRowFlag({
|
|
215
|
+
mutate: (id, next) => apiClient.patch(SELLER_ENDPOINTS.PRODUCT_BY_ID(id), { status: next }),
|
|
216
|
+
invalidate: [["seller", plugin.tabSlug]],
|
|
217
|
+
successMessage: (next) => next === "published" ? "Listing published." : "Listing unpublished.",
|
|
218
|
+
errorMessage: "Could not change that listing's status.",
|
|
219
|
+
});
|
|
207
220
|
const handleEdit = useCallback((id) => {
|
|
208
221
|
if (onEditClick)
|
|
209
222
|
onEditClick(id);
|
|
@@ -233,7 +246,15 @@ export function SellerListingTypeView({ type, onCreateClick, onEditClick, onDele
|
|
|
233
246
|
{
|
|
234
247
|
key: "status",
|
|
235
248
|
header: "Status",
|
|
236
|
-
|
|
249
|
+
/*
|
|
250
|
+
* Reads the optimistic override so the badge and the row action agree
|
|
251
|
+
* the instant one is used — otherwise the menu would say "Unpublish"
|
|
252
|
+
* while the badge beside it still said published, until the refetch.
|
|
253
|
+
*/
|
|
254
|
+
render: (row) => {
|
|
255
|
+
const status = statusFlag.resolve(row.id, row.status);
|
|
256
|
+
return (_jsx(Badge, { variant: status === "active" || status === "published" ? "active" : "inactive", size: "xs", className: "capitalize", children: status }));
|
|
257
|
+
},
|
|
237
258
|
},
|
|
238
259
|
textCell("createdAt", spec.createdHeader ?? "Created"),
|
|
239
260
|
];
|
|
@@ -291,15 +312,40 @@ export function SellerListingTypeView({ type, onCreateClick, onEditClick, onDele
|
|
|
291
312
|
},
|
|
292
313
|
}))
|
|
293
314
|
: undefined,
|
|
294
|
-
renderRowActions: (row) =>
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
label: ACTIONS.STORE["
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
315
|
+
renderRowActions: (row) => {
|
|
316
|
+
const isPublished = statusFlag.resolve(row.id, row.status) === "published";
|
|
317
|
+
return (_jsx(RowActionMenu, { actions: [
|
|
318
|
+
{ label: ACTIONS.STORE["edit-listing"].label, onClick: () => handleEdit(row.id) },
|
|
319
|
+
/*
|
|
320
|
+
* 🛑 This one entry lights up SIX seller pages — art, classified,
|
|
321
|
+
* digital codes, live, spares and stickers are each a ~25-line
|
|
322
|
+
* wrapper around this component.
|
|
323
|
+
*
|
|
324
|
+
* `status` was a read-only Badge on all of them, so changing one
|
|
325
|
+
* listing from published to draft meant opening the full editor,
|
|
326
|
+
* even though `PATCH /api/store/products/[id]` has always taken
|
|
327
|
+
* `status` and SellerProductsView already drives that exact call.
|
|
328
|
+
*
|
|
329
|
+
* `ACTIONS.STORE["publish-listing"]` / `["unpublish-listing"]`
|
|
330
|
+
* were defined with ZERO call sites — this is what finally wires
|
|
331
|
+
* them, rather than reinventing the labels inline.
|
|
332
|
+
*/
|
|
333
|
+
{
|
|
334
|
+
label: isPublished
|
|
335
|
+
? ACTIONS.STORE["unpublish-listing"].label
|
|
336
|
+
: ACTIONS.STORE["publish-listing"].label,
|
|
337
|
+
separator: true,
|
|
338
|
+
disabled: statusFlag.pendingId === row.id,
|
|
339
|
+
onClick: () => { void statusFlag.set(row.id, isPublished ? "draft" : "published"); },
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
label: ACTIONS.STORE["delete-listing"].label,
|
|
343
|
+
destructive: true,
|
|
344
|
+
onClick: () => setDeleteTargetId(row.id),
|
|
345
|
+
disabled: deletingId === row.id,
|
|
346
|
+
},
|
|
347
|
+
] }));
|
|
348
|
+
},
|
|
303
349
|
};
|
|
304
350
|
return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: `Delete ${spec.deleteLabel}`, message: `Are you sure you want to delete this ${spec.deleteLabel.toLowerCase()}? This cannot be undone.`, onConfirm: () => handleDelete(deleteTargetId), onClose: () => setDeleteTargetId(null), isDeleting: deletingId === deleteTargetId }))] }));
|
|
305
351
|
}
|
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { formatPhysicalLocation } from "../../../utils/physical-location.js";
|
|
4
4
|
import { OrderAddonBadges } from "../../orders/components/OrderAddonBadges.js";
|
|
5
|
+
import { OrderProvenanceCard } from "../../orders/components/OrderProvenanceCard.js";
|
|
6
|
+
import { groupOrderItemsByLine } from "../../orders/utils/bundle-grouping.js";
|
|
5
7
|
import { normalizeError } from "../../../errors/normalize.js";
|
|
8
|
+
// The defining module, not a barrel (Root Cause #18). Maps a server error CODE
|
|
9
|
+
// to user-facing copy; it can never return server text, which is the point.
|
|
10
|
+
import { toUserMessage } from "../../../errors/error-display-map.js";
|
|
6
11
|
import { Row, SIEVE_OP, sieveFilter } from "@mohasinac/appkit/client";
|
|
7
12
|
import { sortBy } from "@mohasinac/appkit/client";
|
|
8
13
|
import React, { useState, useCallback } from "react";
|
|
@@ -12,6 +17,7 @@ import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints.js";
|
|
|
12
17
|
import { Badge, Button, Div, FilterChipGroup, SideDrawer, Span, Stack, Text, useToast } from "../../../ui/index.js";
|
|
13
18
|
import { SELLER_ORDER_STATUS_TABS } from "../../admin/constants/filter-tabs.js";
|
|
14
19
|
import { useOrderScope } from "../../orders/components/OrderScopeTabs.js";
|
|
20
|
+
import { ORDER_LANE_TABS } from "../../orders/constants/order-lane-tabs.js";
|
|
15
21
|
import { OrderStatusValues } from "../../orders/schemas/firestore.js";
|
|
16
22
|
import { isManualPaymentMethod } from "../../orders/constants/payment-window.js";
|
|
17
23
|
import { ACTIONS } from "../../../_internal/shared/actions/action-registry.js";
|
|
@@ -60,6 +66,14 @@ const UPDATE_STATUS_OPTIONS = [
|
|
|
60
66
|
{ value: "delivered", label: "Delivered" },
|
|
61
67
|
{ value: "cancelled", label: "Cancelled" },
|
|
62
68
|
];
|
|
69
|
+
/**
|
|
70
|
+
* One item row. Extracted verbatim when grouping landed so the single and
|
|
71
|
+
* grouped paths cannot render differently — two copies of this markup is how
|
|
72
|
+
* the field-name bug below would come back on one path only.
|
|
73
|
+
*/
|
|
74
|
+
function sellerOrderItemRow(item, key) {
|
|
75
|
+
return (_jsxs(Row, { paddingY: "y-xs-tall", padding: "x-sm", align: "center", justify: "between", gap: "3", children: [_jsxs(Row, { align: "center", gap: "sm", className: "min-w-0", children: [_jsx(Div, { className: "h-10 w-10 shrink-0", rounded: "md", overflow: "hidden", children: _jsx(MediaImage, { src: item.image, alt: item.title ?? "Order item", size: "thumbnail" }) }), _jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { size: "sm", className: "truncate", weight: "medium", children: item.productTitle ?? item.title ?? item.productId ?? "Item" }), _jsxs(Text, { size: "xs", className: "text-[var(--appkit-color-text-muted)]", children: ["Qty: ", item.quantity ?? 1] })] })] }), _jsx(Text, { size: "sm", className: "shrink-0", weight: "medium", children: toCurrency(item.totalPrice ?? item.unitPrice ?? item.price ?? 0) })] }, key));
|
|
76
|
+
}
|
|
63
77
|
/**
|
|
64
78
|
* Manual-payment state for the seller's read-only badge. Derived from the same
|
|
65
79
|
* two fields the admin queue uses (`paymentProofUrl` + `paymentReviewOutcome`)
|
|
@@ -198,8 +212,33 @@ export function SellerOrderDetailPanel({ orderId, apiBase, onClose, }) {
|
|
|
198
212
|
body: JSON.stringify(payload),
|
|
199
213
|
});
|
|
200
214
|
if (!res.ok) {
|
|
201
|
-
const d = await res.json().catch(() => ({}));
|
|
202
|
-
|
|
215
|
+
const d = (await res.json().catch(() => ({})));
|
|
216
|
+
/*
|
|
217
|
+
* 🛑 FIELD ERRORS GO ON THE FIELD. The server already sends them.
|
|
218
|
+
*
|
|
219
|
+
* `mapToHttpError` answers a rejected body with
|
|
220
|
+
* `{ status: 400, code: VALIDATION_FAILED, message: "Validation
|
|
221
|
+
* failed", issues }` — the per-field detail is ON THE WIRE. This
|
|
222
|
+
* handler used to throw `d.error` and render it in the banner below,
|
|
223
|
+
* so the seller saw a bare "Validation failed" with nothing marked and
|
|
224
|
+
* no way to tell WHICH field was wrong. Rule #9 §6.
|
|
225
|
+
*
|
|
226
|
+
* `applyZodIssues` keys by the full dotted path, so a nested field
|
|
227
|
+
* lands on itself rather than collapsing onto `issue.path[0]`.
|
|
228
|
+
*/
|
|
229
|
+
if (Array.isArray(d.issues) && d.issues.length > 0) {
|
|
230
|
+
applyZodIssues(d.issues, form.setFieldError);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
/*
|
|
234
|
+
* 🛑 NEVER the server's own message, and this is not hypothetical.
|
|
235
|
+
* `d.error` is server text; rendering it is how a Node
|
|
236
|
+
* `MODULE_NOT_FOUND` with a `/var/task/.next/...` require stack was
|
|
237
|
+
* once shown inside a buyer's "Place your bid" modal (Root Cause #86).
|
|
238
|
+
* `toUserMessage` resolves through `errors.codes.*`, terminates at
|
|
239
|
+
* UNKNOWN, and cannot return server internals.
|
|
240
|
+
*/
|
|
241
|
+
throw new Error(toUserMessage(d.code));
|
|
203
242
|
}
|
|
204
243
|
const updated = await res.json();
|
|
205
244
|
const next = (updated?.data ?? updated);
|
|
@@ -217,8 +256,19 @@ export function SellerOrderDetailPanel({ orderId, apiBase, onClose, }) {
|
|
|
217
256
|
});
|
|
218
257
|
}
|
|
219
258
|
catch (err) {
|
|
220
|
-
|
|
221
|
-
|
|
259
|
+
/*
|
|
260
|
+
* `normalizeError`'s RESULT, not an `as Error` cast. The cast asserted a
|
|
261
|
+
* shape nothing checked, and the only reason it happened to work is that
|
|
262
|
+
* every throw above is one we construct — a rejected promise from `fetch`
|
|
263
|
+
* or a JSON parse failure is not an `Error` by that assertion's logic,
|
|
264
|
+
* it just happens to be one at runtime.
|
|
265
|
+
*
|
|
266
|
+
* What reaches the banner is now bounded: either `toUserMessage(code)`
|
|
267
|
+
* from the throw above (mapped copy, never server text) or a browser-level
|
|
268
|
+
* network message. Field-level problems never get here at all — they were
|
|
269
|
+
* routed to the fields by `applyZodIssues`.
|
|
270
|
+
*/
|
|
271
|
+
setSaveError(normalizeError(err).message);
|
|
222
272
|
}
|
|
223
273
|
finally {
|
|
224
274
|
setSaving(false);
|
|
@@ -249,21 +299,21 @@ export function SellerOrderDetailPanel({ orderId, apiBase, onClose, }) {
|
|
|
249
299
|
const addrLine = typeof rawAddr === "string" && rawAddr.trim()
|
|
250
300
|
? rawAddr.trim()
|
|
251
301
|
: [addr.addressLine1, addr.city, addr.state, addr.pincode].filter(Boolean).join(", ");
|
|
252
|
-
return (_jsxs(_Fragment, { children: [loading && (_jsx(Row, { align: "center", 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" }) })), fetchError && (_jsx(Div, { textSize: "sm", className: "mx-4 mt-4 border border-error/20", color: "error", surface: "danger-surface", padding: "inline", rounded: "lg", children: fetchError })), order && !loading && (
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
302
|
+
return (_jsxs(_Fragment, { children: [loading && (_jsx(Row, { align: "center", 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" }) })), fetchError && (_jsx(Div, { textSize: "sm", className: "mx-4 mt-4 border border-error/20", color: "error", surface: "danger-surface", padding: "inline", rounded: "lg", children: fetchError })), order && !loading && (_jsx(Stack, { gap: "none", children: _jsxs(Stack, { className: `flex-1 ${__O.yAuto}`, gap: "5", padding: "md", children: [_jsxs(Row, { align: "center", justify: "between", children: [_jsx(Badge, { variant: STATUS_BADGE_VARIANT[order.status ?? ""] ?? "default", children: order.status ?? "Unknown" }), _jsx(Text, { size: "sm", className: "text-[var(--appkit-color-text-muted)]", children: toRelativeDate(order.createdAt) })] }), _jsx(OrderProvenanceCard, { sourceContext: order.sourceContext, currency: order.currency }), (order.items ?? []).length > 0 && (_jsxs(Div, { children: [_jsx(Text, { size: "sm", className: "text-[var(--appkit-color-text)] mb-2", weight: "semibold", children: "Items" }), _jsx(Div, { className: "divide-y divide-[var(--appkit-color-border)] divide-[var(--appkit-color-border)] border border-[var(--appkit-color-border)]", rounded: "lg", children: groupOrderItemsByLine(order.items ?? []).map((group, gi) => group.kind === "single" ? (sellerOrderItemRow(group.item, `s-${group.index}`)) : (_jsxs(Div, { children: [_jsxs(Row, { paddingY: "y-xs", padding: "x-sm", align: "center", gap: "sm", surface: "muted", children: [_jsx(Text, { size: "xs", weight: "semibold", children: group.groupTitle ?? "Grouped purchase" }), _jsx(Text, { size: "xs", className: "text-[var(--appkit-color-text-muted)]", children: `${group.memberCount} ${group.memberCount === 1 ? "item" : "items"} · one line` })] }), _jsx(Div, { className: "pl-4", children: group.items.map(({ item, index }) => sellerOrderItemRow(item, `m-${index}`)) })] }, `g-${gi}`))) })] })), _jsx(OrderAddonBadges, { order: order, variant: "detail" }), order.giftWrapAddon && (_jsxs(Div, { className: "border border-[var(--appkit-color-primary-200)] dark:border-[var(--appkit-color-primary-800)]", surface: "subtle", padding: "inline", rounded: "lg", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "\uD83C\uDF81 Gift wrap requested" }), order.giftWrapMessage && (_jsxs(Text, { size: "sm", className: "mt-1 text-[var(--appkit-color-text-muted)]", children: ["\u201C", order.giftWrapMessage, "\u201D"] }))] })), _jsxs(Row, { surface: "muted", padding: "inline", align: "center", justify: "between", rounded: "lg", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "Total" }), _jsx(Text, { size: "sm", className: "text-[var(--appkit-color-primary)]", weight: "bold", children: toCurrency(order.totalAmount ?? order.totalPrice ?? 0) })] }), addrLine && (_jsxs(Div, { children: [_jsx(Text, { size: "sm", className: "mb-1", weight: "semibold", children: "Shipping address" }), _jsx(Text, { size: "sm", className: "text-[var(--appkit-color-text-muted)]", children: [String(addr.fullName ?? ""), addrLine].filter(Boolean).join(" · ") })] })), order.paymentMethod && (_jsxs(Div, { children: [_jsxs(Row, { align: "center", justify: "between", className: "mb-1", gap: "3", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "Payment" }), isManualPaymentMethod(order.paymentMethod) && (_jsx(Badge, { variant: sellerPaymentBadge(order).variant, children: sellerPaymentBadge(order).label }))] }), _jsx(Text, { size: "sm", className: "text-[var(--appkit-color-text-muted)]", transform: "capitalize", children: order.paymentMethod }), isManualPaymentMethod(order.paymentMethod) && order.paymentTransactionId && (_jsxs(Text, { size: "xs", color: "muted", className: "mt-1", children: ["UTR: ", order.paymentTransactionId] }))] })), order.emiEnabled && (_jsxs(Div, { className: "border-t border-[var(--appkit-color-border)]", padding: "t-md", children: [_jsxs(Row, { align: "center", justify: "between", className: "mb-2", children: [_jsxs(Text, { size: "sm", weight: "semibold", children: ["EMI plan ", order.emiTenureMonths ? `· ${order.emiTenureMonths} months` : ""] }), _jsx(Badge, { variant: order.emiComplete ? "success" : "warning", children: order.emiComplete ? "Fully paid" : "In progress" })] }), _jsxs(Row, { align: "center", justify: "between", className: "mb-2", children: [_jsx(Text, { size: "xs", color: "muted", children: "Token collected" }), _jsx(Text, { size: "xs", weight: "medium", children: toCurrency(order.emiTokenAmount ?? 0) })] }), _jsxs(Row, { align: "center", justify: "between", className: "mb-3", children: [_jsx(Text, { size: "xs", color: "muted", children: "Remaining balance" }), _jsx(Text, { size: "xs", weight: "medium", children: toCurrency(order.emiRemainingBalance ?? 0) })] }), _jsx(Div, { className: "divide-y divide-[var(--appkit-color-border)] border border-[var(--appkit-color-border)]", rounded: "lg", children: (order.emiInstallments ?? []).map((inst) => (_jsxs(Row, { paddingY: "y-xs-tall", padding: "x-sm", align: "center", justify: "between", gap: "3", children: [_jsxs(Div, { className: "min-w-0", children: [_jsxs(Text, { size: "sm", weight: "medium", children: ["Installment ", inst.index, " \u00B7 ", toCurrency(inst.amount)] }), _jsx(Text, { size: "xs", color: "muted", children: inst.status === "paid" && inst.paidAt
|
|
303
|
+
? `Paid ${toRelativeDate(inst.paidAt)}`
|
|
304
|
+
: inst.dueDate
|
|
305
|
+
? `Due ${toRelativeDate(inst.dueDate)}`
|
|
306
|
+
: "" })] }), _jsxs(Row, { align: "center", gap: "sm", className: "shrink-0", children: [_jsx(Badge, { variant: EMI_INSTALLMENT_BADGE_VARIANT[inst.status] ?? "default", children: inst.status }), inst.status !== "paid" && (_jsx(Button, { action: ACTIONS.STORE["mark-installment-paid"], size: "sm", variant: "outline", isLoading: markingPaidIndex === inst.index, disabled: markingPaidIndex !== null, onClick: () => handleMarkInstallmentPaid(inst.index), children: "Mark paid" }))] })] }, inst.index))) }), emiError && (_jsx(Div, { textSize: "xs", className: "mt-2 border border-error/20", color: "error", surface: "danger-surface", padding: "inlineSm", rounded: "lg", children: emiError }))] })), _jsxs(Stack, { className: "border-t border-[var(--appkit-color-border)]", padding: "t-md", gap: "3", children: [_jsxs(FormShellContext.Provider, { value: form.shellCtx, children: [_jsx(FormErrorSummary, {}), _jsx(SectionForm, { sections: sections, values: draft, onChange: (partial) => setDraft((d) => ({ ...d, ...partial })), onSubmit: () => {
|
|
307
|
+
// SectionForm scrolls to the first erroring section and then
|
|
308
|
+
// submits regardless, so the guard lives here.
|
|
309
|
+
form.clearErrors();
|
|
310
|
+
const parsed = sellerOrderUpdateSchema.safeParse(visibleValues(sellerOrderUpdateSchema, draft));
|
|
311
|
+
if (!parsed.success) {
|
|
312
|
+
applyZodIssues(parsed.error.issues, form.setFieldError);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
void handleSave();
|
|
316
|
+
}, onValidationChange: () => form.validate(draft), schema: sellerOrderUpdateSchema, openIds: nav.openIds, onOpenChange: nav.setOpenIds, submitLabel: "Save", cancelLabel: "Close", onCancel: onClose, isLoading: saving })] }), saveError && (_jsx(Div, { textSize: "xs", className: "border border-error/20", color: "error", surface: "danger-surface", padding: "inlineSm", rounded: "lg", children: saveError }))] })] }) }))] }));
|
|
267
317
|
}
|
|
268
318
|
function OrderDetailDrawer({ orderId, apiBase, onClose, }) {
|
|
269
319
|
return (_jsx(SideDrawer, { isOpen: true, title: `Order ${orderId}`, onClose: onClose, children: _jsx(SellerOrderDetailPanel, { orderId: orderId, apiBase: apiBase, onClose: onClose }) }));
|
|
@@ -343,9 +393,7 @@ export function SellerOrdersView({ orderDetailApiBase = SELLER_ENDPOINTS.ORDERS,
|
|
|
343
393
|
{
|
|
344
394
|
key: "primary",
|
|
345
395
|
header: "Order",
|
|
346
|
-
render: (row) => (_jsxs(Row, { gap: "sm", align: "center", className: "min-w-0", children: [_jsx(Div, { className: "h-10 w-10 shrink-0", rounded: "md", overflow: "hidden", children: _jsx(MediaImage, { src: row.itemImage, alt: row.itemTitle ?? "Order item", size: "thumbnail" }) }), _jsxs(Stack, { gap: "none", className: "min-w-0", children: [_jsx(Text, { className: "truncate", size: "sm", weight: "semibold", children: row.
|
|
347
|
-
? `${row.itemTitle}${row.itemCount > 1 ? ` +${row.itemCount - 1} more` : ""}`
|
|
348
|
-
: row.primary }), _jsxs(Text, { size: "xs", color: "muted", children: [row.buyerName, " \u00B7 ", row.itemCount, " item", row.itemCount !== 1 ? "s" : ""] })] })] })),
|
|
396
|
+
render: (row) => (_jsxs(Row, { gap: "sm", align: "center", className: "min-w-0", children: [_jsx(Div, { className: "h-10 w-10 shrink-0", rounded: "md", overflow: "hidden", children: _jsx(MediaImage, { src: row.itemImage, alt: row.itemTitle ?? "Order item", size: "thumbnail" }) }), _jsxs(Stack, { gap: "none", className: "min-w-0", children: [_jsx(Text, { className: "truncate", size: "sm", weight: "semibold", children: row.primary }), _jsxs(Text, { size: "xs", color: "muted", children: [row.buyerName, " \u00B7 ", row.itemCount, " item", row.itemCount !== 1 ? "s" : ""] })] })] })),
|
|
349
397
|
},
|
|
350
398
|
{
|
|
351
399
|
key: "totalAmount",
|
|
@@ -392,7 +440,7 @@ export function SellerOrdersView({ orderDetailApiBase = SELLER_ENDPOINTS.ORDERS,
|
|
|
392
440
|
commit: "debounce",
|
|
393
441
|
},
|
|
394
442
|
emptyLabel: "No orders yet",
|
|
395
|
-
filterKeys: ["status"],
|
|
443
|
+
filterKeys: ["status", "orderType"],
|
|
396
444
|
defaultSort: DEFAULT_SORT,
|
|
397
445
|
queryKey: ["seller", "orders", "listing"],
|
|
398
446
|
endpoint: SELLER_ENDPOINTS.ORDERS,
|
|
@@ -425,10 +473,45 @@ export function SellerOrdersView({ orderDetailApiBase = SELLER_ENDPOINTS.ORDERS,
|
|
|
425
473
|
* below as `itemTitle`.
|
|
426
474
|
*/
|
|
427
475
|
primary: (() => {
|
|
428
|
-
|
|
476
|
+
/*
|
|
477
|
+
* Counted in LINES, not item rows, and a grouped line is named by
|
|
478
|
+
* its own title.
|
|
479
|
+
*
|
|
480
|
+
* This was `items[0].productTitle` + `itemsArr.length - 1`, so a
|
|
481
|
+
* four-member bundle read "Dranzer S +3 more" — an arbitrary
|
|
482
|
+
* member, implying four separate purchases. Grouping through the
|
|
483
|
+
* same helper the drawer now uses makes it "Starter Bundle", and a
|
|
484
|
+
* bundle beside one standalone item "+1 more".
|
|
485
|
+
*/
|
|
486
|
+
const groups = groupOrderItemsByLine(itemsArr
|
|
487
|
+
.filter((entry) => Boolean(entry) && typeof entry === "object")
|
|
488
|
+
/*
|
|
489
|
+
* Narrowed, not cast: `Record<string, unknown>` does NOT
|
|
490
|
+
* satisfy `OrderItemForLineGrouping` — its `groupSlug` is
|
|
491
|
+
* `unknown`, which is not assignable to `string | undefined`.
|
|
492
|
+
* A cast would compile and then group on whatever junk a bad
|
|
493
|
+
* document carried.
|
|
494
|
+
*/
|
|
495
|
+
.map((e) => ({
|
|
496
|
+
productTitle: typeof e.productTitle === "string" ? e.productTitle : undefined,
|
|
497
|
+
groupSlug: typeof e.groupSlug === "string" ? e.groupSlug : undefined,
|
|
498
|
+
groupTitle: typeof e.groupTitle === "string" ? e.groupTitle : undefined,
|
|
499
|
+
bundleCategorySlug: typeof e.bundleCategorySlug === "string" ? e.bundleCategorySlug : undefined,
|
|
500
|
+
bundleProductIds: Array.isArray(e.bundleProductIds)
|
|
501
|
+
? e.bundleProductIds.filter((v) => typeof v === "string")
|
|
502
|
+
: undefined,
|
|
503
|
+
})));
|
|
504
|
+
const head = groups[0];
|
|
505
|
+
const extra = Math.max(0, groups.length - 1);
|
|
506
|
+
const title = head === undefined
|
|
507
|
+
? typeof firstItem.productTitle === "string"
|
|
508
|
+
? firstItem.productTitle
|
|
509
|
+
: ""
|
|
510
|
+
: head.kind === "bundle"
|
|
511
|
+
? (head.groupTitle ?? "Grouped purchase")
|
|
512
|
+
: (head.item.productTitle ?? "");
|
|
429
513
|
if (!title)
|
|
430
514
|
return `Order ${toStringValue(item.id, "-")}`;
|
|
431
|
-
const extra = itemsArr.length - 1;
|
|
432
515
|
return extra > 0 ? `${title} +${extra} more` : title;
|
|
433
516
|
})(),
|
|
434
517
|
/*
|
|
@@ -456,10 +539,29 @@ export function SellerOrdersView({ orderDetailApiBase = SELLER_ENDPOINTS.ORDERS,
|
|
|
456
539
|
// The scope narrows; the status chip drills down inside it. Both are
|
|
457
540
|
// emitted — an explicit status always wins, since picking "Delivered"
|
|
458
541
|
// while sitting on Active should show delivered orders, not nothing.
|
|
459
|
-
|
|
542
|
+
/*
|
|
543
|
+
* Two independent axes, joined. The lane answers "how was this won", the
|
|
544
|
+
* status answers "where is it now" — a seller asking "which of my auction
|
|
545
|
+
* wins are still unshipped" should not have to choose between them.
|
|
546
|
+
*
|
|
547
|
+
* 🛑 `orderType` is a registered SELLER_SIEVE_FIELD as of this change. It
|
|
548
|
+
* was not, and the failure would have been invisible: `throwExceptions` is
|
|
549
|
+
* false, so an unallowlisted field drops its clause and the chip would have
|
|
550
|
+
* returned the seller's whole order list while looking like it filtered
|
|
551
|
+
* (Root Cause #62). `standard` is stripped from the query server-side and
|
|
552
|
+
* refined in memory — see `/api/store/orders`.
|
|
553
|
+
*/
|
|
554
|
+
buildFilters: (state) => [
|
|
555
|
+
state.status && state.status !== "All"
|
|
556
|
+
? sieveFilter("status", SIEVE_OP.EQ, state.status)
|
|
557
|
+
: null,
|
|
558
|
+
state.orderType ? sieveFilter("orderType", SIEVE_OP.EQ, state.orderType) : null,
|
|
559
|
+
]
|
|
560
|
+
.filter(Boolean)
|
|
561
|
+
.join(",") || undefined,
|
|
460
562
|
buildExtraParams: () => orderScope.extraParams,
|
|
461
563
|
renderAboveContent: orderScope.renderAboveContent,
|
|
462
|
-
renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) })),
|
|
564
|
+
renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(_Fragment, { children: [_jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }), _jsx(FilterChipGroup, { label: "Type", tabs: ORDER_LANE_TABS, value: pendingFilters.orderType ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, orderType: id })) })] })),
|
|
463
565
|
buildBulkActions: (selection) => {
|
|
464
566
|
const handlePrintPackingSlips = () => {
|
|
465
567
|
const ids = selection.selectedIds.join(",");
|
|
@@ -8,6 +8,8 @@ import { Badge, ConfirmDeleteModal, Div, Row, RowActionMenu, Span, Text, useToas
|
|
|
8
8
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints.js";
|
|
9
9
|
import { ROUTES } from "../../../constants/index.js";
|
|
10
10
|
import { toRecordArray, toStringValue } from "../hooks/useSellerListingData.js";
|
|
11
|
+
import { useOptimisticRowFlag } from "../../admin/hooks/useOptimisticRowFlag.js";
|
|
12
|
+
import { apiClient } from "../../../http/index.js";
|
|
11
13
|
import { DataListingView } from "../../admin/components/DataListingView.js";
|
|
12
14
|
const CLS_TYPE_PILL = "inline-flex items-center rounded-full px-[var(--appkit-space-2)] py-[var(--appkit-space-0-5)] text-[length:var(--appkit-text-xs)] font-semibold uppercase tracking-wide bg-violet-100 text-violet-700 dark:bg-violet-900/40 dark:text-violet-300";
|
|
13
15
|
const DEFAULT_SORT = "-createdAt";
|
|
@@ -42,6 +44,22 @@ const COLUMNS = [
|
|
|
42
44
|
},
|
|
43
45
|
];
|
|
44
46
|
export function SellerPayoutMethodsView({ onCreateClick, onEditClick, onDelete, onSetDefault, }) {
|
|
47
|
+
/*
|
|
48
|
+
* 🛑 `isActive` was a READ-ONLY badge here, and the update schema was built
|
|
49
|
+
* to take it on its own — shipping-config's even says so in a comment: "a
|
|
50
|
+
* PATCH may legitimately carry only `isActive`". Nothing in the client had
|
|
51
|
+
* ever sent one, so flipping one boolean meant a full-editor round trip.
|
|
52
|
+
*
|
|
53
|
+
* The optimistic/rollback logic lives in the hook because eight listings
|
|
54
|
+
* grew this control at once; see its header for why rollback must DELETE
|
|
55
|
+
* the override key rather than write back a captured value.
|
|
56
|
+
*/
|
|
57
|
+
const activeFlag = useOptimisticRowFlag({
|
|
58
|
+
mutate: (id, next) => apiClient.patch(SELLER_ENDPOINTS.PAYOUT_METHOD_BY_ID(id), { isActive: next }),
|
|
59
|
+
invalidate: [["seller", "payout-methods", "listing"]],
|
|
60
|
+
successMessage: (next) => (next ? "Payout method activated." : "Payout method deactivated."),
|
|
61
|
+
errorMessage: "Could not change that payout method's status.",
|
|
62
|
+
});
|
|
45
63
|
const [deleteTargetId, setDeleteTargetId] = useState(null);
|
|
46
64
|
const { deletingId, handleDelete: performDelete } = useEntityDelete({
|
|
47
65
|
endpoint: SELLER_ENDPOINTS.PAYOUT_METHOD_BY_ID,
|
|
@@ -114,13 +132,27 @@ export function SellerPayoutMethodsView({ onCreateClick, onEditClick, onDelete,
|
|
|
114
132
|
label: String(item.label ?? ""),
|
|
115
133
|
type: String(item.type ?? ""),
|
|
116
134
|
isDefault: Boolean(item.isDefault),
|
|
117
|
-
|
|
135
|
+
// Resolved through the pending override so the Status badge and the
|
|
136
|
+
// row toggle cannot disagree between the click and the refetch.
|
|
137
|
+
isActive: activeFlag.resolve(toStringValue(item.id, `pm-${index}`), Boolean(item.isActive)),
|
|
118
138
|
maskedIdentifier: getMaskedIdentifier(item),
|
|
119
139
|
})),
|
|
120
140
|
getTotal: (response, mappedRows) => (typeof response.total === "number" ? response.total : mappedRows.length),
|
|
121
141
|
buildFilters: () => undefined,
|
|
122
142
|
primaryAction: { label: "New Method", onClick: handleCreate },
|
|
123
143
|
renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
|
|
144
|
+
/*
|
|
145
|
+
* 🛑 `isActive` was a read-only badge and the update schema was
|
|
146
|
+
* built to accept it alone. A menu entry rather than a switch here,
|
|
147
|
+
* to match the other actions in this menu — the menu is already
|
|
148
|
+
* click-stopped in all three renderers.
|
|
149
|
+
*/
|
|
150
|
+
{
|
|
151
|
+
label: row.isActive ? "Deactivate" : "Activate",
|
|
152
|
+
separator: true,
|
|
153
|
+
disabled: activeFlag.pendingId === row.id,
|
|
154
|
+
onClick: () => { void activeFlag.set(row.id, !row.isActive); },
|
|
155
|
+
},
|
|
124
156
|
...(!row.isDefault
|
|
125
157
|
? [{ label: "Set as Default", disabled: settingDefaultId === row.id, onClick: () => handleSetDefault(row.id) }]
|
|
126
158
|
: []),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { Alert, Badge, Checkbox, Div, FormField, FormGroup, Heading, Label, Row, Span, Stack, Text, Toggle } from "../../../ui/index.js";
|
|
@@ -8,6 +8,7 @@ import { FormShellContext, useFormShellState, applyZodIssues, FormErrorSummary }
|
|
|
8
8
|
import { SectionForm, useSectionFormNav, annotate } from "../../shell/index.js";
|
|
9
9
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints.js";
|
|
10
10
|
import { normalizeError } from "../../../errors/normalize.js";
|
|
11
|
+
import { toUserMessage } from "../../../errors/error-display-map.js";
|
|
11
12
|
const __P = {
|
|
12
13
|
p3: "p-[var(--appkit-space-3)]",
|
|
13
14
|
};
|
|
@@ -153,6 +154,20 @@ const DEFAULT_DRAFT = {
|
|
|
153
154
|
*/
|
|
154
155
|
advancedListingTypesEnabled: false,
|
|
155
156
|
};
|
|
157
|
+
/**
|
|
158
|
+
* One radio group for a single-value field, with ONE error message.
|
|
159
|
+
*
|
|
160
|
+
* Extracted because the payout-method and account-type groups were the same
|
|
161
|
+
* eleven lines twice, and because adding the error handling to both tipped
|
|
162
|
+
* this view past `audit-code-quality`'s component-size threshold. The error
|
|
163
|
+
* placement is the part worth sharing: `aria-invalid` goes on every radio so
|
|
164
|
+
* assistive tech marks the whole group, but the message renders ONCE
|
|
165
|
+
* underneath — the field is one value, so an `error` per radio would print
|
|
166
|
+
* and announce the same sentence for every option.
|
|
167
|
+
*/
|
|
168
|
+
function RadioFieldGroup({ name, value, options, error, disabled, onSelect, renderOption, layout: Layout, }) {
|
|
169
|
+
return (_jsxs(_Fragment, { children: [_jsx(Layout, { gap: "sm", children: options.map((option) => (_jsxs(Label, { layout: "flex", gap: "md", className: "cursor-pointer", children: [_jsx(Checkbox, { bare: true, type: "radio", name: name, value: option, checked: value === option, onChange: () => onSelect(option), className: "accent-[var(--appkit-color-primary)]", disabled: disabled, "aria-invalid": error ? "true" : undefined }), renderOption(option)] }, option))) }), error && (_jsx(Text, { size: "sm", variant: "error", role: "alert", children: error }))] }));
|
|
170
|
+
}
|
|
156
171
|
export function SellerPayoutSettingsView({ apiBase = SELLER_ENDPOINTS.PAYOUT_SETTINGS }) {
|
|
157
172
|
const [draft, setDraft] = useState(DEFAULT_DRAFT);
|
|
158
173
|
const [current, setCurrent] = useState(null);
|
|
@@ -253,7 +268,22 @@ export function SellerPayoutSettingsView({ apiBase = SELLER_ENDPOINTS.PAYOUT_SET
|
|
|
253
268
|
if (Array.isArray(json?.issues) && json.issues.length > 0) {
|
|
254
269
|
applyZodIssues(json.issues, setFieldError);
|
|
255
270
|
}
|
|
256
|
-
|
|
271
|
+
/*
|
|
272
|
+
* `json.error` is the SERVER's sentence — never shown to a user
|
|
273
|
+
* (Rule #9.6). Resolve the stable `code` instead; `toUserMessage`
|
|
274
|
+
* terminates in this fallback and can never return server text.
|
|
275
|
+
*
|
|
276
|
+
* Only a banner when the issues above attached nothing: if they did,
|
|
277
|
+
* the fields now carry the detail and a banner repeating a vaguer
|
|
278
|
+
* version of it is noise.
|
|
279
|
+
*/
|
|
280
|
+
const attached = Array.isArray(json?.issues) &&
|
|
281
|
+
json.issues.some((i) => i?.path?.length);
|
|
282
|
+
if (!attached) {
|
|
283
|
+
setError(toUserMessage(json?.code, undefined, {
|
|
284
|
+
fallback: "We couldn't save your payout settings.",
|
|
285
|
+
}));
|
|
286
|
+
}
|
|
257
287
|
return;
|
|
258
288
|
}
|
|
259
289
|
clearErrors();
|
|
@@ -263,8 +293,17 @@ export function SellerPayoutSettingsView({ apiBase = SELLER_ENDPOINTS.PAYOUT_SET
|
|
|
263
293
|
setDraft((prev) => ({ ...prev, accountNumber: "" }));
|
|
264
294
|
}
|
|
265
295
|
catch (err) {
|
|
266
|
-
|
|
267
|
-
|
|
296
|
+
/*
|
|
297
|
+
* `normalizeError` was already being called and its result DISCARDED,
|
|
298
|
+
* then the raw `.message` shown anyway — a thrown value's message is
|
|
299
|
+
* written for a developer, and this is the path a network failure or a
|
|
300
|
+
* bundler fault takes (Root Cause #86 rendered a require stack this
|
|
301
|
+
* way). Use the normalized code; the sentence is ours.
|
|
302
|
+
*/
|
|
303
|
+
const normalized = normalizeError(err);
|
|
304
|
+
setError(toUserMessage(normalized.code, undefined, {
|
|
305
|
+
fallback: "We couldn't save your payout settings. Please try again.",
|
|
306
|
+
}));
|
|
268
307
|
}
|
|
269
308
|
finally {
|
|
270
309
|
setSaving(false);
|
|
@@ -283,12 +322,12 @@ export function SellerPayoutSettingsView({ apiBase = SELLER_ENDPOINTS.PAYOUT_SET
|
|
|
283
322
|
required: true,
|
|
284
323
|
quick: true,
|
|
285
324
|
fields: ["method", "upiId", "accountHolderName", "accountNumber", "ifscCode", "bankName", "accountType"],
|
|
286
|
-
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Payout Method" }), current && (_jsx(Row, { className: "mb-2", align: "center", gap: "sm", children: _jsx(Badge, { variant: current.isConfigured ? "success" : "warning", children: current.isConfigured ? "Payout configured" : "Not configured" }) })), current?.isConfigured && (_jsx(Alert, { variant: "info", children: current.method === "upi"
|
|
325
|
+
render: ({ values, onChange, errors }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Payout Method" }), current && (_jsx(Row, { className: "mb-2", align: "center", gap: "sm", children: _jsx(Badge, { variant: current.isConfigured ? "success" : "warning", children: current.isConfigured ? "Payout configured" : "Not configured" }) })), current?.isConfigured && (_jsx(Alert, { variant: "info", children: current.method === "upi"
|
|
287
326
|
? `Current UPI: ${current.upiId}`
|
|
288
|
-
: `Current bank: ${current.bankAccount?.bankName ?? ""} — ••••${current.bankAccount?.accountNumberMasked?.slice(-4) ?? "••••"} (${current.bankAccount?.accountType})` })),
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
327
|
+
: `Current bank: ${current.bankAccount?.bankName ?? ""} — ••••${current.bankAccount?.accountNumberMasked?.slice(-4) ?? "••••"} (${current.bankAccount?.accountType})` })), _jsxs(Stack, { gap: "sm", children: [([
|
|
328
|
+
{ value: "upi", label: "UPI", desc: "Instant payouts via UPI VPA (e.g. name@upi)." },
|
|
329
|
+
{ value: "bank_transfer", label: "Bank Transfer", desc: "NEFT/RTGS to your bank account within 2–3 business days." },
|
|
330
|
+
]).map(({ value, label, desc }) => (_jsxs("label", { className: "flex items-center gap-[var(--appkit-space-3)] p-[var(--appkit-space-3)] rounded-lg border border-[var(--appkit-color-border)] cursor-pointer has-[:checked]:border-[var(--appkit-color-primary)] has-[:checked]:bg-[var(--appkit-color-primary)]/5", children: [_jsx(Checkbox, { bare: true, type: "radio", name: "payoutMethod", value: value, checked: values.method === value, onChange: () => onChange({ method: value }), className: "accent-[var(--appkit-color-primary)]", disabled: busy, "aria-invalid": errors.method ? "true" : undefined }), _jsxs(Div, { children: [_jsx(Text, { weight: "medium", children: label }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: desc })] })] }, value))), errors.method && (_jsx(Text, { size: "sm", variant: "error", role: "alert", children: errors.method }))] }), values.method === "upi" && (_jsx(FormField, { name: "upiId", label: "UPI ID (VPA)", type: "text", value: values.upiId, onChange: (v) => onChange({ upiId: v }), placeholder: "yourname@upi", helpText: "Ensure this VPA is registered and active.", disabled: busy })), values.method === "bank_transfer" && (_jsxs(Stack, { gap: "md", className: "mt-2", children: [_jsx(FormField, { name: "accountHolderName", label: "Account Holder Name", type: "text", value: values.accountHolderName, onChange: (v) => onChange({ accountHolderName: v }), placeholder: "Name as on bank account", disabled: busy }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "accountNumber", label: "Account Number", type: "text", value: values.accountNumber, onChange: (v) => onChange({ accountNumber: v }), placeholder: "Enter full account number", helpText: current?.bankAccount ? `Saved: ••••${current.bankAccount.accountNumberMasked?.slice(-4) ?? "••••"}` : "Stored securely, never displayed in full.", disabled: busy }), _jsx(FormField, { name: "ifscCode", label: "IFSC Code", type: "text", value: values.ifscCode, onChange: (v) => onChange({ ifscCode: v.toUpperCase() }), placeholder: "e.g. SBIN0001234", disabled: busy })] }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "bankName", label: "Bank Name", type: "text", value: values.bankName, onChange: (v) => onChange({ bankName: v }), placeholder: "e.g. State Bank of India", disabled: busy }), _jsxs(Div, { children: [_jsx(Text, { className: "mb-1.5", size: "sm", weight: "medium", children: "Account Type" }), _jsx(RadioFieldGroup, { name: "accountType", value: values.accountType, options: ["savings", "current"], error: errors.accountType, disabled: busy, onSelect: (t) => onChange({ accountType: t }), layout: Row, renderOption: (t) => (_jsx(Text, { size: "sm", transform: "capitalize", children: t })) })] })] })] }))] })),
|
|
292
331
|
},
|
|
293
332
|
{
|
|
294
333
|
id: "tax",
|
|
@@ -641,7 +641,11 @@ export function SellerProductsView({ onDeleteProduct, onCreateClick, }) {
|
|
|
641
641
|
: `/products/${row.id}`,
|
|
642
642
|
renderRowActions: (row) => {
|
|
643
643
|
const isPublished = (statusOverrides.get(row.id) ?? row.status) === "published";
|
|
644
|
-
return (_jsxs(Row, { gap: "xs", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => { e.stopPropagation(); handleEdit(row); }, "aria-label": ACTIONS.STORE["edit-listing"].ariaLabel, children: _jsx(Pencil, { className: "w-4 h-4" }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => { e.stopPropagation(); void openAssembly(row, "assemble"); }, "aria-label": ACTIONS.STORE["assemble-from-parts"].ariaLabel, title: ACTIONS.STORE["assemble-from-parts"].label, disabled: assembleLoading, children: _jsx(Wrench, { className: "w-4 h-4" }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => { e.stopPropagation(); void openAssembly(row, "part-out"); }, "aria-label": ACTIONS.STORE["part-out-listing"].ariaLabel, title: ACTIONS.STORE["part-out-listing"].label, disabled: assembleLoading, children: _jsx(Scissors, { className: "w-4 h-4" }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => { e.stopPropagation(); void handleTogglePublish(row); }, "aria-label": isPublished
|
|
644
|
+
return (_jsxs(Row, { gap: "xs", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => { e.stopPropagation(); handleEdit(row); }, "aria-label": ACTIONS.STORE["edit-listing"].ariaLabel, children: _jsx(Pencil, { className: "w-4 h-4" }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => { e.stopPropagation(); void openAssembly(row, "assemble"); }, "aria-label": ACTIONS.STORE["assemble-from-parts"].ariaLabel, title: ACTIONS.STORE["assemble-from-parts"].label, disabled: assembleLoading, children: _jsx(Wrench, { className: "w-4 h-4" }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => { e.stopPropagation(); void openAssembly(row, "part-out"); }, "aria-label": ACTIONS.STORE["part-out-listing"].ariaLabel, title: ACTIONS.STORE["part-out-listing"].label, disabled: assembleLoading, children: _jsx(Scissors, { className: "w-4 h-4" }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => { e.stopPropagation(); void handleTogglePublish(row); }, "aria-label": isPublished
|
|
645
|
+
? ACTIONS.STORE["unpublish-listing"].label
|
|
646
|
+
: ACTIONS.STORE["publish-listing"].label, title: isPublished
|
|
647
|
+
? ACTIONS.STORE["unpublish-listing"].description
|
|
648
|
+
: ACTIONS.STORE["publish-listing"].description, disabled: publishingId === row.id, children: isPublished ? _jsx(EyeOff, { className: "w-4 h-4" }) : _jsx(Eye, { className: "w-4 h-4" }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => { e.stopPropagation(); void handleDuplicate(row); }, "aria-label": "Duplicate listing", title: "Duplicate", children: "\u29C9" }), onDeleteProduct && (_jsx(Button, { variant: "ghost", size: "sm", action: ACTIONS.STORE["delete-listing"], onClick: (e) => { e.stopPropagation(); void handleDelete(row); }, disabled: deletingId === row.id, className: "text-[var(--appkit-color-error)] hover:bg-[var(--appkit-color-border-subtle)]", children: _jsx(Trash2, { className: "w-4 h-4" }) }))] }));
|
|
645
649
|
},
|
|
646
650
|
};
|
|
647
651
|
return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), setLocationOpen && (_jsx(PhysicalLocationModal, { count: selectedIdsForLocation.length, onSave: (loc) => handleSetLocation(loc, selectedIdsForLocation), onClose: () => setSetLocationOpen(false) })), setStockOpen && (_jsx(BulkStockModal, { count: selectedIdsForStock.length, busy: stockBusy, onSave: (qty) => handleSetStock(qty, selectedIdsForStock), onClose: () => setSetStockOpen(false) })), assembleFor && assembleData && (_jsx(AssemblyDrawer, { isOpen: true,
|