@mohasinac/appkit 2.7.50 → 2.7.53
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/_internal/server/jobs/core/__tests__/couponExpiry.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/couponExpiry.test.js +65 -0
- package/dist/_internal/server/jobs/core/__tests__/listingProcessor.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/listingProcessor.test.js +163 -0
- package/dist/_internal/server/jobs/core/__tests__/mediaTmpCleanup.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/mediaTmpCleanup.test.js +115 -0
- package/dist/_internal/server/jobs/core/__tests__/pendingOrderTimeout.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/pendingOrderTimeout.test.js +96 -0
- package/dist/client.d.ts +29 -6
- package/dist/client.js +16 -4
- package/dist/constants/api-endpoints.d.ts +42 -0
- package/dist/constants/api-endpoints.js +14 -0
- package/dist/features/_guide-cls.d.ts +13 -0
- package/dist/features/_guide-cls.js +14 -0
- package/dist/features/about/components/HelpPageView.js +29 -26
- package/dist/features/account/components/BuyerAccountGuideView.d.ts +1 -0
- package/dist/features/account/components/BuyerAccountGuideView.js +39 -0
- package/dist/features/account/components/BuyerAuctionsGuideView.d.ts +1 -0
- package/dist/features/account/components/BuyerAuctionsGuideView.js +38 -0
- package/dist/features/account/components/BuyerOrdersGuideView.d.ts +1 -0
- package/dist/features/account/components/BuyerOrdersGuideView.js +48 -0
- package/dist/features/account/components/BuyerShoppingGuideView.d.ts +1 -0
- package/dist/features/account/components/BuyerShoppingGuideView.js +38 -0
- package/dist/features/admin/components/AdminAnalyticsGuideView.d.ts +1 -0
- package/dist/features/admin/components/AdminAnalyticsGuideView.js +24 -0
- package/dist/features/admin/components/AdminBlogEditorView.js +100 -77
- package/dist/features/admin/components/AdminBundleEditorView.js +20 -14
- package/dist/features/admin/components/AdminBundlesView.d.ts +1 -3
- package/dist/features/admin/components/AdminBundlesView.js +173 -52
- package/dist/features/admin/components/AdminCatalogGuideView.d.ts +1 -0
- package/dist/features/admin/components/AdminCatalogGuideView.js +28 -0
- package/dist/features/admin/components/AdminContentGuideView.d.ts +1 -0
- package/dist/features/admin/components/AdminContentGuideView.js +36 -0
- package/dist/features/admin/components/AdminCouponEditorView.js +1 -1
- package/dist/features/admin/components/AdminGuideHubView.d.ts +5 -0
- package/dist/features/admin/components/AdminGuideHubView.js +79 -0
- package/dist/features/admin/components/AdminOrdersGuideView.d.ts +1 -0
- package/dist/features/admin/components/AdminOrdersGuideView.js +44 -0
- package/dist/features/admin/components/AdminProductsView.js +8 -3
- package/dist/features/admin/components/AdminSiteConfigGuideView.d.ts +1 -0
- package/dist/features/admin/components/AdminSiteConfigGuideView.js +21 -0
- package/dist/features/admin/components/AdminStoresGuideView.d.ts +1 -0
- package/dist/features/admin/components/AdminStoresGuideView.js +32 -0
- package/dist/features/admin/components/AdminTeamGuideView.d.ts +1 -0
- package/dist/features/admin/components/AdminTeamGuideView.js +33 -0
- package/dist/features/admin/components/AdminTrustGuideView.d.ts +1 -0
- package/dist/features/admin/components/AdminTrustGuideView.js +40 -0
- package/dist/features/admin/components/AdminUsersGuideView.d.ts +1 -0
- package/dist/features/admin/components/AdminUsersGuideView.js +38 -0
- package/dist/features/categories/components/CategoryBundlesListing.js +3 -33
- package/dist/features/categories/components/index.d.ts +0 -2
- package/dist/features/categories/components/index.js +0 -1
- package/dist/features/events/components/AdminEventEditorView.js +223 -269
- package/dist/features/grouped/repository/grouped-listings.repository.d.ts +9 -0
- package/dist/features/grouped/repository/grouped-listings.repository.js +12 -0
- package/dist/features/media/upload/MediaUploadField.js +1 -1
- package/dist/features/pre-orders/components/PreOrdersIndexListing.js +3 -1
- package/dist/features/products/components/AuctionsIndexListing.js +3 -1
- package/dist/features/products/components/MarketplaceBundleCard.d.ts +21 -0
- package/dist/features/products/components/MarketplaceBundleCard.js +56 -0
- package/dist/features/products/components/ProductsIndexListing.js +3 -1
- package/dist/features/products/components/index.d.ts +2 -4
- package/dist/features/products/components/index.js +1 -2
- package/dist/features/promotions/schemas/firestore.js +1 -1
- package/dist/features/reviews/components/index.d.ts +0 -2
- package/dist/features/reviews/components/index.js +0 -1
- package/dist/features/seller/components/BrandInlineSelect.js +23 -3
- package/dist/features/seller/components/CategoryInlineSelect.js +20 -3
- package/dist/features/seller/components/SellerAnalyticsAlertsView.d.ts +6 -0
- package/dist/features/seller/components/SellerAnalyticsAlertsView.js +124 -0
- package/dist/features/seller/components/SellerAnalyticsView.d.ts +2 -0
- package/dist/features/seller/components/SellerAnalyticsView.js +17 -9
- package/dist/features/seller/components/SellerBundlesView.d.ts +5 -0
- package/dist/features/seller/components/SellerBundlesView.js +104 -0
- package/dist/features/seller/components/SellerClassifiedView.d.ts +5 -0
- package/dist/features/seller/components/SellerClassifiedView.js +113 -0
- package/dist/features/seller/components/SellerDashboardView.js +19 -7
- package/dist/features/seller/components/SellerDigitalCodesView.d.ts +5 -0
- package/dist/features/seller/components/SellerDigitalCodesView.js +115 -0
- package/dist/features/seller/components/SellerGoogleReviewsView.d.ts +14 -0
- package/dist/features/seller/components/SellerGoogleReviewsView.js +95 -0
- package/dist/features/seller/components/SellerGroupedListingsView.d.ts +6 -0
- package/dist/features/seller/components/SellerGroupedListingsView.js +112 -0
- package/dist/features/seller/components/SellerLiveView.d.ts +5 -0
- package/dist/features/seller/components/SellerLiveView.js +113 -0
- package/dist/features/seller/components/SellerOrdersView.js +18 -2
- package/dist/features/seller/components/SellerPayoutMethodsView.d.ts +7 -0
- package/dist/features/seller/components/SellerPayoutMethodsView.js +120 -0
- package/dist/features/seller/components/SellerPayoutSettingsView.js +50 -12
- package/dist/features/seller/components/SellerProductShell.d.ts +1 -1
- package/dist/features/seller/components/SellerProductShell.js +9 -7
- package/dist/features/seller/components/SellerProductsFilterDrawer.js +3 -1
- package/dist/features/seller/components/SellerProductsView.js +48 -54
- package/dist/features/seller/components/SellerShippingConfigsView.d.ts +7 -0
- package/dist/features/seller/components/SellerShippingConfigsView.js +149 -0
- package/dist/features/seller/components/SellerShippingView.js +37 -10
- package/dist/features/seller/components/SellerStoreCategoriesView.d.ts +9 -0
- package/dist/features/seller/components/SellerStoreCategoriesView.js +122 -0
- package/dist/features/seller/components/SellerStorefrontView.d.ts +0 -7
- package/dist/features/seller/components/SellerStorefrontView.js +26 -29
- package/dist/features/seller/components/SellerTemplatesView.d.ts +10 -0
- package/dist/features/seller/components/SellerTemplatesView.js +265 -0
- package/dist/features/seller/components/index.d.ts +26 -0
- package/dist/features/seller/components/index.js +13 -0
- package/dist/features/stores/api/[storeSlug]/reviews/route.js +49 -7
- package/dist/features/stores/components/StoreCapabilitiesGuideView.d.ts +3 -0
- package/dist/features/stores/components/StoreCapabilitiesGuideView.js +101 -0
- package/dist/features/stores/components/StoreFinanceGuideView.d.ts +3 -0
- package/dist/features/stores/components/StoreFinanceGuideView.js +79 -0
- package/dist/features/stores/components/StoreGuideHubView.d.ts +5 -0
- package/dist/features/stores/components/StoreGuideHubView.js +89 -0
- package/dist/features/stores/components/StoreListingsGuideView.d.ts +3 -0
- package/dist/features/stores/components/StoreListingsGuideView.js +151 -0
- package/dist/features/stores/components/StoreOrdersGuideView.d.ts +3 -0
- package/dist/features/stores/components/StoreOrdersGuideView.js +122 -0
- package/dist/features/stores/components/StoreReviewsListing.js +100 -23
- package/dist/features/stores/components/StoreSettingsGuideView.d.ts +3 -0
- package/dist/features/stores/components/StoreSettingsGuideView.js +56 -0
- package/dist/features/stores/components/index.d.ts +12 -1
- package/dist/features/stores/components/index.js +6 -1
- package/dist/features/stores/hooks/useStores.d.ts +5 -0
- package/dist/features/stores/hooks/useStores.js +10 -0
- package/dist/features/stores/manifest.js +1 -1
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +13 -2
- package/dist/index.d.ts +54 -9
- package/dist/index.js +58 -15
- package/dist/next/routing/route-map.d.ts +55 -0
- package/dist/next/routing/route-map.js +25 -0
- package/dist/providers/db-firebase/__tests__/filter-aliases.test.d.ts +1 -0
- package/dist/providers/db-firebase/__tests__/filter-aliases.test.js +93 -0
- package/dist/providers/db-firebase/sieve.d.ts +49 -0
- package/dist/providers/db-firebase/sieve.js +61 -8
- package/dist/repositories/index.d.ts +1 -0
- package/dist/repositories/index.js +2 -0
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/ListingToolbar.d.ts +8 -1
- package/dist/ui/components/ListingToolbar.js +4 -2
- package/dist/ui/components/__tests__/BulkActionBar.test.d.ts +1 -0
- package/dist/ui/components/__tests__/BulkActionBar.test.js +96 -0
- package/dist/ui/components/__tests__/ListingToolbar.test.d.ts +1 -0
- package/dist/ui/components/__tests__/ListingToolbar.test.js +125 -0
- package/dist/ui/index.d.ts +1 -1
- package/package.json +8 -2
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useCallback } from "react";
|
|
4
|
+
import { Plus } from "lucide-react";
|
|
5
|
+
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
|
+
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
7
|
+
import { BulkActionBar, Button, DataTable, Div, ListingToolbar, Pagination, Text, } from "../../../ui";
|
|
8
|
+
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
9
|
+
import { ROUTES } from "../../..";
|
|
10
|
+
import { toRecordArray, toRelativeDate, toRupees, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
|
|
11
|
+
import { TABLE_KEYS } from "../../../constants/table-keys";
|
|
12
|
+
const PAGE_SIZE = 25;
|
|
13
|
+
const DEFAULT_SORT = "-createdAt";
|
|
14
|
+
const SORT_OPTIONS = [
|
|
15
|
+
{ value: "-createdAt", label: "Newest" },
|
|
16
|
+
{ value: "createdAt", label: "Oldest" },
|
|
17
|
+
{ value: "productTitle", label: "Name A–Z" },
|
|
18
|
+
{ value: "price", label: "Price: Low–High" },
|
|
19
|
+
{ value: "-price", label: "Price: High–Low" },
|
|
20
|
+
];
|
|
21
|
+
const COLUMNS = [
|
|
22
|
+
{
|
|
23
|
+
key: "title",
|
|
24
|
+
header: "Item",
|
|
25
|
+
render: (row) => (_jsxs(Div, { children: [_jsx(Text, { className: "text-sm font-medium", children: row.title }), row.species && (_jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)] italic", children: row.species }))] })),
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
key: "price",
|
|
29
|
+
header: "Price",
|
|
30
|
+
render: (row) => _jsx(Text, { className: "text-sm tabular-nums", children: row.price }),
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
key: "ageMonths",
|
|
34
|
+
header: "Age",
|
|
35
|
+
render: (row) => (_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: row.ageMonths !== null ? `${row.ageMonths}mo` : "—" })),
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
key: "vendorVerified",
|
|
39
|
+
header: "Verified",
|
|
40
|
+
render: (row) => (_jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${row.vendorVerified
|
|
41
|
+
? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300"
|
|
42
|
+
: "bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300"}`, children: row.vendorVerified ? "Verified" : "Pending" })),
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
key: "status",
|
|
46
|
+
header: "Status",
|
|
47
|
+
render: (row) => (_jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium capitalize ${row.status === "active"
|
|
48
|
+
? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300"
|
|
49
|
+
: "bg-zinc-100 text-zinc-600 dark:bg-slate-800 dark:text-slate-400"}`, children: row.status })),
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
key: "createdAt",
|
|
53
|
+
header: "Listed",
|
|
54
|
+
render: (row) => _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: row.createdAt }),
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
export function SellerLiveView({ onCreateClick, onBulkDelete, }) {
|
|
58
|
+
const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
|
|
59
|
+
const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
|
|
60
|
+
const [view] = useState("table");
|
|
61
|
+
const commitSearch = useCallback(() => {
|
|
62
|
+
table.set(TABLE_KEYS.QUERY, searchInput.trim());
|
|
63
|
+
}, [searchInput, table]);
|
|
64
|
+
const resetAll = useCallback(() => {
|
|
65
|
+
table.setMany({ [TABLE_KEYS.QUERY]: "", [TABLE_KEYS.SORT]: "" });
|
|
66
|
+
setSearchInput("");
|
|
67
|
+
}, [table]);
|
|
68
|
+
const hasActiveState = !!table.get(TABLE_KEYS.QUERY) || table.get(TABLE_KEYS.SORT) !== DEFAULT_SORT;
|
|
69
|
+
const { rows, total, isLoading, errorMessage } = useSellerListingData({
|
|
70
|
+
queryKey: ["seller", "live-items"],
|
|
71
|
+
endpoint: SELLER_ENDPOINTS.PRODUCTS,
|
|
72
|
+
page: table.getNumber(TABLE_KEYS.PAGE, 1),
|
|
73
|
+
pageSize: PAGE_SIZE,
|
|
74
|
+
sorts: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT,
|
|
75
|
+
filters: "listingType==live",
|
|
76
|
+
q: table.get(TABLE_KEYS.QUERY) || undefined,
|
|
77
|
+
mapRows: (response) => toRecordArray(response.products).map((item, index) => {
|
|
78
|
+
const live = (item.liveItem ?? {});
|
|
79
|
+
return {
|
|
80
|
+
id: toStringValue(item.id, `live-${index}`),
|
|
81
|
+
raw: item,
|
|
82
|
+
title: toStringValue(item.productTitle ?? item.title, "Untitled"),
|
|
83
|
+
price: toRupees(item.price),
|
|
84
|
+
species: toStringValue(live.species, ""),
|
|
85
|
+
ageMonths: typeof live.ageMonths === "number" ? live.ageMonths : null,
|
|
86
|
+
vendorVerified: Boolean(live.vendorVerified),
|
|
87
|
+
status: toStringValue(item.status, "draft"),
|
|
88
|
+
createdAt: toRelativeDate(item.createdAt),
|
|
89
|
+
};
|
|
90
|
+
}),
|
|
91
|
+
getTotal: (response, mappedRows) => typeof response.meta?.total === "number" ? response.meta.total : mappedRows.length,
|
|
92
|
+
});
|
|
93
|
+
const currentPage = table.getNumber(TABLE_KEYS.PAGE, 1);
|
|
94
|
+
const totalPages = Math.ceil(total / PAGE_SIZE);
|
|
95
|
+
const selection = useBulkSelection({ items: rows, keyExtractor: (r) => r.id });
|
|
96
|
+
const bulkActions = onBulkDelete
|
|
97
|
+
? [{
|
|
98
|
+
id: "bulk-delete",
|
|
99
|
+
label: "Delete selected",
|
|
100
|
+
variant: "danger",
|
|
101
|
+
onClick: async () => { await onBulkDelete(selection.selectedIds); selection.clearSelection(); },
|
|
102
|
+
}]
|
|
103
|
+
: [];
|
|
104
|
+
const handleCreate = useCallback(() => {
|
|
105
|
+
if (onCreateClick) {
|
|
106
|
+
onCreateClick();
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
window.location.href = String(ROUTES.STORE.LIVE_ITEMS_NEW);
|
|
110
|
+
}
|
|
111
|
+
}, [onCreateClick]);
|
|
112
|
+
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: 0, searchValue: searchInput, searchPlaceholder: "Search live items by name or species...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, showTableView: true, view: view, onViewChange: () => { }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: handleCreate, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: "New Live Item" })] }) }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), selection.selectedCount > 0 && bulkActions.length > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx(Div, { className: "mb-4 rounded-xl border border-red-200 bg-red-50 dark:bg-red-950/40 dark:border-red-900/60 px-4 py-3 text-sm text-red-700 dark:text-red-200", children: errorMessage })), isLoading ? (_jsx(Div, { className: "space-y-2", children: Array.from({ length: 5 }).map((_, i) => (_jsx(Div, { className: "h-14 animate-pulse rounded-xl border border-zinc-100 dark:border-slate-700 bg-zinc-50 dark:bg-slate-800" }, i))) })) : rows.length === 0 ? (_jsx(Div, { className: "py-16 text-center", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-500", children: "No live items yet \u2014 list animals, plants, or other living specimens" }) })) : (_jsx(DataTable, { columns: COLUMNS, data: rows, keyExtractor: (r) => r.id, selectable: bulkActions.length > 0, selectedIds: selection.selectedIds, onSelectionChange: (ids) => selection.setSelectedIds(ids) }))] })] }));
|
|
113
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import React, { useState, useCallback } from "react";
|
|
4
|
-
import { X, Eye, Printer, MapPin } from "lucide-react";
|
|
4
|
+
import { X, Eye, Printer, MapPin, Truck } from "lucide-react";
|
|
5
5
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
6
|
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
7
7
|
import { useActionDispatch } from "../../../react/hooks/use-action-dispatch";
|
|
@@ -34,8 +34,11 @@ const STATUS_BADGE_VARIANT = {
|
|
|
34
34
|
};
|
|
35
35
|
const UPDATE_STATUS_OPTIONS = [
|
|
36
36
|
{ value: "", label: "— keep current —" },
|
|
37
|
+
{ value: "confirmed", label: "Confirmed" },
|
|
37
38
|
{ value: "processing", label: "Processing" },
|
|
38
39
|
{ value: "shipped", label: "Shipped" },
|
|
40
|
+
{ value: "delivered", label: "Delivered" },
|
|
41
|
+
{ value: "cancelled", label: "Cancelled" },
|
|
39
42
|
];
|
|
40
43
|
// ---------------------------------------------------------------------------
|
|
41
44
|
// Order Detail Drawer
|
|
@@ -225,7 +228,20 @@ export function SellerOrdersView({ orderDetailApiBase = SELLER_ENDPOINTS.ORDERS,
|
|
|
225
228
|
render: (row) => _jsx("span", { className: "text-xs text-zinc-500 dark:text-zinc-400", children: row.updatedAt }),
|
|
226
229
|
},
|
|
227
230
|
];
|
|
228
|
-
const
|
|
231
|
+
const handleQuickShip = useCallback(async (row, e) => {
|
|
232
|
+
e.stopPropagation();
|
|
233
|
+
const res = await fetch(`${orderDetailApiBase}/${row.id}`, {
|
|
234
|
+
method: "PATCH",
|
|
235
|
+
headers: { "Content-Type": "application/json" },
|
|
236
|
+
body: JSON.stringify({ status: "shipped" }),
|
|
237
|
+
}).catch(() => null);
|
|
238
|
+
if (res?.ok)
|
|
239
|
+
setSelectedOrderId(null);
|
|
240
|
+
}, [orderDetailApiBase]);
|
|
241
|
+
const renderRowActions = useCallback((row) => {
|
|
242
|
+
const isShippable = ["PENDING", "PROCESSING", "CONFIRMED"].includes(row.status?.toUpperCase() ?? "");
|
|
243
|
+
return (_jsxs("div", { className: "flex items-center gap-1", children: [isShippable && (_jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => void handleQuickShip(row, e), "aria-label": "Mark as shipped", title: "Mark shipped", children: _jsx(Truck, { className: "h-4 w-4" }) })), _jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => { e.stopPropagation(); setSelectedOrderId(row.id); }, title: "View order details", "aria-label": "View order details", children: _jsx(Eye, { className: "h-4 w-4" }) })] }));
|
|
244
|
+
}, [handleQuickShip]);
|
|
229
245
|
const selection = useBulkSelection({ items: rows, keyExtractor: (r) => r.id });
|
|
230
246
|
const handlePrintPackingSlips = useCallback(() => {
|
|
231
247
|
const ids = selection.selectedIds.join(",");
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface SellerPayoutMethodsViewProps {
|
|
2
|
+
onCreateClick?: () => void;
|
|
3
|
+
onEditClick?: (id: string) => void;
|
|
4
|
+
onDelete?: (id: string) => Promise<void>;
|
|
5
|
+
onSetDefault?: (id: string) => Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
export declare function SellerPayoutMethodsView({ onCreateClick, onEditClick, onDelete, onSetDefault, }: SellerPayoutMethodsViewProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useCallback } from "react";
|
|
4
|
+
import { Plus } from "lucide-react";
|
|
5
|
+
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
|
+
import { Button, ConfirmDeleteModal, Div, ListingToolbar, Text, } from "../../../ui";
|
|
7
|
+
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
8
|
+
import { ROUTES } from "../../..";
|
|
9
|
+
import { toRecordArray, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
|
|
10
|
+
import { TABLE_KEYS } from "../../../constants/table-keys";
|
|
11
|
+
const PAGE_SIZE = 50;
|
|
12
|
+
const DEFAULT_SORT = "-createdAt";
|
|
13
|
+
const SORT_OPTIONS = [
|
|
14
|
+
{ value: "-createdAt", label: "Newest" },
|
|
15
|
+
{ value: "createdAt", label: "Oldest" },
|
|
16
|
+
{ value: "label", label: "Label A–Z" },
|
|
17
|
+
];
|
|
18
|
+
function getMaskedIdentifier(item) {
|
|
19
|
+
if (item.upiVpa && typeof item.upiVpa === "string") {
|
|
20
|
+
return item.upiVpa;
|
|
21
|
+
}
|
|
22
|
+
if (item.accountNumber && typeof item.accountNumber === "string") {
|
|
23
|
+
const acc = item.accountNumber;
|
|
24
|
+
return `••••${acc.slice(-4)}`;
|
|
25
|
+
}
|
|
26
|
+
return "—";
|
|
27
|
+
}
|
|
28
|
+
function TypeBadge({ type }) {
|
|
29
|
+
return (_jsx("span", { className: "inline-flex items-center rounded-full px-2 py-0.5 text-xs font-semibold uppercase tracking-wide bg-violet-100 text-violet-700 dark:bg-violet-900/40 dark:text-violet-300", children: type === "upi" ? "UPI" : type === "bank" ? "Bank" : type.toUpperCase() }));
|
|
30
|
+
}
|
|
31
|
+
export function SellerPayoutMethodsView({ onCreateClick, onEditClick, onDelete, onSetDefault, }) {
|
|
32
|
+
const table = useUrlTable({ defaults: { sort: DEFAULT_SORT } });
|
|
33
|
+
const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
|
|
34
|
+
const [deleteTargetId, setDeleteTargetId] = useState(null);
|
|
35
|
+
const [deletingId, setDeletingId] = useState(null);
|
|
36
|
+
const [settingDefaultId, setSettingDefaultId] = useState(null);
|
|
37
|
+
const commitSearch = useCallback(() => {
|
|
38
|
+
table.set(TABLE_KEYS.QUERY, searchInput.trim());
|
|
39
|
+
}, [searchInput, table]);
|
|
40
|
+
const resetAll = useCallback(() => {
|
|
41
|
+
table.setMany({ [TABLE_KEYS.QUERY]: "", [TABLE_KEYS.SORT]: "" });
|
|
42
|
+
setSearchInput("");
|
|
43
|
+
}, [table]);
|
|
44
|
+
const hasActiveState = !!table.get(TABLE_KEYS.QUERY) || table.get(TABLE_KEYS.SORT) !== DEFAULT_SORT;
|
|
45
|
+
const { rows, isLoading, errorMessage, refetch } = useSellerListingData({
|
|
46
|
+
queryKey: ["seller", "payout-methods"],
|
|
47
|
+
endpoint: SELLER_ENDPOINTS.PAYOUT_METHODS,
|
|
48
|
+
page: 1,
|
|
49
|
+
pageSize: PAGE_SIZE,
|
|
50
|
+
sorts: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT,
|
|
51
|
+
q: table.get(TABLE_KEYS.QUERY) || undefined,
|
|
52
|
+
mapRows: (response) => toRecordArray(response.items).map((item, index) => ({
|
|
53
|
+
id: toStringValue(item.id, `pm-${index}`),
|
|
54
|
+
raw: item,
|
|
55
|
+
label: String(item.label ?? ""),
|
|
56
|
+
type: String(item.type ?? ""),
|
|
57
|
+
isDefault: Boolean(item.isDefault),
|
|
58
|
+
isActive: Boolean(item.isActive),
|
|
59
|
+
maskedIdentifier: getMaskedIdentifier(item),
|
|
60
|
+
})),
|
|
61
|
+
});
|
|
62
|
+
const handleDelete = useCallback(async (id) => {
|
|
63
|
+
setDeletingId(id);
|
|
64
|
+
try {
|
|
65
|
+
if (onDelete) {
|
|
66
|
+
await onDelete(id);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
await fetch(SELLER_ENDPOINTS.PAYOUT_METHOD_BY_ID(id), {
|
|
70
|
+
method: "DELETE",
|
|
71
|
+
credentials: "include",
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
refetch?.();
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
setDeletingId(null);
|
|
78
|
+
setDeleteTargetId(null);
|
|
79
|
+
}
|
|
80
|
+
}, [onDelete, refetch]);
|
|
81
|
+
const handleSetDefault = useCallback(async (id) => {
|
|
82
|
+
setSettingDefaultId(id);
|
|
83
|
+
try {
|
|
84
|
+
if (onSetDefault) {
|
|
85
|
+
await onSetDefault(id);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
await fetch(SELLER_ENDPOINTS.PAYOUT_METHOD_BY_ID(id), {
|
|
89
|
+
method: "PATCH",
|
|
90
|
+
headers: { "Content-Type": "application/json" },
|
|
91
|
+
credentials: "include",
|
|
92
|
+
body: JSON.stringify({ isDefault: true }),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
refetch?.();
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
setSettingDefaultId(null);
|
|
99
|
+
}
|
|
100
|
+
}, [onSetDefault, refetch]);
|
|
101
|
+
const handleCreate = useCallback(() => {
|
|
102
|
+
if (onCreateClick) {
|
|
103
|
+
onCreateClick();
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
window.location.href = String(ROUTES.STORE.PAYOUT_METHODS_NEW);
|
|
107
|
+
}
|
|
108
|
+
}, [onCreateClick]);
|
|
109
|
+
const handleEdit = useCallback((id) => {
|
|
110
|
+
if (onEditClick) {
|
|
111
|
+
onEditClick(id);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
window.location.href = String(ROUTES.STORE.PAYOUT_METHODS_EDIT(id));
|
|
115
|
+
}
|
|
116
|
+
}, [onEditClick]);
|
|
117
|
+
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: 0, searchValue: searchInput, searchPlaceholder: "Search payout methods...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: handleCreate, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: "New Method" })] }) }), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx(Div, { className: "mb-4 rounded-xl border border-red-200 bg-red-50 dark:bg-red-950/40 dark:border-red-900/60 px-4 py-3 text-sm text-red-700 dark:text-red-200", children: errorMessage })), isLoading ? (_jsx(Div, { className: "space-y-3", children: Array.from({ length: 3 }).map((_, i) => (_jsx(Div, { className: "h-20 animate-pulse rounded-xl border border-zinc-100 dark:border-slate-700 bg-zinc-50 dark:bg-slate-800" }, i))) })) : rows.length === 0 ? (_jsxs(Div, { className: "py-16 text-center", children: [_jsx(Text, { className: "text-zinc-400 dark:text-zinc-500", children: "No payout methods yet \u2014 add a UPI VPA or bank account to receive payouts" }), _jsx("div", { className: "mt-4", children: _jsx(Button, { size: "sm", onClick: handleCreate, children: "Add payout method" }) })] })) : (_jsx("div", { className: "space-y-3", children: rows.map((row) => (_jsx("div", { className: "rounded-xl border border-zinc-200 dark:border-slate-700 bg-white dark:bg-slate-900 px-4 py-3", children: _jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsx("div", { className: "flex items-start gap-3 min-w-0", children: _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx(Text, { className: "text-sm font-medium", children: row.label }), _jsx(TypeBadge, { type: row.type }), row.isDefault && (_jsx("span", { className: "inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300", children: "Default" })), _jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${row.isActive
|
|
118
|
+
? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300"
|
|
119
|
+
: "bg-zinc-100 text-zinc-600 dark:bg-slate-800 dark:text-slate-400"}`, children: row.isActive ? "Active" : "Inactive" })] }), _jsx(Text, { className: "mt-1 text-xs text-zinc-500 dark:text-zinc-400 font-mono", children: row.maskedIdentifier })] }) }), _jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [!row.isDefault && (_jsx(Button, { size: "sm", variant: "ghost", isLoading: settingDefaultId === row.id, onClick: () => handleSetDefault(row.id), children: "Set Default" })), _jsx(Button, { size: "sm", variant: "outline", onClick: () => handleEdit(row.id), children: "Edit" }), _jsx(Button, { size: "sm", variant: "danger", disabled: deletingId === row.id, onClick: () => setDeleteTargetId(row.id), children: "Delete" })] })] }) }, row.id))) }))] }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Payout Method", message: "Are you sure you want to delete this payout method? This cannot be undone.", onConfirm: () => handleDelete(deleteTargetId), onClose: () => setDeleteTargetId(null), isDeleting: deletingId === deleteTargetId }))] }));
|
|
120
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useCallback, useEffect, useState } from "react";
|
|
4
|
-
import { Alert, Badge,
|
|
4
|
+
import { Alert, Badge, Div, FormField, FormGroup, Heading, Stack, Text, Toggle } from "../../../ui";
|
|
5
5
|
import { StackedViewShell } from "../../../ui";
|
|
6
|
+
import { StepForm } from "../../shell";
|
|
6
7
|
const DEFAULT_DRAFT = {
|
|
7
8
|
method: "upi",
|
|
8
9
|
upiId: "",
|
|
@@ -11,6 +12,11 @@ const DEFAULT_DRAFT = {
|
|
|
11
12
|
ifscCode: "",
|
|
12
13
|
bankName: "",
|
|
13
14
|
accountType: "savings",
|
|
15
|
+
gstin: "",
|
|
16
|
+
pan: "",
|
|
17
|
+
businessType: "",
|
|
18
|
+
autoPayout: true,
|
|
19
|
+
minimumThreshold: "",
|
|
14
20
|
};
|
|
15
21
|
export function SellerPayoutSettingsView({ apiBase = "/api/store/payout-settings" }) {
|
|
16
22
|
const [draft, setDraft] = useState(DEFAULT_DRAFT);
|
|
@@ -19,6 +25,7 @@ export function SellerPayoutSettingsView({ apiBase = "/api/store/payout-settings
|
|
|
19
25
|
const [saving, setSaving] = useState(false);
|
|
20
26
|
const [error, setError] = useState(null);
|
|
21
27
|
const [success, setSuccess] = useState(false);
|
|
28
|
+
const [currentStep, setCurrentStep] = useState(0);
|
|
22
29
|
useEffect(() => {
|
|
23
30
|
fetch(apiBase)
|
|
24
31
|
.then((r) => r.json())
|
|
@@ -33,13 +40,20 @@ export function SellerPayoutSettingsView({ apiBase = "/api/store/payout-settings
|
|
|
33
40
|
ifscCode: details.bankAccount?.ifscCode ?? "",
|
|
34
41
|
bankName: details.bankAccount?.bankName ?? "",
|
|
35
42
|
accountType: details.bankAccount?.accountType ?? "savings",
|
|
43
|
+
gstin: res?.data?.taxInfo?.gstin ?? "",
|
|
44
|
+
pan: res?.data?.taxInfo?.pan ?? "",
|
|
45
|
+
businessType: res?.data?.taxInfo?.businessType ?? "",
|
|
46
|
+
autoPayout: res?.data?.preferences?.autoPayout ?? true,
|
|
47
|
+
minimumThreshold: res?.data?.preferences?.minimumThreshold
|
|
48
|
+
? String(res.data.preferences.minimumThreshold / 100)
|
|
49
|
+
: "",
|
|
36
50
|
});
|
|
37
51
|
})
|
|
38
52
|
.catch(() => { })
|
|
39
53
|
.finally(() => setLoading(false));
|
|
40
54
|
}, [apiBase]);
|
|
41
|
-
const update = useCallback((
|
|
42
|
-
setDraft((prev) => ({ ...prev,
|
|
55
|
+
const update = useCallback((partial) => {
|
|
56
|
+
setDraft((prev) => ({ ...prev, ...partial }));
|
|
43
57
|
setSuccess(false);
|
|
44
58
|
}, []);
|
|
45
59
|
const handleSave = async () => {
|
|
@@ -47,7 +61,7 @@ export function SellerPayoutSettingsView({ apiBase = "/api/store/payout-settings
|
|
|
47
61
|
setSuccess(false);
|
|
48
62
|
setSaving(true);
|
|
49
63
|
try {
|
|
50
|
-
const
|
|
64
|
+
const methodFields = draft.method === "upi"
|
|
51
65
|
? { method: "upi", upiId: draft.upiId.trim() }
|
|
52
66
|
: {
|
|
53
67
|
method: "bank_transfer",
|
|
@@ -57,6 +71,18 @@ export function SellerPayoutSettingsView({ apiBase = "/api/store/payout-settings
|
|
|
57
71
|
bankName: draft.bankName.trim(),
|
|
58
72
|
accountType: draft.accountType,
|
|
59
73
|
};
|
|
74
|
+
const body = {
|
|
75
|
+
...methodFields,
|
|
76
|
+
taxInfo: {
|
|
77
|
+
gstin: draft.gstin.trim(),
|
|
78
|
+
pan: draft.pan.trim(),
|
|
79
|
+
businessType: draft.businessType.trim(),
|
|
80
|
+
},
|
|
81
|
+
preferences: {
|
|
82
|
+
autoPayout: draft.autoPayout,
|
|
83
|
+
minimumThreshold: Math.round(parseFloat(draft.minimumThreshold || "0") * 100),
|
|
84
|
+
},
|
|
85
|
+
};
|
|
60
86
|
const res = await fetch(apiBase, {
|
|
61
87
|
method: "PATCH",
|
|
62
88
|
headers: { "Content-Type": "application/json" },
|
|
@@ -68,7 +94,6 @@ export function SellerPayoutSettingsView({ apiBase = "/api/store/payout-settings
|
|
|
68
94
|
setSuccess(true);
|
|
69
95
|
const updated = json?.data?.payoutDetails ?? { method: draft.method, isConfigured: false };
|
|
70
96
|
setCurrent(updated);
|
|
71
|
-
// clear sensitive field
|
|
72
97
|
setDraft((prev) => ({ ...prev, accountNumber: "" }));
|
|
73
98
|
}
|
|
74
99
|
catch (err) {
|
|
@@ -78,14 +103,27 @@ export function SellerPayoutSettingsView({ apiBase = "/api/store/payout-settings
|
|
|
78
103
|
setSaving(false);
|
|
79
104
|
}
|
|
80
105
|
};
|
|
81
|
-
const isUpi = draft.method === "upi";
|
|
82
106
|
const busy = loading || saving;
|
|
83
|
-
|
|
84
|
-
|
|
107
|
+
const steps = [
|
|
108
|
+
{
|
|
109
|
+
label: "Payout Method",
|
|
110
|
+
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Payout Method" }), current && (_jsx(Div, { className: "flex items-center gap-2 mb-2", 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"
|
|
85
111
|
? `Current UPI: ${current.upiId}`
|
|
86
|
-
: `Current bank: ${current.bankAccount?.bankName ?? ""} — ••••${current.bankAccount?.accountNumberMasked?.slice(-4) ?? "••••"} (${current.bankAccount?.accountType})` })),
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
112
|
+
: `Current bank: ${current.bankAccount?.bankName ?? ""} — ••••${current.bankAccount?.accountNumberMasked?.slice(-4) ?? "••••"} (${current.bankAccount?.accountType})` })), _jsx(Stack, { gap: "sm", children: ([
|
|
113
|
+
{ value: "upi", label: "UPI", desc: "Instant payouts via UPI VPA (e.g. name@upi)." },
|
|
114
|
+
{ value: "bank_transfer", label: "Bank Transfer", desc: "NEFT/RTGS to your bank account within 2–3 business days." },
|
|
115
|
+
]).map(({ value, label, desc }) => (_jsxs("label", { className: "flex items-center gap-3 p-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("input", { type: "radio", name: "payoutMethod", value: value, checked: values.method === value, onChange: () => onChange({ method: value }), className: "accent-[var(--appkit-color-primary)]", disabled: busy }), _jsxs(Div, { children: [_jsx(Text, { className: "font-medium", children: label }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: desc })] })] }, value))) }), 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: "text-sm font-medium mb-1.5", children: "Account Type" }), _jsx(Stack, { gap: "xs", className: "flex-row", children: ["savings", "current"].map((t) => (_jsxs("label", { className: "flex items-center gap-2 cursor-pointer", children: [_jsx("input", { type: "radio", name: "accountType", value: t, checked: values.accountType === t, onChange: () => onChange({ accountType: t }), className: "accent-[var(--appkit-color-primary)]", disabled: busy }), _jsx(Text, { className: "capitalize text-sm", children: t })] }, t))) })] })] })] }))] })),
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
label: "Tax Info",
|
|
119
|
+
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Tax Information" }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "Optional \u2014 required only for GST invoice generation and TDS compliance." }), _jsx(FormField, { name: "gstin", label: "GSTIN (optional)", type: "text", value: values.gstin, onChange: (v) => onChange({ gstin: v.toUpperCase() }), placeholder: "e.g. 22AAAAA0000A1Z5", helpText: "15-character Goods and Services Tax Identification Number.", disabled: busy }), _jsx(FormField, { name: "pan", label: "PAN (optional)", type: "text", value: values.pan, onChange: (v) => onChange({ pan: v.toUpperCase() }), placeholder: "e.g. ABCDE1234F", helpText: "Required for payouts above \u20B950,000 per year (TDS threshold).", disabled: busy }), _jsx(FormField, { name: "businessType", label: "Business Type (optional)", type: "text", value: values.businessType, onChange: (v) => onChange({ businessType: v }), placeholder: "e.g. Individual, Sole Proprietor, Private Limited", disabled: busy })] })),
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
label: "Preferences",
|
|
123
|
+
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Payout Preferences" }), _jsx(Toggle, { checked: values.autoPayout, onChange: (checked) => onChange({ autoPayout: checked }), label: "Enable auto-payout \u2014 automatically transfer earnings on schedule", disabled: busy }), _jsx(FormField, { name: "minimumThreshold", label: "Minimum Payout Threshold (\u20B9)", type: "number", value: values.minimumThreshold, onChange: (v) => onChange({ minimumThreshold: v }), placeholder: "e.g. 500", helpText: "Payouts are held until your balance exceeds this amount. Leave blank for no minimum.", disabled: busy }), _jsxs(Div, { className: "p-3 rounded-lg bg-[var(--appkit-color-surface-alt)] border border-[var(--appkit-color-border)]", children: [_jsx(Text, { className: "text-sm font-medium mb-1", children: "Payout Schedule" }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "Auto-payouts run every Monday for the previous week's settled orders. Manual payouts can be requested from the Payouts page at any time." })] })] })),
|
|
124
|
+
},
|
|
125
|
+
];
|
|
126
|
+
return (_jsx(StackedViewShell, { portal: "seller", title: "Payout Settings", sections: [
|
|
127
|
+
_jsxs("div", { children: [error && _jsx(Alert, { variant: "error", className: "mb-4", children: error }), success && _jsx(Alert, { variant: "success", className: "mb-4", children: "Payout details saved." }), _jsx(StepForm, { steps: steps, values: draft, onChange: update, onComplete: handleSave, formId: "seller-payout-settings", currentStep: currentStep, onStepChange: setCurrentStep, completeLabel: "Save Payout Details", isLoading: busy })] }, "payout"),
|
|
90
128
|
] }));
|
|
91
129
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
export type ProductListingMode = "standard" | "auction" | "pre-order" | "prize-draw" | "classified" | "digital-code" | "live";
|
|
2
|
+
export type ProductListingMode = "standard" | "auction" | "pre-order" | "prize-draw" | "bundle" | "classified" | "digital-code" | "live";
|
|
3
3
|
export interface SellerProductDraft {
|
|
4
4
|
title?: string;
|
|
5
5
|
slug?: string;
|
|
@@ -210,13 +210,15 @@ export function SellerProductShell({ mode, listingType = "standard", initialValu
|
|
|
210
210
|
? "Auction"
|
|
211
211
|
: listingType === "pre-order"
|
|
212
212
|
? "Pre-Order"
|
|
213
|
-
: listingType === "
|
|
214
|
-
? "
|
|
215
|
-
: listingType === "
|
|
216
|
-
? "
|
|
217
|
-
: listingType === "
|
|
218
|
-
? "
|
|
219
|
-
: "
|
|
213
|
+
: listingType === "bundle"
|
|
214
|
+
? "Bundle"
|
|
215
|
+
: listingType === "classified"
|
|
216
|
+
? "Classified"
|
|
217
|
+
: listingType === "digital-code"
|
|
218
|
+
? "Digital Code"
|
|
219
|
+
: listingType === "live"
|
|
220
|
+
? "Live Item"
|
|
221
|
+
: "Product";
|
|
220
222
|
const typeSpecificStep = listingType === "auction"
|
|
221
223
|
? {
|
|
222
224
|
label: "Auction Settings",
|
|
@@ -3,6 +3,8 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
3
3
|
import { X } from "lucide-react";
|
|
4
4
|
import { Button, Div, FilterChipGroup, Row, Text } from "../../../ui";
|
|
5
5
|
import { INPUT_CLS, FILTER_LABEL_CLS } from "./seller-products-styles";
|
|
6
|
+
import { CategoryInlineSelect } from "./CategoryInlineSelect";
|
|
7
|
+
import { BrandInlineSelect } from "./BrandInlineSelect";
|
|
6
8
|
const HALF_INPUT_CLS = INPUT_CLS.replace("w-full", "w-1/2");
|
|
7
9
|
const CONDITION_OPTIONS = [
|
|
8
10
|
{ value: "", label: "Any" },
|
|
@@ -16,5 +18,5 @@ export function SellerProductsFilterDrawer({ isOpen, pendingFilters, statusOptio
|
|
|
16
18
|
if (!isOpen)
|
|
17
19
|
return null;
|
|
18
20
|
const patch = (k, v) => onChange({ ...pendingFilters, [k]: v });
|
|
19
|
-
return (_jsxs(_Fragment, { children: [_jsx(Div, { role: "presentation", className: "fixed inset-0 z-40 bg-black/40", onClick: onClose }), _jsxs(Div, { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-[var(--appkit-color-surface)] shadow-2xl", children: [_jsxs(Row, { justify: "between", className: "border-b border-[var(--appkit-color-border)] px-4 py-3.5", children: [_jsx(Text, { className: "text-base font-semibold text-[var(--appkit-color-text)]", children: "Filters" }), _jsxs(Row, { className: "gap-2", children: [activeFilterCount > 0 && (_jsx(Button, { variant: "ghost", size: "sm", onClick: onClear, className: "text-xs text-[var(--appkit-color-text-muted)] hover:text-[var(--appkit-color-error)]", children: "Clear all" })), _jsx(Button, { variant: "ghost", size: "sm", onClick: onClose, "aria-label": "Close filters", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsxs(Div, { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: [_jsx(FilterChipGroup, { label: "Status", tabs: statusOptions, value: pendingFilters.status ?? "", onChange: (id) => patch("status", id) }), _jsxs(Div, { className: "space-y-1.5", children: [_jsx(Text, { className: FILTER_LABEL_CLS, children: "Category" }), _jsx(
|
|
21
|
+
return (_jsxs(_Fragment, { children: [_jsx(Div, { role: "presentation", className: "fixed inset-0 z-40 bg-black/40", onClick: onClose }), _jsxs(Div, { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-[var(--appkit-color-surface)] shadow-2xl", children: [_jsxs(Row, { justify: "between", className: "border-b border-[var(--appkit-color-border)] px-4 py-3.5", children: [_jsx(Text, { className: "text-base font-semibold text-[var(--appkit-color-text)]", children: "Filters" }), _jsxs(Row, { className: "gap-2", children: [activeFilterCount > 0 && (_jsx(Button, { variant: "ghost", size: "sm", onClick: onClear, className: "text-xs text-[var(--appkit-color-text-muted)] hover:text-[var(--appkit-color-error)]", children: "Clear all" })), _jsx(Button, { variant: "ghost", size: "sm", onClick: onClose, "aria-label": "Close filters", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsxs(Div, { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: [_jsx(FilterChipGroup, { label: "Status", tabs: statusOptions, value: pendingFilters.status ?? "", onChange: (id) => patch("status", id) }), _jsxs(Div, { className: "space-y-1.5", children: [_jsx(Text, { className: FILTER_LABEL_CLS, children: "Category" }), _jsx(CategoryInlineSelect, { value: pendingFilters.category ?? "", onChange: (v) => patch("category", v), placeholder: "Search categories\u2026" })] }), _jsxs(Div, { className: "space-y-1.5", children: [_jsx(Text, { className: FILTER_LABEL_CLS, children: "Brand" }), _jsx(BrandInlineSelect, { value: pendingFilters.brand ?? "", onChange: (v) => patch("brand", v), placeholder: "Search brands\u2026", allowCreate: false })] }), _jsxs(Div, { className: "space-y-1.5", children: [_jsx(Text, { className: FILTER_LABEL_CLS, children: "Condition" }), _jsx("select", { value: pendingFilters.condition ?? "", onChange: (e) => patch("condition", e.target.value), className: INPUT_CLS, children: CONDITION_OPTIONS.map((o) => (_jsx("option", { value: o.value, children: o.label }, o.value))) })] }), _jsxs(Div, { className: "space-y-1.5", children: [_jsx(Text, { className: FILTER_LABEL_CLS, children: "Price (\u20B9 Rupees)" }), _jsxs(Row, { className: "gap-2", children: [_jsx("input", { type: "number", min: 0, value: pendingFilters.minPrice ?? "", onChange: (e) => patch("minPrice", e.target.value), placeholder: "min", className: HALF_INPUT_CLS }), _jsx("input", { type: "number", min: 0, value: pendingFilters.maxPrice ?? "", onChange: (e) => patch("maxPrice", e.target.value), placeholder: "max", className: HALF_INPUT_CLS })] })] }), _jsxs(Div, { className: "space-y-1.5", children: [_jsx(Text, { className: FILTER_LABEL_CLS, children: "Tags (comma-separated)" }), _jsx("input", { type: "text", value: pendingFilters.tags ?? "", onChange: (e) => patch("tags", e.target.value), placeholder: "pokemon, vintage, holo", className: INPUT_CLS })] }), _jsxs(Div, { className: "space-y-1.5", children: [_jsx(Text, { className: FILTER_LABEL_CLS, children: "Badges (feature slugs)" }), _jsx("input", { type: "text", value: pendingFilters.badges ?? "", onChange: (e) => patch("badges", e.target.value), placeholder: "feature-free-shipping, feature-verified", className: INPUT_CLS })] })] }), _jsx(Div, { className: "border-t border-[var(--appkit-color-border)] px-4 py-3.5", children: _jsxs(Button, { variant: "primary", onClick: onApply, className: "w-full rounded-lg py-2.5 active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }));
|
|
20
22
|
}
|