@mohasinac/appkit 2.7.54 → 2.7.55
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/runtime/adapters/firebase.js +5 -14
- package/dist/_internal/shared/actions/action-registry.js +827 -4
- package/dist/_internal/shared/features/events/schema.d.ts +4 -4
- package/dist/constants/api-endpoints.d.ts +3 -0
- package/dist/constants/api-endpoints.js +1 -0
- package/dist/features/account/components/UserOffersPanel.js +2 -1
- package/dist/features/admin/components/AdminAllEventEntriesView.js +4 -3
- package/dist/features/admin/components/AdminBidsView.js +5 -3
- package/dist/features/admin/components/AdminBlogView.js +3 -2
- package/dist/features/admin/components/AdminBrandsView.js +2 -1
- package/dist/features/admin/components/AdminBundleEditorView.js +4 -5
- package/dist/features/admin/components/AdminBundlesView.js +3 -3
- package/dist/features/admin/components/AdminCarouselView.d.ts +2 -1
- package/dist/features/admin/components/AdminCarouselView.js +14 -5
- package/dist/features/admin/components/AdminCategoriesView.js +2 -1
- package/dist/features/admin/components/AdminContactView.d.ts +4 -1
- package/dist/features/admin/components/AdminContactView.js +27 -7
- package/dist/features/admin/components/AdminCouponsView.d.ts +3 -1
- package/dist/features/admin/components/AdminCouponsView.js +17 -3
- package/dist/features/admin/components/AdminFaqsView.d.ts +3 -1
- package/dist/features/admin/components/AdminFaqsView.js +18 -4
- package/dist/features/admin/components/AdminFeaturesView.js +2 -1
- package/dist/features/admin/components/AdminMediaView.js +3 -2
- package/dist/features/admin/components/AdminNavigationView.js +3 -2
- package/dist/features/admin/components/AdminNewsletterView.d.ts +2 -1
- package/dist/features/admin/components/AdminNewsletterView.js +13 -4
- package/dist/features/admin/components/AdminNotificationsView.js +6 -4
- package/dist/features/admin/components/AdminOrdersView.js +4 -3
- package/dist/features/admin/components/AdminPayoutsView.js +2 -2
- package/dist/features/admin/components/AdminPrizeDrawsView.js +2 -1
- package/dist/features/admin/components/AdminProductsView.js +3 -3
- package/dist/features/admin/components/AdminReviewsView.js +4 -3
- package/dist/features/admin/components/AdminScammersView.js +2 -1
- package/dist/features/admin/components/AdminSessionsView.js +5 -3
- package/dist/features/admin/components/AdminStoresView.js +2 -2
- package/dist/features/admin/components/AdminSublistingCategoriesView.d.ts +5 -1
- package/dist/features/admin/components/AdminSublistingCategoriesView.js +12 -3
- package/dist/features/admin/components/AdminSupportTicketsView.js +2 -1
- package/dist/features/admin/components/AdminTeamView.d.ts +2 -1
- package/dist/features/admin/components/AdminTeamView.js +13 -4
- package/dist/features/admin/components/AdminUsersView.js +2 -2
- package/dist/features/products/constants/action-defs.d.ts +86 -7
- package/dist/features/products/constants/action-defs.js +99 -7
- package/dist/features/seller/components/QuickProductForm.d.ts +13 -0
- package/dist/features/seller/components/QuickProductForm.js +50 -0
- package/dist/features/seller/components/SellerAuctionsView.d.ts +4 -1
- package/dist/features/seller/components/SellerAuctionsView.js +37 -3
- package/dist/features/seller/components/SellerBidsView.js +2 -1
- package/dist/features/seller/components/SellerBundlesView.d.ts +3 -1
- package/dist/features/seller/components/SellerBundlesView.js +38 -5
- package/dist/features/seller/components/SellerClassifiedView.d.ts +3 -1
- package/dist/features/seller/components/SellerClassifiedView.js +37 -4
- package/dist/features/seller/components/SellerDigitalCodesView.d.ts +3 -1
- package/dist/features/seller/components/SellerDigitalCodesView.js +37 -4
- package/dist/features/seller/components/SellerGoogleReviewsView.js +2 -1
- package/dist/features/seller/components/SellerGroupedListingsView.js +3 -2
- package/dist/features/seller/components/SellerLiveView.d.ts +3 -1
- package/dist/features/seller/components/SellerLiveView.js +37 -4
- package/dist/features/seller/components/SellerOffersPanel.js +2 -1
- package/dist/features/seller/components/SellerOffersView.d.ts +4 -1
- package/dist/features/seller/components/SellerOffersView.js +8 -3
- package/dist/features/seller/components/SellerPayoutsView.d.ts +3 -1
- package/dist/features/seller/components/SellerPayoutsView.js +7 -3
- package/dist/features/seller/components/SellerPreOrdersView.d.ts +2 -1
- package/dist/features/seller/components/SellerPreOrdersView.js +30 -7
- package/dist/features/seller/components/SellerPrizeDrawsView.d.ts +2 -1
- package/dist/features/seller/components/SellerPrizeDrawsView.js +30 -7
- package/dist/features/seller/components/SellerProductShell.js +12 -0
- package/dist/features/seller/components/SellerReviewsView.js +2 -1
- package/dist/features/seller/components/SellerShippingConfigsView.js +3 -2
- package/dist/features/seller/components/SellerStoreCategoriesView.js +6 -5
- package/dist/features/seller/components/SellerTemplatesView.js +4 -3
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +30 -16
- package/dist/styles.css +1 -1
- package/dist/tailwind-utilities.css +1 -1
- package/package.json +1 -1
|
@@ -4,8 +4,9 @@ import { useState, useCallback } from "react";
|
|
|
4
4
|
import { Plus } from "lucide-react";
|
|
5
5
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
6
|
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
7
|
-
import { BulkActionBar, Button, DataTable, Div, ListingToolbar, Pagination, Text, } from "../../../ui";
|
|
7
|
+
import { BulkActionBar, Button, ConfirmDeleteModal, DataTable, Div, ListingToolbar, Pagination, RowActionMenu, Text, } from "../../../ui";
|
|
8
8
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
9
|
+
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
9
10
|
import { ROUTES } from "../../..";
|
|
10
11
|
import { toRecordArray, toRelativeDate, toRupees, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
|
|
11
12
|
import { TABLE_KEYS } from "../../../constants/table-keys";
|
|
@@ -54,10 +55,12 @@ const COLUMNS = [
|
|
|
54
55
|
render: (row) => _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: row.createdAt }),
|
|
55
56
|
},
|
|
56
57
|
];
|
|
57
|
-
export function SellerClassifiedView({ onCreateClick, onBulkDelete, }) {
|
|
58
|
+
export function SellerClassifiedView({ onCreateClick, onEditClick, onDelete, onBulkDelete, }) {
|
|
58
59
|
const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
|
|
59
60
|
const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
|
|
60
61
|
const [view] = useState("table");
|
|
62
|
+
const [deleteTargetId, setDeleteTargetId] = useState(null);
|
|
63
|
+
const [deletingId, setDeletingId] = useState(null);
|
|
61
64
|
const commitSearch = useCallback(() => {
|
|
62
65
|
table.set(TABLE_KEYS.QUERY, searchInput.trim());
|
|
63
66
|
}, [searchInput, table]);
|
|
@@ -96,11 +99,30 @@ export function SellerClassifiedView({ onCreateClick, onBulkDelete, }) {
|
|
|
96
99
|
const bulkActions = onBulkDelete
|
|
97
100
|
? [{
|
|
98
101
|
id: "bulk-delete",
|
|
99
|
-
label: "
|
|
102
|
+
label: ACTIONS.STORE["delete-listing"].label,
|
|
100
103
|
variant: "danger",
|
|
101
104
|
onClick: async () => { await onBulkDelete(selection.selectedIds); selection.clearSelection(); },
|
|
102
105
|
}]
|
|
103
106
|
: [];
|
|
107
|
+
const handleDelete = useCallback(async (id) => {
|
|
108
|
+
setDeletingId(id);
|
|
109
|
+
try {
|
|
110
|
+
if (onDelete)
|
|
111
|
+
await onDelete(id);
|
|
112
|
+
else
|
|
113
|
+
await fetch(`/api/store/products/${id}`, { method: "DELETE", credentials: "include" });
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
setDeletingId(null);
|
|
117
|
+
setDeleteTargetId(null);
|
|
118
|
+
}
|
|
119
|
+
}, [onDelete]);
|
|
120
|
+
const handleEdit = useCallback((id) => {
|
|
121
|
+
if (onEditClick)
|
|
122
|
+
onEditClick(id);
|
|
123
|
+
else
|
|
124
|
+
window.location.href = String(ROUTES.STORE.CLASSIFIED_EDIT(id));
|
|
125
|
+
}, [onEditClick]);
|
|
104
126
|
const handleCreate = useCallback(() => {
|
|
105
127
|
if (onCreateClick) {
|
|
106
128
|
onCreateClick();
|
|
@@ -109,5 +131,16 @@ export function SellerClassifiedView({ onCreateClick, onBulkDelete, }) {
|
|
|
109
131
|
window.location.href = String(ROUTES.STORE.CLASSIFIED_NEW);
|
|
110
132
|
}
|
|
111
133
|
}, [onCreateClick]);
|
|
112
|
-
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: 0, searchValue: searchInput, searchPlaceholder: "Search classified listings...", 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 Classified" })] }) }), 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 classified listings yet \u2014 post your first buy/sell/trade ad" }) })) : (_jsx(DataTable, { columns: COLUMNS, data: rows, keyExtractor: (r) => r.id, selectable: bulkActions.length > 0, selectedIds: selection.selectedIds, onSelectionChange: (ids) => selection.setSelectedIds(ids)
|
|
134
|
+
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: 0, searchValue: searchInput, searchPlaceholder: "Search classified listings...", 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 Classified" })] }) }), 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 classified listings yet \u2014 post your first buy/sell/trade ad" }) })) : (_jsx(DataTable, { columns: COLUMNS, data: rows, keyExtractor: (r) => r.id, selectable: bulkActions.length > 0, selectedIds: selection.selectedIds, onSelectionChange: (ids) => selection.setSelectedIds(ids), actions: (row) => (_jsx(RowActionMenu, { actions: [
|
|
135
|
+
{
|
|
136
|
+
label: ACTIONS.STORE["edit-listing"].label,
|
|
137
|
+
onClick: () => handleEdit(row.id),
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
label: ACTIONS.STORE["delete-listing"].label,
|
|
141
|
+
destructive: true,
|
|
142
|
+
onClick: () => setDeleteTargetId(row.id),
|
|
143
|
+
disabled: deletingId === row.id,
|
|
144
|
+
},
|
|
145
|
+
] })) }))] }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Classified Listing", message: "Are you sure you want to delete this classified listing? This cannot be undone.", onConfirm: () => handleDelete(deleteTargetId), onClose: () => setDeleteTargetId(null), isDeleting: deletingId === deleteTargetId }))] }));
|
|
113
146
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export interface SellerDigitalCodesViewProps {
|
|
2
2
|
onCreateClick?: () => void;
|
|
3
|
+
onEditClick?: (id: string) => void;
|
|
4
|
+
onDelete?: (id: string) => Promise<void>;
|
|
3
5
|
onBulkDelete?: (ids: string[]) => Promise<void>;
|
|
4
6
|
}
|
|
5
|
-
export declare function SellerDigitalCodesView({ onCreateClick, onBulkDelete, }: SellerDigitalCodesViewProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare function SellerDigitalCodesView({ onCreateClick, onEditClick, onDelete, onBulkDelete, }: SellerDigitalCodesViewProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -4,8 +4,9 @@ import { useState, useCallback } from "react";
|
|
|
4
4
|
import { Plus } from "lucide-react";
|
|
5
5
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
6
|
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
7
|
-
import { BulkActionBar, Button, DataTable, Div, ListingToolbar, Pagination, Text, } from "../../../ui";
|
|
7
|
+
import { BulkActionBar, Button, ConfirmDeleteModal, DataTable, Div, ListingToolbar, Pagination, RowActionMenu, Text, } from "../../../ui";
|
|
8
8
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
9
|
+
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
9
10
|
import { ROUTES } from "../../..";
|
|
10
11
|
import { toRecordArray, toRelativeDate, toRupees, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
|
|
11
12
|
import { TABLE_KEYS } from "../../../constants/table-keys";
|
|
@@ -56,10 +57,12 @@ const COLUMNS = [
|
|
|
56
57
|
render: (row) => _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: row.createdAt }),
|
|
57
58
|
},
|
|
58
59
|
];
|
|
59
|
-
export function SellerDigitalCodesView({ onCreateClick, onBulkDelete, }) {
|
|
60
|
+
export function SellerDigitalCodesView({ onCreateClick, onEditClick, onDelete, onBulkDelete, }) {
|
|
60
61
|
const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
|
|
61
62
|
const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
|
|
62
63
|
const [view] = useState("table");
|
|
64
|
+
const [deleteTargetId, setDeleteTargetId] = useState(null);
|
|
65
|
+
const [deletingId, setDeletingId] = useState(null);
|
|
63
66
|
const commitSearch = useCallback(() => {
|
|
64
67
|
table.set(TABLE_KEYS.QUERY, searchInput.trim());
|
|
65
68
|
}, [searchInput, table]);
|
|
@@ -98,11 +101,30 @@ export function SellerDigitalCodesView({ onCreateClick, onBulkDelete, }) {
|
|
|
98
101
|
const bulkActions = onBulkDelete
|
|
99
102
|
? [{
|
|
100
103
|
id: "bulk-delete",
|
|
101
|
-
label: "
|
|
104
|
+
label: ACTIONS.STORE["delete-listing"].label,
|
|
102
105
|
variant: "danger",
|
|
103
106
|
onClick: async () => { await onBulkDelete(selection.selectedIds); selection.clearSelection(); },
|
|
104
107
|
}]
|
|
105
108
|
: [];
|
|
109
|
+
const handleDelete = useCallback(async (id) => {
|
|
110
|
+
setDeletingId(id);
|
|
111
|
+
try {
|
|
112
|
+
if (onDelete)
|
|
113
|
+
await onDelete(id);
|
|
114
|
+
else
|
|
115
|
+
await fetch(`/api/store/products/${id}`, { method: "DELETE", credentials: "include" });
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
setDeletingId(null);
|
|
119
|
+
setDeleteTargetId(null);
|
|
120
|
+
}
|
|
121
|
+
}, [onDelete]);
|
|
122
|
+
const handleEdit = useCallback((id) => {
|
|
123
|
+
if (onEditClick)
|
|
124
|
+
onEditClick(id);
|
|
125
|
+
else
|
|
126
|
+
window.location.href = String(ROUTES.STORE.DIGITAL_CODES_EDIT(id));
|
|
127
|
+
}, [onEditClick]);
|
|
106
128
|
const handleCreate = useCallback(() => {
|
|
107
129
|
if (onCreateClick) {
|
|
108
130
|
onCreateClick();
|
|
@@ -111,5 +133,16 @@ export function SellerDigitalCodesView({ onCreateClick, onBulkDelete, }) {
|
|
|
111
133
|
window.location.href = String(ROUTES.STORE.DIGITAL_CODES_NEW);
|
|
112
134
|
}
|
|
113
135
|
}, [onCreateClick]);
|
|
114
|
-
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: 0, searchValue: searchInput, searchPlaceholder: "Search digital code products...", 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 Digital Code" })] }) }), 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 digital code products yet \u2014 sell Steam keys, gift cards, and more" }) })) : (_jsx(DataTable, { columns: COLUMNS, data: rows, keyExtractor: (r) => r.id, selectable: bulkActions.length > 0, selectedIds: selection.selectedIds, onSelectionChange: (ids) => selection.setSelectedIds(ids)
|
|
136
|
+
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: 0, searchValue: searchInput, searchPlaceholder: "Search digital code products...", 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 Digital Code" })] }) }), 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 digital code products yet \u2014 sell Steam keys, gift cards, and more" }) })) : (_jsx(DataTable, { columns: COLUMNS, data: rows, keyExtractor: (r) => r.id, selectable: bulkActions.length > 0, selectedIds: selection.selectedIds, onSelectionChange: (ids) => selection.setSelectedIds(ids), actions: (row) => (_jsx(RowActionMenu, { actions: [
|
|
137
|
+
{
|
|
138
|
+
label: ACTIONS.STORE["edit-listing"].label,
|
|
139
|
+
onClick: () => handleEdit(row.id),
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
label: ACTIONS.STORE["delete-listing"].label,
|
|
143
|
+
destructive: true,
|
|
144
|
+
onClick: () => setDeleteTargetId(row.id),
|
|
145
|
+
disabled: deletingId === row.id,
|
|
146
|
+
},
|
|
147
|
+
] })) }))] }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Digital Code Product", message: "Are you sure you want to delete this digital code product? This cannot be undone.", onConfirm: () => handleDelete(deleteTargetId), onClose: () => setDeleteTargetId(null), isDeleting: deletingId === deleteTargetId }))] }));
|
|
115
148
|
}
|
|
@@ -4,6 +4,7 @@ import { useCallback, useEffect, useState } from "react";
|
|
|
4
4
|
import { RefreshCw } from "lucide-react";
|
|
5
5
|
import { Alert, Button, Div, FormField, Heading, Section, Stack, Text, Toggle, } from "../../../ui";
|
|
6
6
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
7
|
+
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
7
8
|
const EMPTY_DRAFT = {
|
|
8
9
|
placeId: "",
|
|
9
10
|
businessName: "",
|
|
@@ -91,5 +92,5 @@ export function SellerGoogleReviewsView({ onSave, onSync, }) {
|
|
|
91
92
|
timeStyle: "short",
|
|
92
93
|
})
|
|
93
94
|
: "Never";
|
|
94
|
-
return (_jsx("div", { className: "py-4 px-3 sm:px-4 max-w-2xl", children: _jsxs(Stack, { gap: "lg", children: [_jsxs(Section, { children: [_jsx(Heading, { level: 3, className: "mb-1", children: "Google Business Settings" }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)] mb-4", children: "Connect your Google Business profile to sync reviews to your storefront." }), _jsxs(Stack, { gap: "md", children: [_jsx(Toggle, { checked: draft.isConnected, onChange: (v) => setDraft((d) => ({ ...d, isConnected: v })), label: "Show Google reviews on my store page" }), _jsx(FormField, { name: "placeId", label: "Google Place ID", type: "text", value: draft.placeId, onChange: (v) => setDraft((d) => ({ ...d, placeId: v })), placeholder: "ChIJ\u2026", helpText: "Find your Place ID at developers.google.com/maps/documentation/places/web-service/place-id" }), _jsx(FormField, { name: "businessName", label: "Business name", type: "text", value: draft.businessName, onChange: (v) => setDraft((d) => ({ ...d, businessName: v })), placeholder: "Pok\u00E9mon Palace" })] })] }), (draft.averageRating !== undefined || draft.totalReviews !== undefined) && (_jsxs(Section, { children: [_jsx(Heading, { level: 3, className: "mb-3", children: "Review Stats" }), _jsxs("div", { className: "flex flex-wrap gap-6", children: [draft.averageRating !== undefined && (_jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)] uppercase tracking-wide", children: "Avg rating" }), _jsx(Text, { className: "text-2xl font-bold tabular-nums", children: draft.averageRating.toFixed(1) })] })), draft.totalReviews !== undefined && (_jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)] uppercase tracking-wide", children: "Total reviews" }), _jsx(Text, { className: "text-2xl font-bold tabular-nums", children: draft.totalReviews })] })), _jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)] uppercase tracking-wide", children: "Last synced" }), _jsx(Text, { className: "text-sm", children: formattedLastSync })] })] })] })), saveMessage && (_jsx(Alert, { variant: saveMessage.ok ? "success" : "error", children: saveMessage.text })), _jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-[var(--appkit-color-border)] pt-4", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: handleSync, isLoading: syncing, disabled: saving || !draft.placeId.trim(), className: "flex items-center gap-1.5", children: [_jsx(RefreshCw, { className: "h-3.5 w-3.5" }), "
|
|
95
|
+
return (_jsx("div", { className: "py-4 px-3 sm:px-4 max-w-2xl", children: _jsxs(Stack, { gap: "lg", children: [_jsxs(Section, { children: [_jsx(Heading, { level: 3, className: "mb-1", children: "Google Business Settings" }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)] mb-4", children: "Connect your Google Business profile to sync reviews to your storefront." }), _jsxs(Stack, { gap: "md", children: [_jsx(Toggle, { checked: draft.isConnected, onChange: (v) => setDraft((d) => ({ ...d, isConnected: v })), label: "Show Google reviews on my store page" }), _jsx(FormField, { name: "placeId", label: "Google Place ID", type: "text", value: draft.placeId, onChange: (v) => setDraft((d) => ({ ...d, placeId: v })), placeholder: "ChIJ\u2026", helpText: "Find your Place ID at developers.google.com/maps/documentation/places/web-service/place-id" }), _jsx(FormField, { name: "businessName", label: "Business name", type: "text", value: draft.businessName, onChange: (v) => setDraft((d) => ({ ...d, businessName: v })), placeholder: "Pok\u00E9mon Palace" })] })] }), (draft.averageRating !== undefined || draft.totalReviews !== undefined) && (_jsxs(Section, { children: [_jsx(Heading, { level: 3, className: "mb-3", children: "Review Stats" }), _jsxs("div", { className: "flex flex-wrap gap-6", children: [draft.averageRating !== undefined && (_jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)] uppercase tracking-wide", children: "Avg rating" }), _jsx(Text, { className: "text-2xl font-bold tabular-nums", children: draft.averageRating.toFixed(1) })] })), draft.totalReviews !== undefined && (_jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)] uppercase tracking-wide", children: "Total reviews" }), _jsx(Text, { className: "text-2xl font-bold tabular-nums", children: draft.totalReviews })] })), _jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)] uppercase tracking-wide", children: "Last synced" }), _jsx(Text, { className: "text-sm", children: formattedLastSync })] })] })] })), saveMessage && (_jsx(Alert, { variant: saveMessage.ok ? "success" : "error", children: saveMessage.text })), _jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-[var(--appkit-color-border)] pt-4", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: handleSync, isLoading: syncing, disabled: saving || !draft.placeId.trim(), className: "flex items-center gap-1.5", children: [_jsx(RefreshCw, { className: "h-3.5 w-3.5" }), ACTIONS.STORE["google-reviews-sync"].label] }), _jsx(Button, { variant: "primary", size: "sm", onClick: handleSave, isLoading: saving, disabled: syncing, children: ACTIONS.STORE["save-google-settings"].label })] })] }) }));
|
|
95
96
|
}
|
|
@@ -5,6 +5,7 @@ import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
|
5
5
|
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
6
6
|
import { Badge, BulkActionBar, Button, ListingToolbar, Pagination } from "../../../ui";
|
|
7
7
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
8
|
+
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
8
9
|
import { toRecordArray, toRelativeDate, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
|
|
9
10
|
import { DataTable } from "../../admin/components/DataTable";
|
|
10
11
|
// ---------------------------------------------------------------------------
|
|
@@ -99,7 +100,7 @@ export function SellerGroupedListingsView({ onCreateClick, onEditClick, onDelete
|
|
|
99
100
|
const bulkActions = [
|
|
100
101
|
{
|
|
101
102
|
id: "delete",
|
|
102
|
-
label: "
|
|
103
|
+
label: ACTIONS.STORE["delete-listing"].label,
|
|
103
104
|
variant: "danger",
|
|
104
105
|
onClick: () => {
|
|
105
106
|
for (const id of selection.selectedIds)
|
|
@@ -108,5 +109,5 @@ export function SellerGroupedListingsView({ onCreateClick, onEditClick, onDelete
|
|
|
108
109
|
},
|
|
109
110
|
},
|
|
110
111
|
];
|
|
111
|
-
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { searchValue: searchInput, searchPlaceholder: "Search grouped listings", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: onCreateClick ? (_jsx(Button, { size: "sm", onClick: onCreateClick, children: "+ New Group" })) : null }), selection.selectedCount > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), 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) }) })), _jsx(DataTable, { columns: COLUMNS, rows: rows, isLoading: isLoading, emptyLabel: errorMessage ?? "No grouped listings yet", selectedIds: selection.selectedIdSet, onToggleSelect: (id, _selected) => selection.toggle(id), onToggleSelectAll: (_next) => selection.toggleAll(), renderRowActions: (row) => (_jsxs("div", { className: "flex gap-1", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: () => onEditClick?.(row.id), children: "
|
|
112
|
+
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { searchValue: searchInput, searchPlaceholder: "Search grouped listings", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: onCreateClick ? (_jsx(Button, { size: "sm", onClick: onCreateClick, children: "+ New Group" })) : null }), selection.selectedCount > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), 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) }) })), _jsx(DataTable, { columns: COLUMNS, rows: rows, isLoading: isLoading, emptyLabel: errorMessage ?? "No grouped listings yet", selectedIds: selection.selectedIdSet, onToggleSelect: (id, _selected) => selection.toggle(id), onToggleSelectAll: (_next) => selection.toggleAll(), renderRowActions: (row) => (_jsxs("div", { className: "flex gap-1", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: () => onEditClick?.(row.id), children: ACTIONS.STORE["edit-listing"].label }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => onDeleteClick?.(row.id), children: ACTIONS.STORE["delete-listing"].label })] })) })] }));
|
|
112
113
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export interface SellerLiveViewProps {
|
|
2
2
|
onCreateClick?: () => void;
|
|
3
|
+
onEditClick?: (id: string) => void;
|
|
4
|
+
onDelete?: (id: string) => Promise<void>;
|
|
3
5
|
onBulkDelete?: (ids: string[]) => Promise<void>;
|
|
4
6
|
}
|
|
5
|
-
export declare function SellerLiveView({ onCreateClick, onBulkDelete, }: SellerLiveViewProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare function SellerLiveView({ onCreateClick, onEditClick, onDelete, onBulkDelete, }: SellerLiveViewProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -4,8 +4,9 @@ import { useState, useCallback } from "react";
|
|
|
4
4
|
import { Plus } from "lucide-react";
|
|
5
5
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
6
|
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
7
|
-
import { BulkActionBar, Button, DataTable, Div, ListingToolbar, Pagination, Text, } from "../../../ui";
|
|
7
|
+
import { BulkActionBar, Button, ConfirmDeleteModal, DataTable, Div, ListingToolbar, Pagination, RowActionMenu, Text, } from "../../../ui";
|
|
8
8
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
9
|
+
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
9
10
|
import { ROUTES } from "../../..";
|
|
10
11
|
import { toRecordArray, toRelativeDate, toRupees, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
|
|
11
12
|
import { TABLE_KEYS } from "../../../constants/table-keys";
|
|
@@ -54,10 +55,12 @@ const COLUMNS = [
|
|
|
54
55
|
render: (row) => _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: row.createdAt }),
|
|
55
56
|
},
|
|
56
57
|
];
|
|
57
|
-
export function SellerLiveView({ onCreateClick, onBulkDelete, }) {
|
|
58
|
+
export function SellerLiveView({ onCreateClick, onEditClick, onDelete, onBulkDelete, }) {
|
|
58
59
|
const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
|
|
59
60
|
const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
|
|
60
61
|
const [view] = useState("table");
|
|
62
|
+
const [deleteTargetId, setDeleteTargetId] = useState(null);
|
|
63
|
+
const [deletingId, setDeletingId] = useState(null);
|
|
61
64
|
const commitSearch = useCallback(() => {
|
|
62
65
|
table.set(TABLE_KEYS.QUERY, searchInput.trim());
|
|
63
66
|
}, [searchInput, table]);
|
|
@@ -96,11 +99,30 @@ export function SellerLiveView({ onCreateClick, onBulkDelete, }) {
|
|
|
96
99
|
const bulkActions = onBulkDelete
|
|
97
100
|
? [{
|
|
98
101
|
id: "bulk-delete",
|
|
99
|
-
label: "
|
|
102
|
+
label: ACTIONS.STORE["delete-listing"].label,
|
|
100
103
|
variant: "danger",
|
|
101
104
|
onClick: async () => { await onBulkDelete(selection.selectedIds); selection.clearSelection(); },
|
|
102
105
|
}]
|
|
103
106
|
: [];
|
|
107
|
+
const handleDelete = useCallback(async (id) => {
|
|
108
|
+
setDeletingId(id);
|
|
109
|
+
try {
|
|
110
|
+
if (onDelete)
|
|
111
|
+
await onDelete(id);
|
|
112
|
+
else
|
|
113
|
+
await fetch(`/api/store/products/${id}`, { method: "DELETE", credentials: "include" });
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
setDeletingId(null);
|
|
117
|
+
setDeleteTargetId(null);
|
|
118
|
+
}
|
|
119
|
+
}, [onDelete]);
|
|
120
|
+
const handleEdit = useCallback((id) => {
|
|
121
|
+
if (onEditClick)
|
|
122
|
+
onEditClick(id);
|
|
123
|
+
else
|
|
124
|
+
window.location.href = String(ROUTES.STORE.LIVE_ITEMS_EDIT(id));
|
|
125
|
+
}, [onEditClick]);
|
|
104
126
|
const handleCreate = useCallback(() => {
|
|
105
127
|
if (onCreateClick) {
|
|
106
128
|
onCreateClick();
|
|
@@ -109,5 +131,16 @@ export function SellerLiveView({ onCreateClick, onBulkDelete, }) {
|
|
|
109
131
|
window.location.href = String(ROUTES.STORE.LIVE_ITEMS_NEW);
|
|
110
132
|
}
|
|
111
133
|
}, [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)
|
|
134
|
+
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), actions: (row) => (_jsx(RowActionMenu, { actions: [
|
|
135
|
+
{
|
|
136
|
+
label: ACTIONS.STORE["edit-listing"].label,
|
|
137
|
+
onClick: () => handleEdit(row.id),
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
label: ACTIONS.STORE["delete-listing"].label,
|
|
141
|
+
destructive: true,
|
|
142
|
+
onClick: () => setDeleteTargetId(row.id),
|
|
143
|
+
disabled: deletingId === row.id,
|
|
144
|
+
},
|
|
145
|
+
] })) }))] }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Live Item", message: "Are you sure you want to delete this live item listing? This cannot be undone.", onConfirm: () => handleDelete(deleteTargetId), onClose: () => setDeleteTargetId(null), isDeleting: deletingId === deleteTargetId }))] }));
|
|
113
146
|
}
|
|
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useCallback, useEffect, useState, useTransition } from "react";
|
|
4
4
|
import { Alert, Badge, Button, Div, Heading, Input, LoginRequiredModal, Spinner, Text } from "../../../ui";
|
|
5
5
|
import { isAuthError } from "../../../utils/auth-error";
|
|
6
|
+
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
6
7
|
function formatRupees(amount) {
|
|
7
8
|
if (amount === undefined || amount === null)
|
|
8
9
|
return "—";
|
|
@@ -151,5 +152,5 @@ export function SellerOffersPanel({ fetchEndpoint = "/api/store/offers", onRespo
|
|
|
151
152
|
{ value: "expired", label: "Expired" },
|
|
152
153
|
];
|
|
153
154
|
const pending = offers.filter((o) => o.status === "pending").length;
|
|
154
|
-
return (_jsxs(Div, { className: `space-y-4 ${className}`, children: [_jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to manage offers. Please log in or create an account to continue." }), _jsxs(Div, { className: "flex items-center justify-between flex-wrap gap-2", children: [_jsxs(Div, { children: [_jsx(Heading, { level: 2, className: "text-lg font-semibold text-zinc-900 dark:text-zinc-100", children: "Offers Received" }), pending > 0 && (_jsxs(Text, { className: "text-xs text-amber-600 dark:text-amber-400 mt-0.5", children: [pending, " pending offer", pending > 1 ? "s" : "", " awaiting your response"] }))] }), _jsx(Button, { size: "sm", variant: "ghost", onClick: loadOffers, disabled: loading, className: "border border-zinc-300 dark:border-zinc-600 text-xs", children: loading ? "Refreshing…" : "
|
|
155
|
+
return (_jsxs(Div, { className: `space-y-4 ${className}`, children: [_jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to manage offers. Please log in or create an account to continue." }), _jsxs(Div, { className: "flex items-center justify-between flex-wrap gap-2", children: [_jsxs(Div, { children: [_jsx(Heading, { level: 2, className: "text-lg font-semibold text-zinc-900 dark:text-zinc-100", children: "Offers Received" }), pending > 0 && (_jsxs(Text, { className: "text-xs text-amber-600 dark:text-amber-400 mt-0.5", children: [pending, " pending offer", pending > 1 ? "s" : "", " awaiting your response"] }))] }), _jsx(Button, { size: "sm", variant: "ghost", onClick: loadOffers, disabled: loading, className: "border border-zinc-300 dark:border-zinc-600 text-xs", children: loading ? "Refreshing…" : ACTIONS.STORE["refresh-offers"].label })] }), _jsx(Div, { className: "flex gap-1 flex-wrap", children: STATUS_FILTERS.map((f) => (_jsx(Button, { size: "sm", variant: statusFilter === f.value ? "primary" : "ghost", onClick: () => setStatusFilter(f.value), className: "text-xs px-2 py-1", children: f.label }, f.value))) }), fetchError && _jsx(Alert, { variant: "error", children: _jsx(Text, { className: "text-sm", children: fetchError }) }), loading && (_jsx(Div, { className: "flex justify-center py-12", children: _jsx(Spinner, { size: "lg" }) })), !loading && offers.length === 0 && (_jsx(Div, { className: "text-center py-12", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-500 text-sm", children: "No offers found" }) })), !loading && offers.length > 0 && (_jsx(Div, { className: "space-y-3", children: offers.map((offer) => (_jsx(OfferCard, { offer: offer, onRespond: onRespond, onUpdate: handleUpdate, onNeedsLogin: () => setShowLoginModal(true) }, offer.id))) }))] }));
|
|
155
156
|
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { ListingViewShellProps } from "../../../ui";
|
|
2
2
|
export interface SellerOffersViewProps extends ListingViewShellProps {
|
|
3
|
+
onAcceptOffer?: (id: string) => Promise<void>;
|
|
4
|
+
onRejectOffer?: (id: string) => Promise<void>;
|
|
5
|
+
onCounterOffer?: (id: string) => void;
|
|
3
6
|
}
|
|
4
|
-
export declare function SellerOffersView({ children, ...props }: SellerOffersViewProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare function SellerOffersView({ children, onAcceptOffer, onRejectOffer, onCounterOffer, ...props }: SellerOffersViewProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -5,9 +5,10 @@ import { X } from "lucide-react";
|
|
|
5
5
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
6
|
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
7
7
|
import { AdminViewCards } from "../../admin/components/AdminViewCards";
|
|
8
|
-
import { FilterChipGroup, ListingToolbar, Pagination, ListingViewShell } from "../../../ui";
|
|
8
|
+
import { FilterChipGroup, ListingToolbar, Pagination, ListingViewShell, RowActionMenu } from "../../../ui";
|
|
9
9
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
10
10
|
import { SELLER_OFFER_STATUS_TABS } from "../../admin/constants/filter-tabs";
|
|
11
|
+
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
11
12
|
import { toRecordArray, toRelativeDate, toRupees, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
|
|
12
13
|
import { DataTable } from "../../admin/components/DataTable";
|
|
13
14
|
const PAGE_SIZE = 25;
|
|
@@ -18,7 +19,7 @@ const SORT_OPTIONS = [
|
|
|
18
19
|
{ value: "createdAt", label: "Oldest" },
|
|
19
20
|
];
|
|
20
21
|
const STATUS_OPTIONS = SELLER_OFFER_STATUS_TABS;
|
|
21
|
-
export function SellerOffersView({ children, ...props }) {
|
|
22
|
+
export function SellerOffersView({ children, onAcceptOffer, onRejectOffer, onCounterOffer, ...props }) {
|
|
22
23
|
const hasChildren = React.Children.count(children) > 0;
|
|
23
24
|
const [view, setView] = useState("table");
|
|
24
25
|
const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
|
|
@@ -79,5 +80,9 @@ export function SellerOffersView({ children, ...props }) {
|
|
|
79
80
|
if (hasChildren) {
|
|
80
81
|
return _jsx(ListingViewShell, { portal: "seller", ...props, children: children });
|
|
81
82
|
}
|
|
82
|
-
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search offers by product or buyer name", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), 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) }) })), _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 px-4 py-3 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-200", children: errorMessage })), view === "table" ? (_jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No offers received"
|
|
83
|
+
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search offers by product or buyer name", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), 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) }) })), _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 px-4 py-3 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-200", children: errorMessage })), view === "table" ? (_jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No offers received", renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
|
|
84
|
+
...(onAcceptOffer ? [{ label: ACTIONS.STORE["accept-offer"].label, onClick: () => void onAcceptOffer(row.id) }] : []),
|
|
85
|
+
...(onCounterOffer ? [{ label: ACTIONS.STORE["counter-offer"].label, onClick: () => onCounterOffer(row.id) }] : []),
|
|
86
|
+
...(onRejectOffer ? [{ label: ACTIONS.STORE["reject-offer"].label, destructive: true, onClick: () => void onRejectOffer(row.id) }] : []),
|
|
87
|
+
] })) })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No offers received", onRowClick: undefined, selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }))] }));
|
|
83
88
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { ListingViewShellProps } from "../../../ui";
|
|
2
2
|
export interface SellerPayoutsViewProps extends ListingViewShellProps {
|
|
3
|
+
onViewClick?: (id: string) => void;
|
|
4
|
+
onExportClick?: (id: string) => void;
|
|
3
5
|
}
|
|
4
|
-
export declare function SellerPayoutsView({ children, ...props }: SellerPayoutsViewProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export declare function SellerPayoutsView({ children, onViewClick, onExportClick, ...props }: SellerPayoutsViewProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -5,9 +5,10 @@ import { X } from "lucide-react";
|
|
|
5
5
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
6
|
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
7
7
|
import { AdminViewCards } from "../../admin/components/AdminViewCards";
|
|
8
|
-
import { FilterChipGroup, ListingToolbar, Pagination, ListingViewShell } from "../../../ui";
|
|
8
|
+
import { FilterChipGroup, ListingToolbar, Pagination, ListingViewShell, RowActionMenu } from "../../../ui";
|
|
9
9
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
10
10
|
import { ADMIN_PAYOUT_STATUS_TABS } from "../../admin/constants/filter-tabs";
|
|
11
|
+
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
11
12
|
import { toRecordArray, toRelativeDate, toRupees, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
|
|
12
13
|
import { DataTable } from "../../admin/components/DataTable";
|
|
13
14
|
const PAGE_SIZE = 25;
|
|
@@ -18,7 +19,7 @@ const SORT_OPTIONS = [
|
|
|
18
19
|
{ value: "createdAt", label: "Oldest" },
|
|
19
20
|
];
|
|
20
21
|
const STATUS_OPTIONS = ADMIN_PAYOUT_STATUS_TABS;
|
|
21
|
-
export function SellerPayoutsView({ children, ...props }) {
|
|
22
|
+
export function SellerPayoutsView({ children, onViewClick, onExportClick, ...props }) {
|
|
22
23
|
const hasChildren = React.Children.count(children) > 0;
|
|
23
24
|
const [view, setView] = useState("table");
|
|
24
25
|
const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
|
|
@@ -79,5 +80,8 @@ export function SellerPayoutsView({ children, ...props }) {
|
|
|
79
80
|
if (hasChildren) {
|
|
80
81
|
return _jsx(ListingViewShell, { portal: "seller", ...props, children: children });
|
|
81
82
|
}
|
|
82
|
-
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search payouts by payout # or amount", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), 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) }) })), _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 px-4 py-3 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-200", children: errorMessage })), view === "table" ? (_jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No payouts found"
|
|
83
|
+
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search payouts by payout # or amount", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), 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) }) })), _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 px-4 py-3 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-200", children: errorMessage })), view === "table" ? (_jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No payouts found", renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
|
|
84
|
+
...(onViewClick ? [{ label: ACTIONS.STORE["view-payout"].label, onClick: () => onViewClick(row.id) }] : []),
|
|
85
|
+
...(onExportClick ? [{ label: ACTIONS.STORE["export-payout"].label, onClick: () => onExportClick(row.id) }] : []),
|
|
86
|
+
] })) })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No payouts found", onRowClick: undefined, selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }))] }));
|
|
83
87
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ListingViewShellProps } from "../../../ui";
|
|
2
2
|
export interface SellerPreOrdersViewProps extends ListingViewShellProps {
|
|
3
|
+
onDelete?: (id: string) => Promise<void>;
|
|
3
4
|
}
|
|
4
|
-
export declare function SellerPreOrdersView({ children, ...props }: SellerPreOrdersViewProps): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export declare function SellerPreOrdersView({ children, onDelete, ...props }: SellerPreOrdersViewProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,10 +1,10 @@
|
|
|
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 {
|
|
4
|
+
import { X } from "lucide-react";
|
|
5
5
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
6
|
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
7
|
-
import { Alert, Badge, Button, Div, FilterChipGroup, ListingToolbar, ListingViewShell, Pagination, Row, Text } from "../../../ui";
|
|
7
|
+
import { Alert, Badge, Button, ConfirmDeleteModal, Div, FilterChipGroup, ListingToolbar, ListingViewShell, Pagination, Row, RowActionMenu, Text } from "../../../ui";
|
|
8
8
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
9
9
|
import { SELLER_PRE_ORDER_STATUS_TABS } from "../../admin/constants/filter-tabs";
|
|
10
10
|
import { ROUTES } from "../../../constants";
|
|
@@ -70,10 +70,12 @@ const PRE_ORDER_COLUMNS = [
|
|
|
70
70
|
render: (row) => (_jsx("span", { className: "text-xs text-[var(--appkit-color-text-muted)]", children: row.updatedAt })),
|
|
71
71
|
},
|
|
72
72
|
];
|
|
73
|
-
export function SellerPreOrdersView({ children, ...props }) {
|
|
73
|
+
export function SellerPreOrdersView({ children, onDelete, ...props }) {
|
|
74
74
|
const hasChildren = React.Children.count(children) > 0;
|
|
75
75
|
const [view, setView] = useState("table");
|
|
76
76
|
const dispatch = useActionDispatch();
|
|
77
|
+
const [deleteTargetId, setDeleteTargetId] = useState(null);
|
|
78
|
+
const [deletingId, setDeletingId] = useState(null);
|
|
77
79
|
const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
|
|
78
80
|
const [searchInput, setSearchInput] = useState(table.get("q") || "");
|
|
79
81
|
const [filterOpen, setFilterOpen] = useState(false);
|
|
@@ -135,11 +137,32 @@ export function SellerPreOrdersView({ children, ...props }) {
|
|
|
135
137
|
const currentPage = table.getNumber("page", 1);
|
|
136
138
|
const totalPages = Math.ceil(total / PAGE_SIZE);
|
|
137
139
|
const selection = useBulkSelection({ items: rows, keyExtractor: (r) => r.id });
|
|
140
|
+
const handleDelete = useCallback(async (id) => {
|
|
141
|
+
setDeletingId(id);
|
|
142
|
+
try {
|
|
143
|
+
if (onDelete)
|
|
144
|
+
await onDelete(id);
|
|
145
|
+
else
|
|
146
|
+
await fetch(`/api/store/products/${id}`, { method: "DELETE", credentials: "include" });
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
setDeletingId(null);
|
|
150
|
+
setDeleteTargetId(null);
|
|
151
|
+
}
|
|
152
|
+
}, [onDelete]);
|
|
138
153
|
if (hasChildren) {
|
|
139
154
|
return (_jsx(ListingViewShell, { portal: "seller", ...props, children: children }));
|
|
140
155
|
}
|
|
141
|
-
return (_jsxs(Div, { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search pre-orders by name\u2026", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("div", { className: "sticky z-10 flex justify-center bg-[var(--appkit-color-surface)]/95 backdrop-blur-sm border-b border-[var(--appkit-color-border)] px-3 py-1.5", style: { top: "calc(var(--header-height, 0px) + 44px)" }, children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx(Alert, { variant: "error", className: "mb-4", children: errorMessage })), _jsx(DataTable, { columns: PRE_ORDER_COLUMNS, rows: rows, isLoading: isLoading, emptyLabel: "No pre-orders listed yet", getRowHref: (row) => String(ROUTES.STORE.PRE_ORDERS_EDIT(row.id)), renderRowActions: (row) => (_jsx(
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
156
|
+
return (_jsxs(Div, { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search pre-orders by name\u2026", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("div", { className: "sticky z-10 flex justify-center bg-[var(--appkit-color-surface)]/95 backdrop-blur-sm border-b border-[var(--appkit-color-border)] px-3 py-1.5", style: { top: "calc(var(--header-height, 0px) + 44px)" }, children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx(Alert, { variant: "error", className: "mb-4", children: errorMessage })), _jsx(DataTable, { columns: PRE_ORDER_COLUMNS, rows: rows, isLoading: isLoading, emptyLabel: "No pre-orders listed yet", getRowHref: (row) => String(ROUTES.STORE.PRE_ORDERS_EDIT(row.id)), renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
|
|
157
|
+
{
|
|
158
|
+
label: ACTIONS.STORE["edit-listing"].label,
|
|
159
|
+
onClick: () => void dispatch({ type: "NAVIGATE", href: String(ROUTES.STORE.PRE_ORDERS_EDIT(row.id)) }),
|
|
160
|
+
},
|
|
161
|
+
...(onDelete ? [{
|
|
162
|
+
label: ACTIONS.STORE["delete-listing"].label,
|
|
163
|
+
destructive: true,
|
|
164
|
+
onClick: () => setDeleteTargetId(row.id),
|
|
165
|
+
disabled: deletingId === row.id,
|
|
166
|
+
}] : []),
|
|
167
|
+
] })) })] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx(Div, { role: "presentation", className: "fixed inset-0 z-40 bg-black/40", onClick: () => setFilterOpen(false) }), _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: clearFilters, 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: () => setFilterOpen(false), "aria-label": "Close filters", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx(Div, { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }) }), _jsx(Div, { className: "border-t border-[var(--appkit-color-border)] px-4 py-3.5", children: _jsxs(Button, { variant: "primary", onClick: applyFilters, className: "w-full rounded-lg py-2.5 active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] })), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Pre-Order", message: "Are you sure you want to delete this pre-order listing? This cannot be undone.", onConfirm: () => handleDelete(deleteTargetId), onClose: () => setDeleteTargetId(null), isDeleting: deletingId === deleteTargetId }))] }));
|
|
145
168
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ListingViewShellProps } from "../../../ui";
|
|
2
2
|
export interface SellerPrizeDrawsViewProps extends ListingViewShellProps {
|
|
3
|
+
onDelete?: (id: string) => Promise<void>;
|
|
3
4
|
}
|
|
4
|
-
export declare function SellerPrizeDrawsView({ children, ...props }: SellerPrizeDrawsViewProps): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export declare function SellerPrizeDrawsView({ children, onDelete, ...props }: SellerPrizeDrawsViewProps): import("react/jsx-runtime").JSX.Element;
|