@mohasinac/appkit 4.7.2 → 4.8.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.
Files changed (45) hide show
  1. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +25 -5
  2. package/dist/_internal/shared/features/cart/schema.d.ts +6 -6
  3. package/dist/_internal/shared/features/orders/schema.d.ts +2 -2
  4. package/dist/_internal/shared/features/products/schema.d.ts +8 -8
  5. package/dist/features/account/schemas/index.d.ts +12 -12
  6. package/dist/features/admin/components/AdminArtView.js +1 -0
  7. package/dist/features/admin/components/AdminBlogView.js +1 -0
  8. package/dist/features/admin/components/AdminClassifiedView.js +1 -0
  9. package/dist/features/admin/components/AdminDigitalCodesView.js +1 -0
  10. package/dist/features/admin/components/AdminLiveView.js +1 -0
  11. package/dist/features/admin/components/AdminPrizeDrawsView.js +1 -0
  12. package/dist/features/admin/components/AdminProductsView.js +1 -0
  13. package/dist/features/admin/components/AdminStickersView.js +1 -0
  14. package/dist/features/admin/components/AdminStoresView.js +1 -0
  15. package/dist/features/admin/components/AdminUsersView.js +1 -0
  16. package/dist/features/admin/components/AdminViewCards.d.ts +3 -1
  17. package/dist/features/admin/components/AdminViewCards.js +21 -7
  18. package/dist/features/admin/components/DataListingView.d.ts +2 -0
  19. package/dist/features/admin/components/DataListingView.js +4 -2
  20. package/dist/features/admin/components/DataTable.d.ts +3 -1
  21. package/dist/features/admin/components/DataTable.js +36 -21
  22. package/dist/features/collections/schemas/index.d.ts +3 -3
  23. package/dist/features/homepage/schemas/index.d.ts +4 -4
  24. package/dist/features/orders/schemas/index.d.ts +22 -22
  25. package/dist/features/pre-orders/schemas/index.d.ts +2 -2
  26. package/dist/features/products/schemas/index.d.ts +8 -8
  27. package/dist/features/products/schemas/product-features.validators.d.ts +6 -6
  28. package/dist/features/reviews/schemas/index.d.ts +4 -4
  29. package/dist/features/scams/schemas/index.d.ts +4 -4
  30. package/dist/features/seller/components/SellerAuctionsView.js +1 -0
  31. package/dist/features/seller/components/SellerPreOrdersView.js +1 -0
  32. package/dist/features/seller/components/SellerPrizeDrawsView.js +1 -0
  33. package/dist/features/seller/components/SellerProductsView.js +1 -0
  34. package/dist/features/shipments/schemas/validation.d.ts +6 -6
  35. package/dist/features/support/schemas/index.d.ts +2 -2
  36. package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
  37. package/dist/schemas/registry.d.ts +70 -70
  38. package/dist/schemas/webhooks/razorpay.d.ts +50 -50
  39. package/dist/ui/columns/column-renderers.d.ts +5 -0
  40. package/dist/ui/columns/column-renderers.js +135 -0
  41. package/dist/ui/columns/index.d.ts +2 -2
  42. package/dist/ui/columns/index.js +1 -1
  43. package/dist/ui/index.d.ts +2 -2
  44. package/dist/ui/index.js +1 -1
  45. package/package.json +1 -1
@@ -22,8 +22,9 @@ import { normalizeError } from "../../../../errors/normalize";
22
22
  * the underlying *Sidebar components.
23
23
  */
24
24
  import { useCallback, useEffect, useState, startTransition } from "react";
25
- import { usePathname } from "next/navigation";
25
+ import { usePathname, useRouter } from "next/navigation";
26
26
  import Link from "next/link";
27
+ import { useQueryClient } from "@tanstack/react-query";
27
28
  import { useDashboardNav } from "../../../../features/layout/DashboardNavContext";
28
29
  import { AdminSidebar } from "../../../../features/admin/components/AdminSidebar";
29
30
  import { StoreSidebar } from "../../../../features/seller/components/SellerSidebar";
@@ -33,7 +34,10 @@ import { filterNavItems } from "./filterNavItems";
33
34
  import { useSiteSettings } from "../../../../core/hooks/useSiteSettings";
34
35
  import { useTheme } from "../../theme";
35
36
  import { BackgroundRenderer, Div, Nav, Span } from "../../../../ui";
37
+ import { useToast } from "../../../../ui/components/Toast";
36
38
  import { useVisualViewportInset } from "../../../../react/hooks/useVisualViewportInset";
39
+ import { useSession } from "../../../../react/contexts/SessionContext";
40
+ import { ROUTES } from "../../../../next/routing/route-map";
37
41
  /**
38
42
  * Hoisted drawer-state hook — the matchMedia-aware open/close logic that was
39
43
  * triplicated across admin/store/user layouts. Used internally by
@@ -153,6 +157,24 @@ export function DashboardLayoutClient({ variant, groups, permissions, activeHref
153
157
  const storageKey = `appkit:sidebar-open:${variant}`;
154
158
  const { desktopOpen, mobileOpen, close, closeMobile, toggle } = useResponsiveDrawer(storageKey);
155
159
  useEffect(() => { closeMobile(); }, [pathname, closeMobile]);
160
+ const router = useRouter();
161
+ const { signOut } = useSession();
162
+ const { showToast } = useToast();
163
+ const queryClient = useQueryClient();
164
+ const handleLogout = useCallback(async () => {
165
+ try {
166
+ await signOut();
167
+ void queryClient.invalidateQueries({ queryKey: ["wishlist"] });
168
+ void queryClient.invalidateQueries({ queryKey: ["cart"] });
169
+ void queryClient.invalidateQueries({ queryKey: ["notifications"] });
170
+ showToast("Signed out successfully", "info");
171
+ }
172
+ catch (_err) {
173
+ void normalizeError(_err);
174
+ showToast("Signed out", "info");
175
+ }
176
+ router.push(String(ROUTES.AUTH.LOGIN));
177
+ }, [signOut, queryClient, router, showToast]);
156
178
  const { data: settings } = useSiteSettings();
157
179
  const navConfig = settings?.navConfig;
158
180
  const { theme } = useTheme();
@@ -166,10 +188,8 @@ export function DashboardLayoutClient({ variant, groups, permissions, activeHref
166
188
  ? filteredGroups
167
189
  : groups;
168
190
  const crossNavLinkClass = "flex items-center gap-[var(--appkit-space-2)] rounded-lg px-[var(--appkit-space-3)] py-[var(--appkit-space-2)] text-[0.8125rem] font-medium text-[var(--appkit-color-text-muted)] hover:bg-[var(--appkit-color-surface-elevated)]/60 hover:text-[var(--appkit-color-text)] transition-colors";
169
- const hasCrossNav = Boolean(crossNav?.profileHref || crossNav?.storeHref || crossNav?.adminHref);
170
- const renderCrossNavFooter = hasCrossNav
171
- ? () => (_jsxs(Nav, { "aria-label": "Cross-dashboard links", padding: "y-xs", children: [crossNav?.storeHref && (_jsx(Link, { href: crossNav.storeHref, onClick: closeMobile, className: crossNavLinkClass, children: "Go to my Store" })), crossNav?.adminHref && (_jsx(Link, { href: crossNav.adminHref, onClick: closeMobile, className: crossNavLinkClass, children: "Back to Admin" })), crossNav?.profileHref && (_jsx(Link, { href: crossNav.profileHref, onClick: closeMobile, className: crossNavLinkClass, children: "My Profile" }))] }))
172
- : undefined;
191
+ const logoutBtnClass = "flex w-full items-center gap-[var(--appkit-space-2)] rounded-lg px-[var(--appkit-space-3)] py-[var(--appkit-space-2)] text-[0.8125rem] font-medium text-error transition-colors hover:bg-error-surface hover:text-error";
192
+ const renderCrossNavFooter = () => (_jsxs(Nav, { "aria-label": "Cross-dashboard links", padding: "y-xs", children: [crossNav?.storeHref && (_jsx(Link, { href: crossNav.storeHref, onClick: closeMobile, className: crossNavLinkClass, children: "Go to my Store" })), crossNav?.adminHref && (_jsx(Link, { href: crossNav.adminHref, onClick: closeMobile, className: crossNavLinkClass, children: "Back to Admin" })), crossNav?.profileHref && (_jsx(Link, { href: crossNav.profileHref, onClick: closeMobile, className: crossNavLinkClass, children: "My Profile" })), _jsx("button", { type: "button", onClick: () => { closeMobile(); void handleLogout(); }, className: logoutBtnClass, children: "Log out" })] }));
173
193
  return (_jsxs(_Fragment, { children: [hasBackground && (_jsx(BackgroundRenderer, { mode: theme === "dark" ? "dark" : "light", lightMode: resolvedLightBackground ?? { type: "color", value: "" }, darkMode: resolvedDarkBackground ?? { type: "color", value: "" } })), variant === "admin" && (_jsx(AdminSidebar, { variant: "sidebar", desktopOpen: desktopOpen, mobileOpen: mobileOpen, activePath: activeHref, groups: adminGroups, onCloseMobile: close, onToggle: toggle, className: className, renderFooter: renderCrossNavFooter })), variant === "store" && (_jsx(StoreSidebar, { variant: "sidebar", desktopOpen: desktopOpen, mobileOpen: mobileOpen, activeHref: activeHref, items: [], groups: filteredGroups, onCloseMobile: close, onToggle: toggle, className: className, renderFooter: renderCrossNavFooter })), variant === "user" && (_jsx(UserSidebar, { variant: "sidebar", desktopOpen: desktopOpen, mobileOpen: mobileOpen, items: filteredGroups.flatMap((g) => g.items), groups: filteredGroups, onCloseMobile: close, onToggle: toggle, className: className, renderFooter: renderCrossNavFooter })), _jsx(Div, { className: [
174
194
  "w-full flex-1 flex flex-col min-h-[calc(100dvh-var(--header-height,3.5rem))]",
175
195
  "pb-[var(--appkit-space-16)] lg:pb-[0]", // clears the fixed mobile bottom-nav
@@ -15,7 +15,7 @@ export declare const addToCartSchema: z.ZodObject<{
15
15
  }, "strip", z.ZodTypeAny, {
16
16
  currency: string;
17
17
  storeId: string;
18
- listingType: "standard" | "auction" | "pre-order" | "prize-draw" | "classified" | "digital-code" | "live";
18
+ listingType: "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live";
19
19
  price: number;
20
20
  storeName: string;
21
21
  productId: string;
@@ -27,7 +27,7 @@ export declare const addToCartSchema: z.ZodObject<{
27
27
  isOffer?: boolean | undefined;
28
28
  }, {
29
29
  storeId: string;
30
- listingType: "standard" | "auction" | "pre-order" | "prize-draw" | "classified" | "digital-code" | "live";
30
+ listingType: "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live";
31
31
  price: number;
32
32
  productId: string;
33
33
  productTitle: string;
@@ -73,7 +73,7 @@ export declare const mergeGuestCartSchema: z.ZodObject<{
73
73
  }, "strip", z.ZodTypeAny, {
74
74
  currency: string;
75
75
  storeId: string;
76
- listingType: "standard" | "auction" | "pre-order" | "prize-draw" | "classified" | "digital-code" | "live";
76
+ listingType: "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live";
77
77
  price: number;
78
78
  storeName: string;
79
79
  productId: string;
@@ -85,7 +85,7 @@ export declare const mergeGuestCartSchema: z.ZodObject<{
85
85
  isOffer?: boolean | undefined;
86
86
  }, {
87
87
  storeId: string;
88
- listingType: "standard" | "auction" | "pre-order" | "prize-draw" | "classified" | "digital-code" | "live";
88
+ listingType: "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live";
89
89
  price: number;
90
90
  productId: string;
91
91
  productTitle: string;
@@ -101,7 +101,7 @@ export declare const mergeGuestCartSchema: z.ZodObject<{
101
101
  guestItems: {
102
102
  currency: string;
103
103
  storeId: string;
104
- listingType: "standard" | "auction" | "pre-order" | "prize-draw" | "classified" | "digital-code" | "live";
104
+ listingType: "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live";
105
105
  price: number;
106
106
  storeName: string;
107
107
  productId: string;
@@ -115,7 +115,7 @@ export declare const mergeGuestCartSchema: z.ZodObject<{
115
115
  }, {
116
116
  guestItems: {
117
117
  storeId: string;
118
- listingType: "standard" | "auction" | "pre-order" | "prize-draw" | "classified" | "digital-code" | "live";
118
+ listingType: "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live";
119
119
  price: number;
120
120
  productId: string;
121
121
  productTitle: string;
@@ -87,13 +87,13 @@ export declare const updateOrderStatusSchema: z.ZodObject<{
87
87
  carrier: z.ZodOptional<z.ZodString>;
88
88
  note: z.ZodOptional<z.ZodString>;
89
89
  }, "strip", z.ZodTypeAny, {
90
- status: "cancelled" | "processing" | "refunded" | "shipped" | "delivered" | "return_requested";
90
+ status: "cancelled" | "processing" | "refunded" | "delivered" | "shipped" | "return_requested";
91
91
  orderId: string;
92
92
  note?: string | undefined;
93
93
  trackingNumber?: string | undefined;
94
94
  carrier?: string | undefined;
95
95
  }, {
96
- status: "cancelled" | "processing" | "refunded" | "shipped" | "delivered" | "return_requested";
96
+ status: "cancelled" | "processing" | "refunded" | "delivered" | "shipped" | "return_requested";
97
97
  orderId: string;
98
98
  note?: string | undefined;
99
99
  trackingNumber?: string | undefined;
@@ -33,12 +33,12 @@ export declare const productInputSchema: z.ZodObject<{
33
33
  mainImage: string;
34
34
  images: string[];
35
35
  tags: string[];
36
+ features?: string[] | undefined;
36
37
  description?: string | undefined;
37
38
  seoTitle?: string | undefined;
38
39
  seoDescription?: string | undefined;
39
40
  seoKeywords?: string[] | undefined;
40
41
  brandSlug?: string | undefined;
41
- features?: string[] | undefined;
42
42
  shippingInfo?: string | undefined;
43
43
  returnPolicy?: string | undefined;
44
44
  condition?: "new" | "used" | "refurbished" | "like_new" | "good" | "fair" | "poor" | "broken" | undefined;
@@ -53,6 +53,7 @@ export declare const productInputSchema: z.ZodObject<{
53
53
  price: number;
54
54
  mainImage: string;
55
55
  currency?: string | undefined;
56
+ features?: string[] | undefined;
56
57
  description?: string | undefined;
57
58
  seoTitle?: string | undefined;
58
59
  seoDescription?: string | undefined;
@@ -62,7 +63,6 @@ export declare const productInputSchema: z.ZodObject<{
62
63
  availableQuantity?: number | undefined;
63
64
  images?: string[] | undefined;
64
65
  tags?: string[] | undefined;
65
- features?: string[] | undefined;
66
66
  shippingInfo?: string | undefined;
67
67
  returnPolicy?: string | undefined;
68
68
  condition?: "new" | "used" | "refurbished" | "like_new" | "good" | "fair" | "poor" | "broken" | undefined;
@@ -99,6 +99,7 @@ export declare const productUpdateSchema: z.ZodObject<{
99
99
  }, "strip", z.ZodTypeAny, {
100
100
  currency?: string | undefined;
101
101
  title?: string | undefined;
102
+ features?: string[] | undefined;
102
103
  category?: string | undefined;
103
104
  description?: string | undefined;
104
105
  seoTitle?: string | undefined;
@@ -111,7 +112,6 @@ export declare const productUpdateSchema: z.ZodObject<{
111
112
  mainImage?: string | undefined;
112
113
  images?: string[] | undefined;
113
114
  tags?: string[] | undefined;
114
- features?: string[] | undefined;
115
115
  shippingInfo?: string | undefined;
116
116
  returnPolicy?: string | undefined;
117
117
  condition?: "new" | "used" | "refurbished" | "like_new" | "good" | "fair" | "poor" | "broken" | undefined;
@@ -123,6 +123,7 @@ export declare const productUpdateSchema: z.ZodObject<{
123
123
  }, {
124
124
  currency?: string | undefined;
125
125
  title?: string | undefined;
126
+ features?: string[] | undefined;
126
127
  category?: string | undefined;
127
128
  description?: string | undefined;
128
129
  seoTitle?: string | undefined;
@@ -135,7 +136,6 @@ export declare const productUpdateSchema: z.ZodObject<{
135
136
  mainImage?: string | undefined;
136
137
  images?: string[] | undefined;
137
138
  tags?: string[] | undefined;
138
- features?: string[] | undefined;
139
139
  shippingInfo?: string | undefined;
140
140
  returnPolicy?: string | undefined;
141
141
  condition?: "new" | "used" | "refurbished" | "like_new" | "good" | "fair" | "poor" | "broken" | undefined;
@@ -193,12 +193,12 @@ export declare const auctionInputSchema: z.ZodObject<{
193
193
  auctionEndDate: string;
194
194
  startingBid: number;
195
195
  autoExtendable: boolean;
196
+ features?: string[] | undefined;
196
197
  description?: string | undefined;
197
198
  seoTitle?: string | undefined;
198
199
  seoDescription?: string | undefined;
199
200
  seoKeywords?: string[] | undefined;
200
201
  brandSlug?: string | undefined;
201
- features?: string[] | undefined;
202
202
  shippingInfo?: string | undefined;
203
203
  returnPolicy?: string | undefined;
204
204
  condition?: "new" | "used" | "refurbished" | "like_new" | "good" | "fair" | "poor" | "broken" | undefined;
@@ -221,6 +221,7 @@ export declare const auctionInputSchema: z.ZodObject<{
221
221
  auctionEndDate: string;
222
222
  startingBid: number;
223
223
  currency?: string | undefined;
224
+ features?: string[] | undefined;
224
225
  description?: string | undefined;
225
226
  seoTitle?: string | undefined;
226
227
  seoDescription?: string | undefined;
@@ -230,7 +231,6 @@ export declare const auctionInputSchema: z.ZodObject<{
230
231
  availableQuantity?: number | undefined;
231
232
  images?: string[] | undefined;
232
233
  tags?: string[] | undefined;
233
- features?: string[] | undefined;
234
234
  shippingInfo?: string | undefined;
235
235
  returnPolicy?: string | undefined;
236
236
  condition?: "new" | "used" | "refurbished" | "like_new" | "good" | "fair" | "poor" | "broken" | undefined;
@@ -291,12 +291,12 @@ export declare const preOrderInputSchema: z.ZodObject<{
291
291
  preOrderDeliveryDate: string;
292
292
  preOrderProductionStatus: "upcoming" | "in_production" | "ready_to_ship";
293
293
  preOrderCancellable: boolean;
294
+ features?: string[] | undefined;
294
295
  description?: string | undefined;
295
296
  seoTitle?: string | undefined;
296
297
  seoDescription?: string | undefined;
297
298
  seoKeywords?: string[] | undefined;
298
299
  brandSlug?: string | undefined;
299
- features?: string[] | undefined;
300
300
  shippingInfo?: string | undefined;
301
301
  returnPolicy?: string | undefined;
302
302
  condition?: "new" | "used" | "refurbished" | "like_new" | "good" | "fair" | "poor" | "broken" | undefined;
@@ -315,6 +315,7 @@ export declare const preOrderInputSchema: z.ZodObject<{
315
315
  mainImage: string;
316
316
  preOrderDeliveryDate: string;
317
317
  currency?: string | undefined;
318
+ features?: string[] | undefined;
318
319
  description?: string | undefined;
319
320
  seoTitle?: string | undefined;
320
321
  seoDescription?: string | undefined;
@@ -324,7 +325,6 @@ export declare const preOrderInputSchema: z.ZodObject<{
324
325
  availableQuantity?: number | undefined;
325
326
  images?: string[] | undefined;
326
327
  tags?: string[] | undefined;
327
- features?: string[] | undefined;
328
328
  shippingInfo?: string | undefined;
329
329
  returnPolicy?: string | undefined;
330
330
  condition?: "new" | "used" | "refurbished" | "like_new" | "good" | "fair" | "poor" | "broken" | undefined;
@@ -42,14 +42,14 @@ export declare const notificationPreferencesSchema: z.ZodObject<{
42
42
  push: z.ZodOptional<z.ZodBoolean>;
43
43
  }, "strip", z.ZodTypeAny, {
44
44
  push?: boolean | undefined;
45
- promotions?: boolean | undefined;
46
45
  newsletter?: boolean | undefined;
46
+ promotions?: boolean | undefined;
47
47
  sms?: boolean | undefined;
48
48
  orderUpdates?: boolean | undefined;
49
49
  }, {
50
50
  push?: boolean | undefined;
51
- promotions?: boolean | undefined;
52
51
  newsletter?: boolean | undefined;
52
+ promotions?: boolean | undefined;
53
53
  sms?: boolean | undefined;
54
54
  orderUpdates?: boolean | undefined;
55
55
  }>;
@@ -113,14 +113,14 @@ export declare const userProfileSchema: z.ZodObject<{
113
113
  push: z.ZodOptional<z.ZodBoolean>;
114
114
  }, "strip", z.ZodTypeAny, {
115
115
  push?: boolean | undefined;
116
- promotions?: boolean | undefined;
117
116
  newsletter?: boolean | undefined;
117
+ promotions?: boolean | undefined;
118
118
  sms?: boolean | undefined;
119
119
  orderUpdates?: boolean | undefined;
120
120
  }, {
121
121
  push?: boolean | undefined;
122
- promotions?: boolean | undefined;
123
122
  newsletter?: boolean | undefined;
123
+ promotions?: boolean | undefined;
124
124
  sms?: boolean | undefined;
125
125
  orderUpdates?: boolean | undefined;
126
126
  }>>;
@@ -132,9 +132,6 @@ export declare const userProfileSchema: z.ZodObject<{
132
132
  displayName?: string | undefined;
133
133
  createdAt?: string | undefined;
134
134
  updatedAt?: string | undefined;
135
- phone?: string | undefined;
136
- photoURL?: string | undefined;
137
- bio?: string | undefined;
138
135
  addresses?: {
139
136
  country: string;
140
137
  id: string;
@@ -147,10 +144,13 @@ export declare const userProfileSchema: z.ZodObject<{
147
144
  phone?: string | undefined;
148
145
  line2?: string | undefined;
149
146
  }[] | undefined;
147
+ phone?: string | undefined;
148
+ photoURL?: string | undefined;
149
+ bio?: string | undefined;
150
150
  notificationPreferences?: {
151
151
  push?: boolean | undefined;
152
- promotions?: boolean | undefined;
153
152
  newsletter?: boolean | undefined;
153
+ promotions?: boolean | undefined;
154
154
  sms?: boolean | undefined;
155
155
  orderUpdates?: boolean | undefined;
156
156
  } | undefined;
@@ -160,9 +160,6 @@ export declare const userProfileSchema: z.ZodObject<{
160
160
  displayName?: string | undefined;
161
161
  createdAt?: string | undefined;
162
162
  updatedAt?: string | undefined;
163
- phone?: string | undefined;
164
- photoURL?: string | undefined;
165
- bio?: string | undefined;
166
163
  addresses?: {
167
164
  country: string;
168
165
  id: string;
@@ -175,10 +172,13 @@ export declare const userProfileSchema: z.ZodObject<{
175
172
  phone?: string | undefined;
176
173
  line2?: string | undefined;
177
174
  }[] | undefined;
175
+ phone?: string | undefined;
176
+ photoURL?: string | undefined;
177
+ bio?: string | undefined;
178
178
  notificationPreferences?: {
179
179
  push?: boolean | undefined;
180
- promotions?: boolean | undefined;
181
180
  newsletter?: boolean | undefined;
181
+ promotions?: boolean | undefined;
182
182
  sms?: boolean | undefined;
183
183
  orderUpdates?: boolean | undefined;
184
184
  } | undefined;
@@ -34,6 +34,7 @@ const ADMIN_ART_CONFIG = {
34
34
  ].join(" · "),
35
35
  status: toStringValue(item.status, "draft"),
36
36
  updatedAt: toRelativeDate(item.updatedAt ?? item.createdAt),
37
+ image: toStringValue(item.mainImage, "") || undefined,
37
38
  })),
38
39
  getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
39
40
  buildFilters: () => "listingType==art",
@@ -42,6 +42,7 @@ export function AdminBlogView({ children, ...props }) {
42
42
  ].join(" · "),
43
43
  status: toStringValue(item.status, "Draft"),
44
44
  updatedAt: toRelativeDate(item.updatedAt ?? item.createdAt),
45
+ image: toStringValue(item.coverImage, "") || undefined,
45
46
  })),
46
47
  getTotal: (response, mappedRows) => {
47
48
  if (typeof response.meta?.filteredTotal === "number")
@@ -34,6 +34,7 @@ const ADMIN_CLASSIFIED_CONFIG = {
34
34
  ].join(" · "),
35
35
  status: toStringValue(item.status, "draft"),
36
36
  updatedAt: toRelativeDate(item.updatedAt ?? item.createdAt),
37
+ image: toStringValue(item.mainImage, "") || undefined,
37
38
  })),
38
39
  getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
39
40
  buildFilters: () => "listingType==classified",
@@ -40,6 +40,7 @@ const ADMIN_DIGITAL_CODES_CONFIG = {
40
40
  .join(" · "),
41
41
  status: toStringValue(item.status, "draft"),
42
42
  updatedAt: toRelativeDate(item.updatedAt ?? item.createdAt),
43
+ image: toStringValue(item.mainImage, "") || undefined,
43
44
  };
44
45
  }),
45
46
  getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
@@ -39,6 +39,7 @@ const ADMIN_LIVE_CONFIG = {
39
39
  .join(" · "),
40
40
  status: toStringValue(item.status, "draft"),
41
41
  updatedAt: toRelativeDate(item.updatedAt ?? item.createdAt),
42
+ image: toStringValue(item.mainImage, "") || undefined,
42
43
  };
43
44
  }),
44
45
  getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
@@ -86,6 +86,7 @@ export function AdminPrizeDrawsView({ children, ...props }) {
86
86
  drawDate: item.prizeRevealWindowEnd
87
87
  ? toRelativeDate(item.prizeRevealWindowEnd)
88
88
  : "TBA",
89
+ image: toStringValue(item.mainImage, "") || undefined,
89
90
  };
90
91
  }),
91
92
  getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
@@ -154,6 +154,7 @@ export function AdminProductsView({ children, ...props }) {
154
154
  isOnSale: Boolean(item.isOnSale),
155
155
  isSold: Boolean(item.isSold),
156
156
  barcodeId: typeof item.barcodeId === "string" ? item.barcodeId : undefined,
157
+ image: toStringValue(item.mainImage, "") || undefined,
157
158
  };
158
159
  return overrides[id] ? { ...base, ...overrides[id] } : base;
159
160
  }),
@@ -34,6 +34,7 @@ const ADMIN_STICKERS_CONFIG = {
34
34
  ].join(" · "),
35
35
  status: toStringValue(item.status, "draft"),
36
36
  updatedAt: toRelativeDate(item.updatedAt ?? item.createdAt),
37
+ image: toStringValue(item.mainImage, "") || undefined,
37
38
  })),
38
39
  getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
39
40
  buildFilters: () => "listingType==stickers",
@@ -64,6 +64,7 @@ export function AdminStoresView({ children, ...props }) {
64
64
  ].join(" · "),
65
65
  status: toStringValue(item.status, "Pending"),
66
66
  updatedAt: toRelativeDate(item.updatedAt ?? item.createdAt),
67
+ image: toStringValue(item.storeLogoURL, "") || undefined,
67
68
  _raw: item,
68
69
  })),
69
70
  getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
@@ -132,6 +132,7 @@ export function AdminUsersView({ children, ...props }) {
132
132
  ].join(" · "),
133
133
  status,
134
134
  updatedAt: toRelativeDate(item.lastLoginAt ?? item.createdAt),
135
+ image: toStringValue(item.photoURL, "") || undefined,
135
136
  _raw: item,
136
137
  };
137
138
  }),
@@ -10,6 +10,8 @@ interface AdminViewCardsProps {
10
10
  onToggleSelect?: (id: string) => void;
11
11
  /** Same row-actions menu DataTable renders in its table view — mirrored here so cards carry the same quick actions, not just navigation. */
12
12
  renderRowActions?: (row: AdminListingScaffoldRow) => React.ReactNode;
13
+ /** Resource-type emoji fallback for rows without their own `image` (e.g. 👤 for users, 🏪 for stores). */
14
+ resourceIcon?: string;
13
15
  }
14
- export declare function AdminViewCards({ rows, view, isLoading, emptyLabel, onRowClick, selectedIdSet, onToggleSelect, renderRowActions, }: AdminViewCardsProps): React.JSX.Element;
16
+ export declare function AdminViewCards({ rows, view, isLoading, emptyLabel, onRowClick, selectedIdSet, onToggleSelect, renderRowActions, resourceIcon, }: AdminViewCardsProps): React.JSX.Element;
15
17
  export {};
@@ -1,12 +1,25 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Checkbox, Div, Grid, Row, Span, Stack, Text } from "../../../ui";
4
+ import { getStatusTone } from "../../../ui/columns/column-renderers";
5
+ import { MediaImage } from "../../media/MediaImage";
4
6
  const __P = {
5
7
  p3: "p-[var(--appkit-space-3)]",
6
8
  };
7
9
  const __O = {
8
10
  hidden: "overflow-hidden",
9
11
  };
12
+ const STATUS_TONE_CLASSES = {
13
+ success: "bg-success-surface text-success",
14
+ warning: "bg-warning-surface text-warning",
15
+ error: "bg-error-surface text-error",
16
+ info: "bg-info-surface text-info",
17
+ neutral: "bg-primary-50 text-primary-800 dark:bg-secondary-900/30 dark:text-secondary-300",
18
+ };
19
+ function RowAvatar({ image, alt, icon, size = "9" }) {
20
+ const dims = size === "12" ? "h-12 w-12" : "h-9 w-9";
21
+ return (_jsx(Div, { className: `relative ${dims} shrink-0 overflow-hidden`, rounded: "full", children: _jsx(MediaImage, { src: image, alt: alt, size: "avatar", fallback: icon }) }));
22
+ }
10
23
  const FLAG_BADGES = [
11
24
  { key: "featured", label: "Featured", color: "bg-warning-surface text-warning dark:bg-warning-surface dark:text-warning" },
12
25
  { key: "isPromoted", label: "Promoted", color: "bg-purple-100 text-purple-800 dark:bg-purple-900/30 dark:text-purple-300" },
@@ -14,7 +27,8 @@ const FLAG_BADGES = [
14
27
  { key: "isSold", label: "Sold", color: "bg-[var(--appkit-color-surface)] text-[var(--appkit-color-text-muted)] bg-[var(--appkit-color-surface-elevated)] text-[var(--appkit-color-text-muted)]" },
15
28
  ];
16
29
  function StatusBadge({ status }) {
17
- return (_jsx(Span, { size: "xs", weight: "medium", className: "inline-flex bg-primary-50 text-primary-800 dark:bg-secondary-900/30 dark:text-secondary-300 truncate max-w-[120px]", rounded: "full", padding: "pill-xs", children: status }));
30
+ const tone = getStatusTone(status);
31
+ return (_jsx(Span, { size: "xs", weight: "medium", className: `inline-flex truncate max-w-[120px] ${STATUS_TONE_CLASSES[tone]}`, rounded: "full", padding: "pill-xs", children: status }));
18
32
  }
19
33
  function SkeletonCard({ view }) {
20
34
  if (view === "list") {
@@ -22,7 +36,7 @@ function SkeletonCard({ view }) {
22
36
  }
23
37
  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
38
  }
25
- function AdminCardItem({ row, view, selected, onToggleSelect, onRowClick, renderRowActions, }) {
39
+ function AdminCardItem({ row, view, selected, onToggleSelect, onRowClick, renderRowActions, resourceIcon, }) {
26
40
  const flags = FLAG_BADGES.filter(({ key }) => Boolean(row[key]));
27
41
  const handleClick = (e) => {
28
42
  if (e.target.closest('[data-no-row-click]'))
@@ -33,16 +47,16 @@ function AdminCardItem({ row, view, selected, onToggleSelect, onRowClick, render
33
47
  return (_jsxs(Row, { gap: "sm", className: [
34
48
  "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
49
  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-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) }))] }));
50
+ ].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}` }) })), _jsx(RowAvatar, { image: row.image, alt: row.primary, icon: resourceIcon }), _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
51
  }
38
52
  return (_jsxs(Div, { rounded: "xl", className: [
39
53
  "border overflow-hidden cursor-pointer transition-all hover:shadow-md hover:-translate-y-0.5",
40
54
  selected
41
55
  ? "border-primary ring-1 ring-primary/20 bg-primary-50/30 dark:bg-primary-900/10"
42
56
  : "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-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) }))] })] }));
57
+ ].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(Row, { gap: "sm", align: "center", children: [_jsx(RowAvatar, { image: row.image, alt: row.primary, icon: resourceIcon, size: "12" }), _jsxs(Stack, { gap: "none", className: "min-w-0 flex-1", 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
58
  }
45
- export function AdminViewCards({ rows, view, isLoading, emptyLabel = "No items found", onRowClick, selectedIdSet, onToggleSelect, renderRowActions, }) {
59
+ export function AdminViewCards({ rows, view, isLoading, emptyLabel = "No items found", onRowClick, selectedIdSet, onToggleSelect, renderRowActions, resourceIcon, }) {
46
60
  if (isLoading) {
47
61
  const count = view === "grid" ? 12 : 8;
48
62
  if (view === "list") {
@@ -54,7 +68,7 @@ export function AdminViewCards({ rows, view, isLoading, emptyLabel = "No items f
54
68
  return (_jsx(Text, { paddingY: "3xl", size: "sm", color: "muted", align: "center", children: emptyLabel }));
55
69
  }
56
70
  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, renderRowActions: renderRowActions }, row.id))) }));
71
+ 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, resourceIcon: resourceIcon }, row.id))) }));
58
72
  }
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))) }));
73
+ 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, resourceIcon: resourceIcon }, row.id))) }));
60
74
  }
@@ -39,6 +39,8 @@ export interface AdminListingScaffoldRow {
39
39
  isOnSale?: boolean;
40
40
  isSold?: boolean;
41
41
  barcodeId?: string;
42
+ /** Row photo/thumbnail (avatar, product image, store logo, cover image, etc). Falls back to the table's resource icon when omitted. */
43
+ image?: string;
42
44
  }
43
45
  export interface ListingSortOption {
44
46
  value: string;
@@ -4,6 +4,7 @@ import { Plus } from "lucide-react";
4
4
  import { BulkActionBar, Button, Div, ListingFilterDrawer, ListingToolbar, Pagination, Row, SideDrawer, StickyToolbar } from "../../../ui";
5
5
  import { useBottomActions } from "../../layout";
6
6
  import { useAdminListing } from "../hooks/useAdminListing";
7
+ import { getResourceIcon } from "../../../ui/columns/column-renderers";
7
8
  import { AdminViewCards } from "./AdminViewCards";
8
9
  import { DataTable } from "./DataTable";
9
10
  export function DataListingView({ config, }) {
@@ -21,6 +22,7 @@ export function DataListingView({ config, }) {
21
22
  rows,
22
23
  openEditPanel: panel.openEditPanel,
23
24
  };
25
+ const resourceIcon = getResourceIcon(typeof config.queryKey[1] === "string" ? config.queryKey[1] : undefined);
24
26
  const bulkActionItems = config.buildBulkActions?.(selectionContext);
25
27
  // Mobile bulk bar
26
28
  useBottomActions(selection.selectedCount > 0 && bulkActionItems
@@ -64,7 +66,7 @@ export function DataListingView({ config, }) {
64
66
  : undefined;
65
67
  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({
66
68
  openCreatePanel: panel.openCreatePanel,
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
69
+ }), 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, resourceIcon: resourceIcon, isLoading: isLoading, emptyLabel: config.emptyLabel ?? `No ${config.title.toLowerCase()} found`, selectedIds: selection.selectedIdSet, onToggleSelect: selection.toggle, onToggleSelectAll: (next) => next
68
70
  ? selection.setSelectedIds(rows.map((r) => r.id))
69
71
  : selection.clearSelection(), rowHrefTemplate: config.rowHrefTemplate, onRowClick: config.onRowClick
70
72
  ? (row) => config.onRowClick(row, {
@@ -76,7 +78,7 @@ export function DataListingView({ config, }) {
76
78
  // The persisted view-mode preference is global, so a "table"
77
79
  // value can still reach here on a hideTableView-only view (see
78
80
  // the DataTable branch's guard above) — fall back to "grid".
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
81
+ config.renderCards(rows, view === "table" ? "grid" : view, selectionContext, isLoading)) : (_jsx(AdminViewCards, { rows: rows, view: view === "table" ? "grid" : view, resourceIcon: resourceIcon, isLoading: isLoading, emptyLabel: config.emptyLabel ?? `No ${config.title.toLowerCase()} found`, onRowClick: resolvedRowClick
80
82
  ? (row) => resolvedRowClick(row)
81
83
  : undefined, selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle, renderRowActions: config.renderRowActions
82
84
  ? (row) => config.renderRowActions(row)
@@ -28,8 +28,10 @@ interface DataTableProps<T extends {
28
28
  selectedIds?: Set<string>;
29
29
  onToggleSelect?: (id: string, selected: boolean) => void;
30
30
  onToggleSelectAll?: (nextAllSelected: boolean) => void;
31
+ /** Resource-type emoji fallback for the default "Name" column's avatar when a row has no `image` and no custom `columns` were supplied. */
32
+ resourceIcon?: string;
31
33
  }
32
34
  export declare function DataTable<T extends {
33
35
  id: string;
34
- }>({ columns: columnsProp, rows, isLoading, sortKey, sortDir, onSort, totalPages, currentPage, onPageChange, emptyLabel, rowHrefTemplate, onRowClick, renderRowActions, selectedIds, onToggleSelect, onToggleSelectAll, }: DataTableProps<T>): React.JSX.Element;
36
+ }>({ columns: columnsProp, rows, isLoading, sortKey, sortDir, onSort, totalPages, currentPage, onPageChange, emptyLabel, rowHrefTemplate, onRowClick, renderRowActions, selectedIds, onToggleSelect, onToggleSelectAll, resourceIcon, }: DataTableProps<T>): React.JSX.Element;
35
37
  export {};