@mohasinac/appkit 4.4.5 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_internal/server/features/checkout/actions.js +2 -0
- package/dist/_internal/server/features/orders/adapters.js +1 -0
- package/dist/features/account/hooks/useDataViewMode.js +1 -1
- package/dist/features/admin/components/AdminAddressesView.js +5 -0
- package/dist/features/admin/components/AdminArtView.js +4 -0
- package/dist/features/admin/components/AdminClassifiedView.js +4 -0
- package/dist/features/admin/components/AdminContactView.js +6 -0
- package/dist/features/admin/components/AdminDigitalCodesView.js +4 -0
- package/dist/features/admin/components/AdminGroupedListingsView.js +14 -8
- package/dist/features/admin/components/AdminLiveView.js +4 -0
- package/dist/features/admin/components/AdminOrdersView.js +6 -0
- package/dist/features/admin/components/AdminProductsView.js +22 -4
- package/dist/features/admin/components/AdminReturnRequestsView.js +5 -0
- package/dist/features/admin/components/AdminReviewsView.js +4 -3
- package/dist/features/admin/components/AdminScammersView.js +6 -0
- package/dist/features/admin/components/AdminStickersView.js +4 -0
- package/dist/features/admin/components/AdminSublistingCategoriesView.js +2 -0
- package/dist/features/admin/components/AdminSupportTicketsView.js +6 -0
- package/dist/features/admin/components/AdminTeamView.js +3 -0
- package/dist/features/admin/components/AdminViewCards.d.ts +3 -1
- package/dist/features/admin/components/AdminViewCards.js +7 -7
- package/dist/features/admin/components/DataListingView.d.ts +1 -1
- package/dist/features/admin/components/DataListingView.js +26 -2
- package/dist/features/admin/hooks/useAdminListing.js +1 -1
- package/dist/features/auth/actions/profile-actions.js +3 -3
- package/dist/features/orders/schemas/firestore.d.ts +2 -0
- package/dist/features/products/components/ProductDetailPageView.js +1 -3
- package/dist/features/products/constants/action-defs.d.ts +13 -2
- package/dist/features/products/constants/action-defs.js +33 -0
- package/dist/features/reviews/components/ReviewDetailShell.js +3 -3
- package/dist/features/reviews/components/ReviewModal.js +1 -1
- package/dist/features/reviews/components/ReviewsList.js +1 -1
- package/dist/features/reviews/types/index.d.ts +2 -6
- package/dist/features/seller/components/SellerArtView.js +2 -0
- package/dist/features/seller/components/SellerClassifiedView.js +2 -0
- package/dist/features/seller/components/SellerDigitalCodesView.js +2 -0
- package/dist/features/seller/components/SellerGroupedListingsView.js +2 -0
- package/dist/features/seller/components/SellerLiveView.js +2 -0
- package/dist/features/seller/components/SellerPayoutsView.js +3 -0
- package/dist/features/seller/components/SellerProductsView.js +20 -2
- package/dist/features/seller/components/SellerStickersView.js +2 -0
- package/dist/features/tester/seed-data/orders-tester-seed-data.js +19 -1
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +39 -0
- package/dist/index.d.ts +0 -1
- package/dist/seed/orders-seed-data.js +25 -1
- package/dist/styles.css +1 -1
- package/dist/tailwind-utilities.css +1 -1
- package/package.json +1 -1
|
@@ -256,6 +256,7 @@ async function createOrderForGroup(group, orderType, ctx) {
|
|
|
256
256
|
const baseLine = {
|
|
257
257
|
productId: item.productId,
|
|
258
258
|
productTitle: item.productTitle,
|
|
259
|
+
image: item.productImage,
|
|
259
260
|
quantity: item.quantity,
|
|
260
261
|
unitPrice,
|
|
261
262
|
totalPrice: unitPrice * item.quantity,
|
|
@@ -932,6 +933,7 @@ async function createRazorpayGroupOrder(group, orderType, ctx) {
|
|
|
932
933
|
const baseLine = {
|
|
933
934
|
productId: item.productId,
|
|
934
935
|
productTitle: item.productTitle,
|
|
936
|
+
image: item.productImage,
|
|
935
937
|
quantity: item.quantity,
|
|
936
938
|
unitPrice,
|
|
937
939
|
totalPrice: unitPrice * item.quantity,
|
|
@@ -15,7 +15,7 @@ const MOBILE_BREAKPOINT_PX = 768;
|
|
|
15
15
|
* pagination already live in the URL via useUrlTable() and must never be
|
|
16
16
|
* added to this hook — see CLAUDE.md Phase 3 / user directive 2026-08-18.
|
|
17
17
|
*/
|
|
18
|
-
export function useDataViewMode(fallback = "
|
|
18
|
+
export function useDataViewMode(fallback = "list") {
|
|
19
19
|
const { data: profile } = useCurrentProfile();
|
|
20
20
|
const updateProfile = useUpdateCurrentProfile();
|
|
21
21
|
const debounceRef = useRef(null);
|
|
@@ -11,6 +11,7 @@ import { DataListingView } from "./DataListingView";
|
|
|
11
11
|
import { apiClient } from "../../../http";
|
|
12
12
|
import { useApiMutation } from "@mohasinac/appkit/client";
|
|
13
13
|
import { QuickEditMenu } from "./QuickEditMenu";
|
|
14
|
+
import { ROUTES } from "../../../next/routing/route-map";
|
|
14
15
|
const BAN_STATUS_TABS = [
|
|
15
16
|
{ id: "", label: "All" },
|
|
16
17
|
{ id: "banned", label: "Banned" },
|
|
@@ -78,6 +79,10 @@ function buildAddressConfig(banStatus, onAction) {
|
|
|
78
79
|
})),
|
|
79
80
|
getTotal: (response, rows) => typeof response.total === "number" ? response.total : rows.length,
|
|
80
81
|
buildFilters: () => undefined,
|
|
82
|
+
// The full address record (owner, ban reason/history) lives on the
|
|
83
|
+
// existing admin address edit page — reuse it instead of leaving a
|
|
84
|
+
// banned-address row with no detail destination.
|
|
85
|
+
rowHrefTemplate: String(ROUTES.ADMIN.ADDRESSES_EDIT("{id}")),
|
|
81
86
|
renderRowActions: (row) => {
|
|
82
87
|
const actions = [];
|
|
83
88
|
if (row.status !== "banned") {
|
|
@@ -10,6 +10,7 @@ import { ListingLayout } from "../../../ui";
|
|
|
10
10
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
11
11
|
import { toRecordArray, toRelativeDate, toCurrency, toStringValue, } from "../hooks/useAdminListingData";
|
|
12
12
|
import { DataListingView } from "./DataListingView";
|
|
13
|
+
import { ROUTES } from "../../../next/routing/route-map";
|
|
13
14
|
const ADMIN_ART_CONFIG = {
|
|
14
15
|
portal: "admin",
|
|
15
16
|
title: "Art",
|
|
@@ -36,6 +37,9 @@ const ADMIN_ART_CONFIG = {
|
|
|
36
37
|
})),
|
|
37
38
|
getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
|
|
38
39
|
buildFilters: () => "listingType==art",
|
|
40
|
+
// Art listings are products (filtered by listingType) — reuse the real
|
|
41
|
+
// admin product edit page rather than leaving rows non-navigable.
|
|
42
|
+
rowHrefTemplate: String(ROUTES.ADMIN.PRODUCTS_EDIT("{id}")),
|
|
39
43
|
};
|
|
40
44
|
export function AdminArtView({ children, ...props }) {
|
|
41
45
|
if (React.Children.count(children) > 0) {
|
|
@@ -10,6 +10,7 @@ import { ListingLayout } from "../../../ui";
|
|
|
10
10
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
11
11
|
import { toRecordArray, toRelativeDate, toCurrency, toStringValue, } from "../hooks/useAdminListingData";
|
|
12
12
|
import { DataListingView } from "./DataListingView";
|
|
13
|
+
import { ROUTES } from "../../../next/routing/route-map";
|
|
13
14
|
const ADMIN_CLASSIFIED_CONFIG = {
|
|
14
15
|
portal: "admin",
|
|
15
16
|
title: "Classified",
|
|
@@ -36,6 +37,9 @@ const ADMIN_CLASSIFIED_CONFIG = {
|
|
|
36
37
|
})),
|
|
37
38
|
getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
|
|
38
39
|
buildFilters: () => "listingType==classified",
|
|
40
|
+
// Classified listings are products (filtered by listingType) — reuse the
|
|
41
|
+
// real admin product edit page rather than leaving rows non-navigable.
|
|
42
|
+
rowHrefTemplate: String(ROUTES.ADMIN.PRODUCTS_EDIT("{id}")),
|
|
39
43
|
};
|
|
40
44
|
export function AdminClassifiedView({ children, ...props }) {
|
|
41
45
|
if (React.Children.count(children) > 0) {
|
|
@@ -81,6 +81,12 @@ export function AdminContactView({ children, onBulkMarkRead, onBulkArchive, onBu
|
|
|
81
81
|
return mappedRows.length;
|
|
82
82
|
},
|
|
83
83
|
buildFilters: (f) => (f.status && f.status !== "All" ? sieveFilter("status", SIEVE_OP.EQ, f.status) : undefined),
|
|
84
|
+
// Mirrors the row action's "View" entry so the row itself is clickable,
|
|
85
|
+
// not just the overflow menu.
|
|
86
|
+
onRowClick: (row) => {
|
|
87
|
+
setSelectedRow(row);
|
|
88
|
+
setDrawerOpen(true);
|
|
89
|
+
},
|
|
84
90
|
buildBulkActions: (selection) => [
|
|
85
91
|
...(onBulkMarkRead
|
|
86
92
|
? [
|
|
@@ -9,6 +9,7 @@ import { ListingLayout } from "../../../ui";
|
|
|
9
9
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
10
10
|
import { toRecordArray, toRelativeDate, toCurrency, toStringValue, } from "../hooks/useAdminListingData";
|
|
11
11
|
import { DataListingView } from "./DataListingView";
|
|
12
|
+
import { ROUTES } from "../../../next/routing/route-map";
|
|
12
13
|
const ADMIN_DIGITAL_CODES_CONFIG = {
|
|
13
14
|
portal: "admin",
|
|
14
15
|
title: "Digital Codes",
|
|
@@ -43,6 +44,9 @@ const ADMIN_DIGITAL_CODES_CONFIG = {
|
|
|
43
44
|
}),
|
|
44
45
|
getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
|
|
45
46
|
buildFilters: () => "listingType==digital-code",
|
|
47
|
+
// Digital-code listings are products (filtered by listingType) — reuse
|
|
48
|
+
// the real admin product edit page rather than leaving rows non-navigable.
|
|
49
|
+
rowHrefTemplate: String(ROUTES.ADMIN.PRODUCTS_EDIT("{id}")),
|
|
46
50
|
};
|
|
47
51
|
export function AdminDigitalCodesView({ children, ...props }) {
|
|
48
52
|
if (React.Children.count(children) > 0) {
|
|
@@ -39,6 +39,15 @@ function ReassignProductsDrawer({ state, onClose, onSaved, }) {
|
|
|
39
39
|
export function AdminGroupedListingsView({ children, ...props }) {
|
|
40
40
|
const [reassign, setReassign] = useState(null);
|
|
41
41
|
const [refreshKey, setRefreshKey] = useState(0);
|
|
42
|
+
const openReassign = React.useCallback((row) => {
|
|
43
|
+
setReassign({
|
|
44
|
+
groupId: row.id,
|
|
45
|
+
groupTitle: row.primary,
|
|
46
|
+
currentProductIds: Array.isArray(row._raw?.productIds)
|
|
47
|
+
? (row._raw?.productIds ?? []).map(String)
|
|
48
|
+
: [],
|
|
49
|
+
});
|
|
50
|
+
}, []);
|
|
42
51
|
const config = React.useMemo(() => ({
|
|
43
52
|
portal: "admin",
|
|
44
53
|
title: "Grouped Listings",
|
|
@@ -66,14 +75,11 @@ export function AdminGroupedListingsView({ children, ...props }) {
|
|
|
66
75
|
})),
|
|
67
76
|
getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
|
|
68
77
|
buildFilters: () => "",
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
: [],
|
|
75
|
-
}), children: "Reassign products" })),
|
|
76
|
-
}), [refreshKey]);
|
|
78
|
+
// Mirrors the row action button's "Reassign products" drawer so the
|
|
79
|
+
// row itself is clickable, not just the button.
|
|
80
|
+
onRowClick: (row) => openReassign(row),
|
|
81
|
+
renderRowActions: (row) => (_jsx(Button, { size: "sm", variant: "outline", onClick: () => openReassign(row), children: "Reassign products" })),
|
|
82
|
+
}), [refreshKey, openReassign]);
|
|
77
83
|
if (React.Children.count(children) > 0) {
|
|
78
84
|
return (_jsx(ListingLayout, { portal: "admin", ...props, children: children }));
|
|
79
85
|
}
|
|
@@ -9,6 +9,7 @@ import { ListingLayout } from "../../../ui";
|
|
|
9
9
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
10
10
|
import { toRecordArray, toRelativeDate, toCurrency, toStringValue, } from "../hooks/useAdminListingData";
|
|
11
11
|
import { DataListingView } from "./DataListingView";
|
|
12
|
+
import { ROUTES } from "../../../next/routing/route-map";
|
|
12
13
|
const ADMIN_LIVE_CONFIG = {
|
|
13
14
|
portal: "admin",
|
|
14
15
|
title: "Live Items",
|
|
@@ -42,6 +43,9 @@ const ADMIN_LIVE_CONFIG = {
|
|
|
42
43
|
}),
|
|
43
44
|
getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
|
|
44
45
|
buildFilters: () => "listingType==live",
|
|
46
|
+
// Live-item listings are products (filtered by listingType) — reuse the
|
|
47
|
+
// real admin product edit page rather than leaving rows non-navigable.
|
|
48
|
+
rowHrefTemplate: String(ROUTES.ADMIN.PRODUCTS_EDIT("{id}")),
|
|
45
49
|
};
|
|
46
50
|
export function AdminLiveView({ children, ...props }) {
|
|
47
51
|
if (React.Children.count(children) > 0) {
|
|
@@ -66,6 +66,12 @@ export function AdminOrdersView({ children, ...props }) {
|
|
|
66
66
|
})),
|
|
67
67
|
getTotal: (response, mappedRows) => typeof response.meta?.total === "number" ? response.meta.total : mappedRows.length,
|
|
68
68
|
buildFilters: (f) => (f.status && f.status !== "All" ? sieveFilter("status", SIEVE_OP.EQ, f.status) : undefined),
|
|
69
|
+
// Mirrors the row action's "View full details" entry so the row itself
|
|
70
|
+
// is clickable, not just the overflow menu.
|
|
71
|
+
onRowClick: (row) => {
|
|
72
|
+
setSelectedRow(row);
|
|
73
|
+
setDrawerOpen(true);
|
|
74
|
+
},
|
|
69
75
|
// Rule #7: bulk-action array sourced from the ADMIN_BULK_ACTIONS preset.
|
|
70
76
|
buildBulkActions: (selection) => {
|
|
71
77
|
const statusByAction = {
|
|
@@ -122,13 +122,31 @@ export function AdminProductsView({ children, ...props }) {
|
|
|
122
122
|
mapRows: (response) => toRecordArray(response.items).map((item, index) => {
|
|
123
123
|
const id = toStringValue(item.id, `product-${index}`);
|
|
124
124
|
rawByIdRef.current[id] = item;
|
|
125
|
+
// Auction listings lost their reserve/bid/end-date summary when this
|
|
126
|
+
// view was consolidated onto the shared Products listing — restore
|
|
127
|
+
// it into `secondary` instead of seller/SKU, which admins reviewing
|
|
128
|
+
// an auction care about far less than bid activity.
|
|
129
|
+
const auctionSecondary = item.listingType === "auction"
|
|
130
|
+
? [
|
|
131
|
+
typeof item.reservePrice === "number"
|
|
132
|
+
? `Reserve ₹${item.reservePrice.toLocaleString("en-IN")}`
|
|
133
|
+
: null,
|
|
134
|
+
`${typeof item.bidCount === "number" ? item.bidCount : 0} bids`,
|
|
135
|
+
item.auctionEndDate
|
|
136
|
+
? `Ends ${new Date(item.auctionEndDate).toLocaleDateString("en-IN", { month: "short", day: "numeric" })}`
|
|
137
|
+
: null,
|
|
138
|
+
]
|
|
139
|
+
.filter(Boolean)
|
|
140
|
+
.join(" · ")
|
|
141
|
+
: "";
|
|
125
142
|
const base = {
|
|
126
143
|
id,
|
|
127
144
|
primary: toStringValue(item.title ?? item.name, "Untitled product"),
|
|
128
|
-
secondary:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
145
|
+
secondary: auctionSecondary ||
|
|
146
|
+
[
|
|
147
|
+
toStringValue(item.sellerName, "Unknown seller"),
|
|
148
|
+
toStringValue(item.sku, "No SKU"),
|
|
149
|
+
].join(" · "),
|
|
132
150
|
status: toStringValue(item.status, "Unknown"),
|
|
133
151
|
updatedAt: toRelativeDate(item.updatedAt ?? item.createdAt),
|
|
134
152
|
featured: Boolean(item.featured),
|
|
@@ -7,6 +7,7 @@ import { useQueryClient } from "@tanstack/react-query";
|
|
|
7
7
|
import { ConfirmDeleteModal, RowActionMenu, useToast } from "../../../ui";
|
|
8
8
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
9
9
|
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
10
|
+
import { ROUTES } from "../../../next/routing/route-map";
|
|
10
11
|
import { toRecordArray, toRelativeDate, toCurrency, toStringValue, } from "../hooks/useAdminListingData";
|
|
11
12
|
import { DataListingView } from "./DataListingView";
|
|
12
13
|
import { apiClient } from "../../../http";
|
|
@@ -71,6 +72,10 @@ export function AdminReturnRequestsView(_props) {
|
|
|
71
72
|
})),
|
|
72
73
|
getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
|
|
73
74
|
buildFilters: () => undefined,
|
|
75
|
+
// Return requests are orders (endpoint filters status==return_requested)
|
|
76
|
+
// — reuse the real admin order detail page rather than leaving rows
|
|
77
|
+
// non-navigable.
|
|
78
|
+
rowHrefTemplate: String(ROUTES.ADMIN.ORDER_DETAIL("{id}")),
|
|
74
79
|
renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
|
|
75
80
|
{
|
|
76
81
|
label: ACTIONS.ADMIN["approve-return"].label,
|
|
@@ -62,9 +62,7 @@ export function AdminReviewsView({ children, ...props }) {
|
|
|
62
62
|
userName: toStringValue(raw.userName ?? raw.sellerName, "Unknown"),
|
|
63
63
|
userAvatar: toStringValue(raw.userAvatar, "") || undefined,
|
|
64
64
|
verified: Boolean(raw.verified),
|
|
65
|
-
images: Array.isArray(raw.images)
|
|
66
|
-
? raw.images
|
|
67
|
-
: [],
|
|
65
|
+
images: Array.isArray(raw.images) ? raw.images : [],
|
|
68
66
|
helpfulCount: Number(raw.helpfulCount ?? 0),
|
|
69
67
|
createdAt: toStringValue(raw.createdAt, "") || undefined,
|
|
70
68
|
});
|
|
@@ -119,6 +117,9 @@ export function AdminReviewsView({ children, ...props }) {
|
|
|
119
117
|
parts.push(sieveFilter("rating", SIEVE_OP.EQ, f.rating));
|
|
120
118
|
return parts.join(",") || undefined;
|
|
121
119
|
},
|
|
120
|
+
// Mirrors the row action's "View" entry so the row itself is clickable,
|
|
121
|
+
// not just the overflow menu.
|
|
122
|
+
onRowClick: (row) => handleViewReview(row),
|
|
122
123
|
// Rule #7: bulk-action array sourced from the ADMIN_BULK_ACTIONS preset.
|
|
123
124
|
// DELETE has no wired handler yet (pre-existing — approve/reject were
|
|
124
125
|
// already no-op placeholders too), so it's left out until one exists.
|
|
@@ -86,6 +86,12 @@ export function AdminScammersView({ children, ...props }) {
|
|
|
86
86
|
return mappedRows.length;
|
|
87
87
|
},
|
|
88
88
|
buildFilters: (f) => (f.status && f.status !== "All" ? sieveFilter("status", SIEVE_OP.EQ, f.status) : undefined),
|
|
89
|
+
// Mirrors the row action's "review-scammer" entry so the row itself is
|
|
90
|
+
// clickable, not just the overflow menu.
|
|
91
|
+
onRowClick: (row) => {
|
|
92
|
+
setSelectedRow(row);
|
|
93
|
+
setDrawerOpen(true);
|
|
94
|
+
},
|
|
89
95
|
renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
|
|
90
96
|
{
|
|
91
97
|
label: ACTIONS.ADMIN["review-scammer"].label,
|
|
@@ -10,6 +10,7 @@ import { ListingLayout } from "../../../ui";
|
|
|
10
10
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
11
11
|
import { toRecordArray, toRelativeDate, toCurrency, toStringValue, } from "../hooks/useAdminListingData";
|
|
12
12
|
import { DataListingView } from "./DataListingView";
|
|
13
|
+
import { ROUTES } from "../../../next/routing/route-map";
|
|
13
14
|
const ADMIN_STICKERS_CONFIG = {
|
|
14
15
|
portal: "admin",
|
|
15
16
|
title: "Stickers",
|
|
@@ -36,6 +37,9 @@ const ADMIN_STICKERS_CONFIG = {
|
|
|
36
37
|
})),
|
|
37
38
|
getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
|
|
38
39
|
buildFilters: () => "listingType==stickers",
|
|
40
|
+
// Sticker listings are products (filtered by listingType) — reuse the
|
|
41
|
+
// real admin product edit page rather than leaving rows non-navigable.
|
|
42
|
+
rowHrefTemplate: String(ROUTES.ADMIN.PRODUCTS_EDIT("{id}")),
|
|
39
43
|
};
|
|
40
44
|
export function AdminStickersView({ children, ...props }) {
|
|
41
45
|
if (React.Children.count(children) > 0) {
|
|
@@ -4,6 +4,7 @@ import { sortBy } from "@mohasinac/appkit/client";
|
|
|
4
4
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
5
5
|
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
6
6
|
import { buildBulkAction } from "../../../_internal/shared/actions/bulk-helpers";
|
|
7
|
+
import { ROUTES } from "../../../next/routing/route-map";
|
|
7
8
|
import { toRecordArray, toRelativeDate, toStringValue, } from "../hooks/useAdminListingData";
|
|
8
9
|
import { DataListingView } from "./DataListingView";
|
|
9
10
|
export function AdminSublistingCategoriesView({ onBulkDelete, }) {
|
|
@@ -36,6 +37,7 @@ export function AdminSublistingCategoriesView({ onBulkDelete, }) {
|
|
|
36
37
|
})),
|
|
37
38
|
getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
|
|
38
39
|
buildFilters: () => undefined,
|
|
40
|
+
rowHrefTemplate: String(ROUTES.ADMIN.SUBLISTING_CATEGORIES_EDIT("{id}")),
|
|
39
41
|
buildBulkActions: onBulkDelete
|
|
40
42
|
? (selection) => [
|
|
41
43
|
buildBulkAction(ACTIONS.ADMIN["delete-sublisting-category"], async () => {
|
|
@@ -111,6 +111,12 @@ export function AdminSupportTicketsView({ children, ...props }) {
|
|
|
111
111
|
parts.push(sieveFilter("priority", SIEVE_OP.EQ, f.priority));
|
|
112
112
|
return parts.join(",") || undefined;
|
|
113
113
|
},
|
|
114
|
+
// Mirrors the row action's "View" entry so the row itself is clickable,
|
|
115
|
+
// not just the overflow menu.
|
|
116
|
+
onRowClick: (row) => {
|
|
117
|
+
setSelectedRow(row);
|
|
118
|
+
setDrawerOpen(true);
|
|
119
|
+
},
|
|
114
120
|
renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
|
|
115
121
|
{
|
|
116
122
|
label: ROW_ACTION_META[ROW_ACTION_ID.VIEW].label,
|
|
@@ -93,6 +93,9 @@ export function AdminTeamView({ children, onBulkRemove, ...props }) {
|
|
|
93
93
|
return mappedRows.length;
|
|
94
94
|
},
|
|
95
95
|
buildFilters: (state) => state.group && state.group !== "All" ? sieveFilter("permissionGroup", SIEVE_OP.EQ, state.group) : undefined,
|
|
96
|
+
// Mirrors the row action's "edit-team-member" entry so the row itself
|
|
97
|
+
// is clickable, not just the overflow menu.
|
|
98
|
+
onRowClick: (row) => openEdit(row),
|
|
96
99
|
toolbarExtra: (_jsxs(Button, { gap: "sm", type: "button", variant: "primary", onClick: openInvite, className: "whitespace-nowrap", children: [_jsx(UserPlus, { className: "h-4 w-4" }), "Invite Employee"] })),
|
|
97
100
|
// Rule #7: bulk-action array sourced from the ADMIN_BULK_ACTIONS preset.
|
|
98
101
|
buildBulkActions: onBulkRemove
|
|
@@ -8,6 +8,8 @@ interface AdminViewCardsProps {
|
|
|
8
8
|
onRowClick?: (row: AdminListingScaffoldRow) => void;
|
|
9
9
|
selectedIdSet?: Set<string>;
|
|
10
10
|
onToggleSelect?: (id: string) => void;
|
|
11
|
+
/** Same row-actions menu DataTable renders in its table view — mirrored here so cards carry the same quick actions, not just navigation. */
|
|
12
|
+
renderRowActions?: (row: AdminListingScaffoldRow) => React.ReactNode;
|
|
11
13
|
}
|
|
12
|
-
export declare function AdminViewCards({ rows, view, isLoading, emptyLabel, onRowClick, selectedIdSet, onToggleSelect, }: AdminViewCardsProps): React.JSX.Element;
|
|
14
|
+
export declare function AdminViewCards({ rows, view, isLoading, emptyLabel, onRowClick, selectedIdSet, onToggleSelect, renderRowActions, }: AdminViewCardsProps): React.JSX.Element;
|
|
13
15
|
export {};
|
|
@@ -22,10 +22,10 @@ function SkeletonCard({ view }) {
|
|
|
22
22
|
}
|
|
23
23
|
return (_jsx(Div, { rounded: "xl", border: "subtle", className: `${__O.hidden} animate-pulse`, children: _jsxs(Stack, { gap: "xs", padding: "md", children: [_jsx(Div, { className: "h-4 w-3/4", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-3 w-1/2", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-5 w-20 mt-1", surface: "subtle", rounded: "full" }), _jsx(Div, { className: "h-3 w-1/3", surface: "subtle", rounded: "default" })] }) }));
|
|
24
24
|
}
|
|
25
|
-
function AdminCardItem({ row, view, selected, onToggleSelect, onRowClick, }) {
|
|
25
|
+
function AdminCardItem({ row, view, selected, onToggleSelect, onRowClick, renderRowActions, }) {
|
|
26
26
|
const flags = FLAG_BADGES.filter(({ key }) => Boolean(row[key]));
|
|
27
27
|
const handleClick = (e) => {
|
|
28
|
-
if (e.target.closest('[data-
|
|
28
|
+
if (e.target.closest('[data-no-row-click]'))
|
|
29
29
|
return;
|
|
30
30
|
onRowClick?.(row);
|
|
31
31
|
};
|
|
@@ -33,16 +33,16 @@ function AdminCardItem({ row, view, selected, onToggleSelect, onRowClick, }) {
|
|
|
33
33
|
return (_jsxs(Row, { gap: "sm", className: [
|
|
34
34
|
"px-[var(--appkit-space-4)] py-[var(--appkit-space-3)] cursor-pointer transition-colors hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)]/50",
|
|
35
35
|
selected ? "bg-primary-50/40 dark:bg-primary-900/10" : "",
|
|
36
|
-
].filter(Boolean).join(" "), onClick: handleClick, role: onRowClick ? "button" : undefined, children: [onToggleSelect && (_jsx(Div, { "data-
|
|
36
|
+
].filter(Boolean).join(" "), onClick: handleClick, role: onRowClick ? "button" : undefined, children: [onToggleSelect && (_jsx(Div, { "data-no-row-click": true, className: "shrink-0", onClick: (e) => { e.stopPropagation(); onToggleSelect(row.id); }, children: _jsx(Checkbox, { bare: true, checked: selected, onChange: () => onToggleSelect(row.id), className: "h-4 w-4 rounded border-zinc-300 text-primary accent-primary cursor-pointer", "aria-label": `Select ${row.primary}` }) })), _jsxs(Stack, { gap: "none", className: "flex-1 min-w-0", children: [_jsx(Text, { size: "sm", weight: "semibold", className: "truncate", color: "primary", children: row.primary }), _jsx(Text, { size: "xs", color: "muted", className: "truncate", children: row.secondary }), row.barcodeId && (_jsx(Text, { size: "xs", color: "faint", className: "truncate font-mono", children: row.barcodeId }))] }), flags.length > 0 && (_jsx(Row, { gap: "xs", className: "hidden sm:flex shrink-0", children: flags.map(({ key, label, color }) => (_jsx(Span, { padding: "pill-2xs", weight: "medium", className: `inline-flex text-[10px] ${color}`, rounded: "full", children: label }, key))) })), _jsx(StatusBadge, { status: row.status }), _jsx(Span, { size: "xs", color: "muted", className: "hidden sm:block shrink-0 w-24", align: "end", children: row.updatedAt }), renderRowActions && (_jsx(Div, { "data-no-row-click": true, className: "shrink-0", onClick: (e) => e.stopPropagation(), children: renderRowActions(row) }))] }));
|
|
37
37
|
}
|
|
38
38
|
return (_jsxs(Div, { rounded: "xl", className: [
|
|
39
39
|
"border overflow-hidden cursor-pointer transition-all hover:shadow-md hover:-translate-y-0.5",
|
|
40
40
|
selected
|
|
41
41
|
? "border-primary ring-1 ring-primary/20 bg-primary-50/30 dark:bg-primary-900/10"
|
|
42
42
|
: "border-zinc-100 border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]",
|
|
43
|
-
].filter(Boolean).join(" "), onClick: handleClick, role: onRowClick ? "button" : undefined, children: [onToggleSelect && (_jsxs(Row, { gap: "xs", "data-
|
|
43
|
+
].filter(Boolean).join(" "), onClick: handleClick, role: onRowClick ? "button" : undefined, children: [onToggleSelect && (_jsxs(Row, { gap: "xs", "data-no-row-click": true, paddingY: "t-sm", padding: "x-sm", onClick: (e) => { e.stopPropagation(); onToggleSelect(row.id); }, children: [_jsx(Checkbox, { bare: true, checked: selected, onChange: () => onToggleSelect(row.id), className: "h-4 w-4 rounded border-zinc-300 text-primary accent-primary cursor-pointer", "aria-label": `Select ${row.primary}` }), flags.length > 0 && (_jsx(Row, { gap: "xs", wrap: true, children: flags.map(({ key, label, color }) => (_jsx(Span, { padding: "pill-2xs", weight: "medium", className: `inline-flex text-[10px] ${color}`, rounded: "full", children: label }, key))) }))] })), _jsxs(Stack, { gap: "xs", className: `${__P.p3}.5`, children: [_jsxs(Stack, { gap: "none", children: [_jsx(Text, { size: "sm", weight: "semibold", className: "line-clamp-2 leading-snug", color: "primary", children: row.primary }), _jsx(Text, { size: "xs", color: "muted", className: "truncate", children: row.secondary }), row.barcodeId && (_jsx(Text, { size: "xs", color: "faint", className: "truncate font-mono", children: row.barcodeId }))] }), _jsxs(Row, { justify: "between", gap: "xs", children: [_jsx(StatusBadge, { status: row.status }), _jsx(Span, { color: "muted", className: "text-[11px] shrink-0", children: row.updatedAt })] }), renderRowActions && (_jsx(Row, { "data-no-row-click": true, justify: "end", gap: "xs", className: "border-t border-[var(--appkit-color-border)] -mx-[var(--appkit-space-3)] -mb-[var(--appkit-space-3)] mt-[var(--appkit-space-1)] px-[var(--appkit-space-3)] py-[var(--appkit-space-2)]", onClick: (e) => e.stopPropagation(), children: renderRowActions(row) }))] })] }));
|
|
44
44
|
}
|
|
45
|
-
export function AdminViewCards({ rows, view, isLoading, emptyLabel = "No items found", onRowClick, selectedIdSet, onToggleSelect, }) {
|
|
45
|
+
export function AdminViewCards({ rows, view, isLoading, emptyLabel = "No items found", onRowClick, selectedIdSet, onToggleSelect, renderRowActions, }) {
|
|
46
46
|
if (isLoading) {
|
|
47
47
|
const count = view === "grid" ? 12 : 8;
|
|
48
48
|
if (view === "list") {
|
|
@@ -54,7 +54,7 @@ export function AdminViewCards({ rows, view, isLoading, emptyLabel = "No items f
|
|
|
54
54
|
return (_jsx(Text, { paddingY: "3xl", size: "sm", color: "muted", align: "center", children: emptyLabel }));
|
|
55
55
|
}
|
|
56
56
|
if (view === "list") {
|
|
57
|
-
return (_jsx(Div, { rounded: "xl", border: "subtle", className: `${__O.hidden} divide-y divide-zinc-100 divide-[var(--appkit-color-border)]`, children: rows.map((row) => (_jsx(AdminCardItem, { row: row, view: "list", selected: selectedIdSet?.has(row.id) ?? false, onToggleSelect: onToggleSelect, onRowClick: onRowClick }, row.id))) }));
|
|
57
|
+
return (_jsx(Div, { rounded: "xl", border: "subtle", className: `${__O.hidden} divide-y divide-zinc-100 divide-[var(--appkit-color-border)]`, children: rows.map((row) => (_jsx(AdminCardItem, { row: row, view: "list", selected: selectedIdSet?.has(row.id) ?? false, onToggleSelect: onToggleSelect, onRowClick: onRowClick, renderRowActions: renderRowActions }, row.id))) }));
|
|
58
58
|
}
|
|
59
|
-
return (_jsx(Grid, { gap: "md", className: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-4", children: rows.map((row) => (_jsx(AdminCardItem, { row: row, view: "grid", selected: selectedIdSet?.has(row.id) ?? false, onToggleSelect: onToggleSelect, onRowClick: onRowClick }, row.id))) }));
|
|
59
|
+
return (_jsx(Grid, { gap: "md", className: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-4", children: rows.map((row) => (_jsx(AdminCardItem, { row: row, view: "grid", selected: selectedIdSet?.has(row.id) ?? false, onToggleSelect: onToggleSelect, onRowClick: onRowClick, renderRowActions: renderRowActions }, row.id))) }));
|
|
60
60
|
}
|
|
@@ -118,7 +118,7 @@ export interface ListingViewConfig<TResponse, TRow extends {
|
|
|
118
118
|
rowHrefTemplate?: string | ((row: TRow) => string);
|
|
119
119
|
/** Hide the table toggle in the toolbar; views with no table column set should use this. */
|
|
120
120
|
hideTableView?: boolean;
|
|
121
|
-
/** Initial view mode (defaults to "
|
|
121
|
+
/** Initial view mode (defaults to "list" — the row-style card view). */
|
|
122
122
|
initialView?: "grid" | "list" | "table";
|
|
123
123
|
className?: string;
|
|
124
124
|
}
|
|
@@ -7,7 +7,7 @@ import { useAdminListing } from "../hooks/useAdminListing";
|
|
|
7
7
|
import { AdminViewCards } from "./AdminViewCards";
|
|
8
8
|
import { DataTable } from "./DataTable";
|
|
9
9
|
export function DataListingView({ config, }) {
|
|
10
|
-
const effectiveInitialView = config.initialView ??
|
|
10
|
+
const effectiveInitialView = config.initialView ?? "list";
|
|
11
11
|
const listing = useAdminListing({
|
|
12
12
|
...config,
|
|
13
13
|
initialView: effectiveInitialView,
|
|
@@ -42,6 +42,26 @@ export function DataListingView({ config, }) {
|
|
|
42
42
|
? `Add ${config.title.replace(/s$/, "")}`
|
|
43
43
|
: `Edit ${config.title.replace(/s$/, "")}`;
|
|
44
44
|
const isEditorOpen = panel.isCreateOpen || panel.isEditOpen;
|
|
45
|
+
// Shared row-navigation resolver — the table branch and the default
|
|
46
|
+
// AdminViewCards branch must agree on when a row is actually clickable.
|
|
47
|
+
// Previously AdminViewCards unconditionally wired onRowClick to
|
|
48
|
+
// openEditPanel even when the config had no renderEditor/onRowClick/
|
|
49
|
+
// rowHrefTemplate, so cards always looked clickable (cursor-pointer,
|
|
50
|
+
// hover state) but silently did nothing (or mutated the URL with no
|
|
51
|
+
// visible drawer) while the table for the same config correctly showed
|
|
52
|
+
// no click affordance at all — read as "table isn't clickable" by users.
|
|
53
|
+
const resolvedRowClick = config.onRowClick
|
|
54
|
+
? (row) => config.onRowClick(row, { openEditPanel: panel.openEditPanel })
|
|
55
|
+
: config.renderEditor
|
|
56
|
+
? (row) => panel.openEditPanel(row.id)
|
|
57
|
+
: config.rowHrefTemplate
|
|
58
|
+
? (row) => {
|
|
59
|
+
const href = typeof config.rowHrefTemplate === "function"
|
|
60
|
+
? config.rowHrefTemplate(row)
|
|
61
|
+
: config.rowHrefTemplate.replace("{id}", encodeURIComponent(row.id));
|
|
62
|
+
window.location.href = href;
|
|
63
|
+
}
|
|
64
|
+
: undefined;
|
|
45
65
|
return (_jsxs(Div, { className: config.className ?? "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: config.searchPlaceholder, onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || config.defaultSort, sortOptions: config.sortOptions, onSortChange: (v) => table.set("sort", v), showTableView: !config.hideTableView, toggles: config.toggles, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState, extra: config.primaryAction || config.toolbarExtra ? (_jsxs(Row, { align: "center", gap: "sm", children: [config.toolbarExtra, config.primaryAction && (_jsxs(Button, { gap: "sm", size: "sm", onClick: () => config.primaryAction.onClick({
|
|
46
66
|
openCreatePanel: panel.openCreatePanel,
|
|
47
67
|
}), children: [config.primaryAction.icon ?? _jsx(Plus, { className: "h-4 w-4" }), config.primaryAction.label] }))] })) : undefined }), config.renderAboveContent?.(), bulkActionItems && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: bulkActionItems })), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p), pageSize: pageSize, onPageSizeChange: setPageSize, paginationConfig: { showPageSizeSelector: true, pageSizeOptions: [10, 25, 50, 100] } }) }) })), _jsxs(Div, { paddingX: "x-sm-md", padding: "y-md", children: [errorMessage && (_jsx(Div, { textSize: "sm", className: "mb-4 border border-error/20", color: "error", surface: "danger-surface", padding: "inline", rounded: "xl", children: errorMessage })), view === "table" && !config.hideTableView ? (_jsx(DataTable, { columns: config.columns, rows: rows, isLoading: isLoading, emptyLabel: config.emptyLabel ?? `No ${config.title.toLowerCase()} found`, selectedIds: selection.selectedIdSet, onToggleSelect: selection.toggle, onToggleSelectAll: (next) => next
|
|
@@ -56,7 +76,11 @@ export function DataListingView({ config, }) {
|
|
|
56
76
|
// The persisted view-mode preference is global, so a "table"
|
|
57
77
|
// value can still reach here on a hideTableView-only view (see
|
|
58
78
|
// the DataTable branch's guard above) — fall back to "grid".
|
|
59
|
-
config.renderCards(rows, view === "table" ? "grid" : view, selectionContext, isLoading)) : (_jsx(AdminViewCards, { rows: rows, view: view === "table" ? "grid" : view, isLoading: isLoading, emptyLabel: config.emptyLabel ?? `No ${config.title.toLowerCase()} found`, onRowClick:
|
|
79
|
+
config.renderCards(rows, view === "table" ? "grid" : view, selectionContext, isLoading)) : (_jsx(AdminViewCards, { rows: rows, view: view === "table" ? "grid" : view, isLoading: isLoading, emptyLabel: config.emptyLabel ?? `No ${config.title.toLowerCase()} found`, onRowClick: resolvedRowClick
|
|
80
|
+
? (row) => resolvedRowClick(row)
|
|
81
|
+
: undefined, selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle, renderRowActions: config.renderRowActions
|
|
82
|
+
? (row) => config.renderRowActions(row)
|
|
83
|
+
: undefined }))] }), config.renderFilterPanel && (_jsx(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearFilters, activeCount: activeFilterCount, children: config.renderFilterPanel({
|
|
60
84
|
pendingFilters,
|
|
61
85
|
setPendingFilters,
|
|
62
86
|
applyFilters,
|
|
@@ -11,7 +11,7 @@ export function useAdminListing(config) {
|
|
|
11
11
|
// (AdminViewCards' one-full-width-card-per-row layout) unless the caller
|
|
12
12
|
// explicitly pins hideTableView (grid-only views like coupons); the user's
|
|
13
13
|
// own explicit choice, once made, always wins and persists across visits.
|
|
14
|
-
const { view, setView } = useDataViewMode(config.initialView ?? "
|
|
14
|
+
const { view, setView } = useDataViewMode(config.initialView ?? "list");
|
|
15
15
|
const table = useUrlTable({
|
|
16
16
|
defaults: { pageSize: String(defaultPageSize), sort: defaultSort, ...filterDefaults },
|
|
17
17
|
});
|
|
@@ -54,7 +54,7 @@ export async function getSellerReviews(storeId) {
|
|
|
54
54
|
rating: r.rating,
|
|
55
55
|
title: r.title,
|
|
56
56
|
comment: r.comment,
|
|
57
|
-
images: r.images
|
|
57
|
+
images: r.images,
|
|
58
58
|
status: r.status,
|
|
59
59
|
helpfulCount: r.helpfulCount,
|
|
60
60
|
reportCount: r.reportCount,
|
|
@@ -85,7 +85,7 @@ export async function getReviewsAuthoredBy(userId) {
|
|
|
85
85
|
rating: r.rating,
|
|
86
86
|
title: r.title,
|
|
87
87
|
comment: r.comment,
|
|
88
|
-
images: r.images
|
|
88
|
+
images: r.images,
|
|
89
89
|
status: r.status,
|
|
90
90
|
helpfulCount: r.helpfulCount,
|
|
91
91
|
reportCount: r.reportCount,
|
|
@@ -110,7 +110,7 @@ export async function getReviewsReceivedBy(userId) {
|
|
|
110
110
|
rating: r.rating,
|
|
111
111
|
title: r.title,
|
|
112
112
|
comment: r.comment,
|
|
113
|
-
images: r.images
|
|
113
|
+
images: r.images,
|
|
114
114
|
status: r.status,
|
|
115
115
|
helpfulCount: r.helpfulCount,
|
|
116
116
|
reportCount: r.reportCount,
|
|
@@ -85,6 +85,8 @@ export declare const RefundStatusValues: {
|
|
|
85
85
|
export interface OrderDocumentItem {
|
|
86
86
|
productId: string;
|
|
87
87
|
productTitle: string;
|
|
88
|
+
/** Snapshotted from the product/cart-item at order time so the order-detail UI can render a thumbnail without an extra product fetch. */
|
|
89
|
+
image?: string;
|
|
88
90
|
quantity: number;
|
|
89
91
|
unitPrice: number;
|
|
90
92
|
totalPrice: number;
|
|
@@ -60,9 +60,7 @@ function toProductItem(doc) {
|
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
62
|
function toReview(doc) {
|
|
63
|
-
const images = Array.isArray(doc.images)
|
|
64
|
-
? doc.images.map((url) => ({ url }))
|
|
65
|
-
: undefined;
|
|
63
|
+
const images = Array.isArray(doc.images) ? doc.images : undefined;
|
|
66
64
|
const createdAt = doc.createdAt instanceof Date
|
|
67
65
|
? doc.createdAt.toISOString()
|
|
68
66
|
: typeof doc.createdAt === "string"
|
|
@@ -292,6 +292,11 @@ export declare const DASHBOARD_QUICK_ACTION_ID: {
|
|
|
292
292
|
readonly ADMIN_FAQS: "dqa-admin-faqs";
|
|
293
293
|
readonly ADMIN_CAROUSEL: "dqa-admin-carousel";
|
|
294
294
|
readonly ADMIN_SECTIONS: "dqa-admin-sections";
|
|
295
|
+
readonly ADMIN_BLOG: "dqa-admin-blog";
|
|
296
|
+
readonly ADMIN_SCAMMERS: "dqa-admin-scammers";
|
|
297
|
+
readonly ADMIN_BUNDLES: "dqa-admin-bundles";
|
|
298
|
+
readonly ADMIN_PRIZE_DRAWS: "dqa-admin-prize-draws";
|
|
299
|
+
readonly ADMIN_TESTER_CHECKLIST: "dqa-admin-tester-checklist";
|
|
295
300
|
readonly SELLER_ADD_PRODUCT: "dqa-seller-add-product";
|
|
296
301
|
readonly SELLER_ADD_COUPON: "dqa-seller-add-coupon";
|
|
297
302
|
readonly SELLER_VIEW_ORDERS: "dqa-seller-view-orders";
|
|
@@ -305,6 +310,12 @@ export declare const DASHBOARD_QUICK_ACTION_ID: {
|
|
|
305
310
|
readonly SELLER_PRODUCTS: "dqa-seller-products";
|
|
306
311
|
readonly SELLER_STOREFRONT: "dqa-seller-storefront";
|
|
307
312
|
readonly SELLER_ANALYTICS: "dqa-seller-analytics";
|
|
313
|
+
readonly SELLER_BUNDLES: "dqa-seller-bundles";
|
|
314
|
+
readonly SELLER_PRIZE_DRAWS: "dqa-seller-prize-draws";
|
|
315
|
+
readonly SELLER_OFFERS: "dqa-seller-offers";
|
|
316
|
+
readonly SELLER_GROUPED_LISTINGS: "dqa-seller-grouped-listings";
|
|
317
|
+
readonly SELLER_CATEGORIES: "dqa-seller-categories";
|
|
318
|
+
readonly SELLER_PRINT_CENTER: "dqa-seller-print-center";
|
|
308
319
|
readonly USER_VIEW_ORDERS: "dqa-user-view-orders";
|
|
309
320
|
readonly USER_VIEW_WISHLIST: "dqa-user-view-wishlist";
|
|
310
321
|
readonly USER_EDIT_PROFILE: "dqa-user-edit-profile";
|
|
@@ -332,8 +343,8 @@ export interface DashboardQuickActionMeta {
|
|
|
332
343
|
}
|
|
333
344
|
export declare const DASHBOARD_QUICK_ACTION_META: Record<DashboardQuickActionId, DashboardQuickActionMeta>;
|
|
334
345
|
export declare const DASHBOARD_QUICK_ACTIONS: {
|
|
335
|
-
readonly admin: readonly ["dqa-admin-add-product", "dqa-admin-add-user", "dqa-admin-add-store", "dqa-admin-add-coupon", "dqa-admin-add-event", "dqa-admin-add-blog", "dqa-admin-users", "dqa-admin-stores", "dqa-admin-orders", "dqa-admin-payouts", "dqa-admin-analytics", "dqa-admin-categories", "dqa-admin-reviews", "dqa-admin-events", "dqa-admin-faqs", "dqa-admin-carousel", "dqa-admin-sections", "dqa-admin-support", "dqa-admin-moderation", "dqa-admin-settings"];
|
|
336
|
-
readonly seller: readonly ["dqa-seller-add-product", "dqa-seller-products", "dqa-seller-view-orders", "dqa-seller-analytics", "dqa-seller-add-coupon", "dqa-seller-auctions", "dqa-seller-payout-request", "dqa-seller-shipping", "dqa-seller-messages", "dqa-seller-whatsapp", "dqa-seller-reviews", "dqa-seller-storefront", "dqa-seller-settings"];
|
|
346
|
+
readonly admin: readonly ["dqa-admin-add-product", "dqa-admin-add-user", "dqa-admin-add-store", "dqa-admin-add-coupon", "dqa-admin-add-event", "dqa-admin-add-blog", "dqa-admin-users", "dqa-admin-stores", "dqa-admin-orders", "dqa-admin-payouts", "dqa-admin-analytics", "dqa-admin-categories", "dqa-admin-reviews", "dqa-admin-events", "dqa-admin-faqs", "dqa-admin-carousel", "dqa-admin-sections", "dqa-admin-support", "dqa-admin-moderation", "dqa-admin-blog", "dqa-admin-scammers", "dqa-admin-bundles", "dqa-admin-prize-draws", "dqa-admin-tester-checklist", "dqa-admin-settings"];
|
|
347
|
+
readonly seller: readonly ["dqa-seller-add-product", "dqa-seller-products", "dqa-seller-view-orders", "dqa-seller-analytics", "dqa-seller-add-coupon", "dqa-seller-auctions", "dqa-seller-bundles", "dqa-seller-prize-draws", "dqa-seller-offers", "dqa-seller-grouped-listings", "dqa-seller-categories", "dqa-seller-payout-request", "dqa-seller-shipping", "dqa-seller-print-center", "dqa-seller-messages", "dqa-seller-whatsapp", "dqa-seller-reviews", "dqa-seller-storefront", "dqa-seller-settings"];
|
|
337
348
|
readonly user: readonly ["dqa-user-view-orders", "dqa-user-view-wishlist", "dqa-user-edit-profile", "dqa-user-add-address", "dqa-user-recently-viewed", "dqa-user-my-catalogue", "dqa-user-my-coupons"];
|
|
338
349
|
};
|
|
339
350
|
export declare const ADMIN_BULK_ACTIONS: {
|