@mohasinac/appkit 3.9.0 → 4.0.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 (86) hide show
  1. package/dist/_internal/shared/actions/action-registry.js +8 -0
  2. package/dist/client.d.ts +2 -2
  3. package/dist/client.js +1 -4
  4. package/dist/constants/api-endpoints.d.ts +3 -0
  5. package/dist/constants/api-endpoints.js +1 -0
  6. package/dist/features/account/hooks/useDataViewMode.d.ts +17 -0
  7. package/dist/features/account/hooks/useDataViewMode.js +55 -0
  8. package/dist/features/account/hooks/useProfile.d.ts +2 -0
  9. package/dist/features/admin/components/AdminBundlesView.d.ts +3 -4
  10. package/dist/features/admin/components/AdminBundlesView.js +2 -2
  11. package/dist/features/admin/components/AdminCarouselView.js +1 -1
  12. package/dist/features/admin/components/AdminCategoriesView.d.ts +2 -6
  13. package/dist/features/admin/components/AdminCategoriesView.js +1 -1
  14. package/dist/features/admin/components/AdminFaqsView.d.ts +0 -2
  15. package/dist/features/admin/components/AdminPrizeDrawsView.js +1 -1
  16. package/dist/features/admin/components/AdminSectionsView.js +4 -4
  17. package/dist/features/admin/components/DataListingView.d.ts +8 -2
  18. package/dist/features/admin/components/DataListingView.js +7 -3
  19. package/dist/features/admin/components/DataTable.d.ts +10 -2
  20. package/dist/features/admin/components/DataTable.js +4 -2
  21. package/dist/features/admin/components/sections/adminSectionsBuildParse.js +13 -5
  22. package/dist/features/admin/components/sections/adminSectionsTypes.d.ts +4 -0
  23. package/dist/features/admin/components/sections/adminSectionsTypes.js +9 -5
  24. package/dist/features/admin/hooks/useAdminListing.d.ts +2 -2
  25. package/dist/features/admin/hooks/useAdminListing.js +6 -1
  26. package/dist/features/categories/components/BrandDetailTabs.js +2 -12
  27. package/dist/features/categories/components/CategoryDetailTabs.js +2 -12
  28. package/dist/features/events/components/AdminEventsView.d.ts +1 -5
  29. package/dist/features/faq/components/FAQAccordion.js +3 -2
  30. package/dist/features/faq/components/RelatedFAQs.js +1 -1
  31. package/dist/features/homepage/components/BrandsSection.d.ts +4 -1
  32. package/dist/features/homepage/components/BrandsSection.js +2 -2
  33. package/dist/features/homepage/components/CustomCardsSection.js +3 -3
  34. package/dist/features/homepage/components/CustomerReviewsSection.d.ts +4 -1
  35. package/dist/features/homepage/components/CustomerReviewsSection.js +2 -2
  36. package/dist/features/homepage/components/EventsSection.d.ts +4 -1
  37. package/dist/features/homepage/components/EventsSection.js +2 -2
  38. package/dist/features/homepage/components/FAQSection.js +3 -3
  39. package/dist/features/homepage/components/FeaturedAuctionsSection.d.ts +2 -1
  40. package/dist/features/homepage/components/FeaturedAuctionsSection.js +2 -2
  41. package/dist/features/homepage/components/FeaturedPreOrdersSection.d.ts +2 -1
  42. package/dist/features/homepage/components/FeaturedPreOrdersSection.js +2 -2
  43. package/dist/features/homepage/components/FeaturedProductsSection.d.ts +2 -1
  44. package/dist/features/homepage/components/FeaturedProductsSection.js +2 -2
  45. package/dist/features/homepage/components/FeaturedStoresSection.d.ts +4 -1
  46. package/dist/features/homepage/components/FeaturedStoresSection.js +2 -2
  47. package/dist/features/homepage/components/HomepageCustomerReviewsSection.d.ts +4 -1
  48. package/dist/features/homepage/components/HomepageCustomerReviewsSection.js +2 -2
  49. package/dist/features/homepage/components/SectionCarousel.d.ts +3 -1
  50. package/dist/features/homepage/components/SectionCarousel.js +2 -2
  51. package/dist/features/homepage/components/ShopByCategorySection.d.ts +4 -1
  52. package/dist/features/homepage/components/ShopByCategorySection.js +2 -2
  53. package/dist/features/homepage/lib/section-renderer.js +9 -9
  54. package/dist/features/homepage/schemas/firestore.d.ts +8 -0
  55. package/dist/features/layout/FooterLayout.js +2 -2
  56. package/dist/features/lottery/schemas/zod.d.ts +4 -4
  57. package/dist/features/payments/schemas/firestore.d.ts +6 -0
  58. package/dist/features/payments/schemas/firestore.js +2 -0
  59. package/dist/features/seller/components/SellerBundlesView.d.ts +3 -4
  60. package/dist/features/seller/components/SellerBundlesView.js +2 -2
  61. package/dist/features/seller/components/SellerPayoutsView.d.ts +2 -5
  62. package/dist/features/seller/components/SellerPayoutsView.js +100 -21
  63. package/dist/features/seller/components/SellerPreOrdersView.js +1 -1
  64. package/dist/features/seller/components/SellerPrizeDrawsView.js +1 -1
  65. package/dist/features/seller/components/SellerProductsView.js +6 -2
  66. package/dist/features/shipments/components/AdminShipmentsView.d.ts +1 -5
  67. package/dist/index.d.ts +3 -5
  68. package/dist/index.js +3 -3
  69. package/dist/react/index.d.ts +0 -2
  70. package/dist/react/index.js +0 -2
  71. package/dist/seed/faq-seed-data.js +11 -11
  72. package/dist/seed/homepage-sections-seed-data.js +11 -1
  73. package/dist/styles.css +30 -99
  74. package/dist/tailwind-utilities.css +1 -1
  75. package/dist/ui/DataTable.js +1 -1
  76. package/dist/ui/DataTable.style.css +10 -0
  77. package/dist/ui/components/DetailPageTabs.d.ts +1 -1
  78. package/dist/ui/components/DetailPageTabs.js +6 -30
  79. package/dist/ui/components/HorizontalScroller.js +3 -0
  80. package/dist/ui/components/Tabs.d.ts +9 -1
  81. package/dist/ui/components/Tabs.js +13 -8
  82. package/dist/ui/components/Tabs.style.css +19 -0
  83. package/dist/ui/components/index.style.css +0 -1
  84. package/dist/ui/index.d.ts +0 -2
  85. package/dist/ui/index.js +0 -1
  86. package/package.json +1 -1
@@ -53,7 +53,7 @@ function renderSectionElement(section, newsletterFormSlot, faqItems, slides, liv
53
53
  }
54
54
  case "categories": {
55
55
  const cfg = config;
56
- return (_jsx(ShopByCategorySection, { title: cleanTitle(cfg?.title) || "Shop by Category", viewMoreHref: ROUTES.PUBLIC.CATEGORIES, viewMoreLabel: "All categories \u2192", initialItems: sectionData.categories, cta: cfg?.cta, filters: cfg?.filters }));
56
+ return (_jsx(ShopByCategorySection, { title: cleanTitle(cfg?.title) || "Shop by Category", viewMoreHref: ROUTES.PUBLIC.CATEGORIES, viewMoreLabel: "All categories \u2192", initialItems: sectionData.categories, cta: cfg?.cta, filters: cfg?.filters, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval, loop: cfg?.loop }));
57
57
  }
58
58
  case "stats": {
59
59
  const cfg = config;
@@ -84,27 +84,27 @@ function renderSectionElement(section, newsletterFormSlot, faqItems, slides, liv
84
84
  }
85
85
  case "products": {
86
86
  const cfg = config;
87
- return (_jsx(FeaturedProductsSection, { title: cleanTitle(cfg?.title) || "Featured Products", viewMoreHref: ROUTES.PUBLIC.PRODUCTS, viewMoreLabel: "View all products \u2192", filterByBrand: cfg?.filterByBrand, initialItems: sectionData.products, rows: cfg?.rows, maxItems: cfg?.maxItems, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval }));
87
+ return (_jsx(FeaturedProductsSection, { title: cleanTitle(cfg?.title) || "Featured Products", viewMoreHref: ROUTES.PUBLIC.PRODUCTS, viewMoreLabel: "View all products \u2192", filterByBrand: cfg?.filterByBrand, initialItems: sectionData.products, rows: cfg?.rows, maxItems: cfg?.maxItems, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval, loop: cfg?.loop }));
88
88
  }
89
89
  case "auctions": {
90
90
  const cfg = config;
91
- return (_jsx(FeaturedAuctionsSection, { title: cleanTitle(cfg?.title) || "Live Auctions", viewMoreHref: ROUTES.PUBLIC.AUCTIONS, viewMoreLabel: "View all auctions \u2192", filterByBrand: cfg?.filterByBrand, initialItems: sectionData.auctions, rows: cfg?.rows, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval }));
91
+ return (_jsx(FeaturedAuctionsSection, { title: cleanTitle(cfg?.title) || "Live Auctions", viewMoreHref: ROUTES.PUBLIC.AUCTIONS, viewMoreLabel: "View all auctions \u2192", filterByBrand: cfg?.filterByBrand, initialItems: sectionData.auctions, rows: cfg?.rows, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval, loop: cfg?.loop }));
92
92
  }
93
93
  case "pre-orders": {
94
94
  const cfg = config;
95
- return (_jsx(FeaturedPreOrdersSection, { title: cleanTitle(cfg?.title) || "Reserve Before It Ships", viewMoreHref: ROUTES.PUBLIC.PRE_ORDERS, viewMoreLabel: "View all pre-orders \u2192", filterByBrand: cfg?.filterByBrand, initialItems: sectionData.preOrders, rows: cfg?.rows, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval }));
95
+ return (_jsx(FeaturedPreOrdersSection, { title: cleanTitle(cfg?.title) || "Reserve Before It Ships", viewMoreHref: ROUTES.PUBLIC.PRE_ORDERS, viewMoreLabel: "View all pre-orders \u2192", filterByBrand: cfg?.filterByBrand, initialItems: sectionData.preOrders, rows: cfg?.rows, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval, loop: cfg?.loop }));
96
96
  }
97
97
  case "stores": {
98
98
  const cfg = config;
99
- return (_jsx(FeaturedStoresSection, { title: cleanTitle(cfg?.title) || "Featured Stores", viewMoreHref: ROUTES.PUBLIC.STORES, viewMoreLabel: "View all stores \u2192", initialItems: sectionData.stores }));
99
+ return (_jsx(FeaturedStoresSection, { title: cleanTitle(cfg?.title) || "Featured Stores", viewMoreHref: ROUTES.PUBLIC.STORES, viewMoreLabel: "View all stores \u2192", initialItems: sectionData.stores, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval, loop: cfg?.loop }));
100
100
  }
101
101
  case "events": {
102
102
  const cfg = config;
103
- return (_jsx(EventsSection, { title: cleanTitle(cfg?.title) || "Events & Offers", viewMoreHref: ROUTES.PUBLIC.EVENTS, viewMoreLabel: "View all events \u2192", initialItems: sectionData.events }));
103
+ return (_jsx(EventsSection, { title: cleanTitle(cfg?.title) || "Events & Offers", viewMoreHref: ROUTES.PUBLIC.EVENTS, viewMoreLabel: "View all events \u2192", initialItems: sectionData.events, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval, loop: cfg?.loop }));
104
104
  }
105
105
  case "reviews": {
106
106
  const cfg = config;
107
- return (_jsx(HomepageCustomerReviewsSection, { title: cleanTitle(cfg?.title) || "What Our Customers Say", viewMoreHref: ROUTES.PUBLIC.REVIEWS, viewMoreLabel: "See all reviews \u2192" }));
107
+ return (_jsx(HomepageCustomerReviewsSection, { title: cleanTitle(cfg?.title) || "What Our Customers Say", viewMoreHref: ROUTES.PUBLIC.REVIEWS, viewMoreLabel: "See all reviews \u2192", autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval, loop: cfg?.loop }));
108
108
  }
109
109
  case "banner": {
110
110
  const cfg = config;
@@ -156,7 +156,7 @@ function renderSectionElement(section, newsletterFormSlot, faqItems, slides, liv
156
156
  }
157
157
  case "brands": {
158
158
  const cfg = config;
159
- return (_jsx(BrandsSection, { title: cleanTitle(cfg?.title) || "Top Brands", subtitle: cfg?.subtitle, limit: cfg?.maxBrands || 12, viewMoreHref: ROUTES.PUBLIC.CATEGORIES, viewMoreLabel: "All brands \u2192", initialItems: sectionData.brands, cta: cfg?.cta, filters: cfg?.filters }));
159
+ return (_jsx(BrandsSection, { title: cleanTitle(cfg?.title) || "Top Brands", subtitle: cfg?.subtitle, limit: cfg?.maxBrands || 12, viewMoreHref: ROUTES.PUBLIC.CATEGORIES, viewMoreLabel: "All brands \u2192", initialItems: sectionData.brands, cta: cfg?.cta, filters: cfg?.filters, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval, loop: cfg?.loop }));
160
160
  }
161
161
  case "social-feed": {
162
162
  const cfg = config;
@@ -169,7 +169,7 @@ function renderSectionElement(section, newsletterFormSlot, faqItems, slides, liv
169
169
  const cfg = config;
170
170
  if (!cfg?.cards?.length)
171
171
  return null;
172
- return (_jsx(CustomCardsSection, { title: cleanTitle(cfg.title), layout: cfg.layout ?? "grid", columns: cfg.columns ?? 3, cards: cfg.cards, autoScroll: cfg.autoScroll, scrollIntervalMs: cfg.scrollIntervalMs }));
172
+ return (_jsx(CustomCardsSection, { title: cleanTitle(cfg.title), layout: cfg.layout ?? "grid", columns: cfg.columns ?? 3, cards: cfg.cards, autoScroll: cfg.autoScroll, scrollIntervalMs: cfg.scrollIntervalMs, loop: cfg.loop }));
173
173
  }
174
174
  case "google-reviews": {
175
175
  const cfg = config;
@@ -196,6 +196,8 @@ export interface CategoriesSectionConfig {
196
196
  maxCategories: 4;
197
197
  autoScroll: boolean;
198
198
  scrollInterval: number;
199
+ /** Circular auto-rotate at the carousel edges. Default: true. */
200
+ loop?: boolean;
199
201
  /** Optional CTA button rendered below the scroller. */
200
202
  cta?: SectionCTA;
201
203
  /** Optional client-side filter chips above the scroller. */
@@ -213,6 +215,8 @@ export interface BrandsSectionConfig {
213
215
  maxBrands: number;
214
216
  autoScroll: boolean;
215
217
  scrollInterval: number;
218
+ /** Circular auto-rotate at the carousel edges. Default: true. */
219
+ loop?: boolean;
216
220
  /** Optional CTA button rendered below the scroller. */
217
221
  cta?: SectionCTA;
218
222
  /** Optional client-side filter chips above the scroller. */
@@ -306,6 +310,8 @@ export interface ReviewsSectionConfig {
306
310
  mobileItemsPerView: 1;
307
311
  autoScroll: boolean;
308
312
  scrollInterval: number;
313
+ /** Circular auto-rotate at the carousel edges. Default: true. */
314
+ loop?: boolean;
309
315
  source?: "platform" | "google";
310
316
  placeId?: string;
311
317
  }
@@ -496,6 +502,8 @@ export interface CustomCardsSectionConfig {
496
502
  cards: CustomCardsCard[];
497
503
  autoScroll?: boolean;
498
504
  scrollIntervalMs?: number;
505
+ /** Circular auto-rotate at the carousel edges. Default: true. */
506
+ loop?: boolean;
499
507
  }
500
508
  export type CollectionCardType = "products" | "auctions" | "pre-orders" | "stores" | "events" | "blog-posts" | "reviews" | "brands" | "categories";
501
509
  export interface CollectionCardsEntry {
@@ -8,7 +8,7 @@ export function FooterLayout({ brandName, brandDescription, socialLinks, linkGro
8
8
  const [openGroups, setOpenGroups] = useState({});
9
9
  const toggleGroup = (idx) => setOpenGroups((prev) => ({ ...prev, [idx]: !prev[idx] }));
10
10
  const visibleTrustItems = trustBarItems.filter((item) => item.visible !== false);
11
- return (_jsxs(BlockFooter, { id: id, className: "bg-zinc-50 bg-[var(--appkit-color-bg)] border-t border-[var(--appkit-color-border-subtle)]", children: [showTrustBar && visibleTrustItems.length > 0 && (_jsx(Div, { border: "subtle", className: "border-b", padding: "y-xl", children: _jsx(Div, { paddingX: "x-page", className: "container mx-auto max-w-[1920px]", children: _jsx(Row, { as: "ul", wrap: true, justify: "center", gap: "lg", className: "lg:gap-[var(--appkit-space-10)]", children: visibleTrustItems.map((item, i) => (_jsx(Li, { children: _jsxs(Row, { textSize: "sm", gap: "sm", className: "min-w-[160px]", children: [_jsx(Span, { className: "flex-shrink-0 text-primary-600 dark:text-secondary-400 w-5 h-5", children: item.icon }), _jsxs(Span, { children: [_jsx(Span, { size: "sm", weight: "bold", className: "block", color: "primary", children: item.label }), item.subtitle && (_jsx(Span, { size: "xs", className: "block", color: "muted", children: item.subtitle }))] })] }) }, item.id ?? String(i)))) }) }) })), _jsxs(Div, { paddingX: "x-page", className: "container mx-auto max-w-[1920px] lg:py-[var(--appkit-space-14)]", padding: "y-2xl", children: [_jsxs(Div, { className: "grid grid-cols-1 lg:grid-cols-5 gap-[var(--appkit-space-10)] lg:gap-[var(--appkit-space-16)]", children: [_jsxs(Stack, { className: "lg:col-span-2", gap: "md", children: [_jsx(Heading, { level: 5, size: "xl", weight: "bold", color: "primary", children: brandName }), _jsx(Text, { className: "leading-relaxed max-w-sm", color: "muted", size: "sm", children: brandDescription }), socialLinks.length > 0 && (_jsx(Row, { as: Ul, gap: "sm", children: socialLinks.map((link) => (_jsx(Li, { children: _jsx(Link, { href: link.href, "aria-label": link.ariaLabel, target: "_blank", rel: "noopener noreferrer", className: "flex items-center justify-center w-9 h-9 rounded-full border border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)] hover:text-primary dark:hover:text-secondary hover:border-primary/40 dark:hover:border-secondary/40 transition-colors", children: link.icon }) }, link.platform))) })), newsletterEnabled && newsletterSlot && (_jsx(Div, { padding: "t-xs", children: newsletterSlot }))] }), _jsx(Div, { className: `lg:col-span-3 grid grid-cols-1 gap-[var(--appkit-space-0)] lg:gap-[var(--appkit-space-8)] ${linkGroups.length <= 3 ? "lg:grid-cols-3" :
11
+ return (_jsxs(BlockFooter, { id: id, className: "bg-[var(--appkit-color-bg)] border-t border-[var(--appkit-color-border-subtle)]", children: [showTrustBar && visibleTrustItems.length > 0 && (_jsx(Div, { border: "subtle", className: "border-b", padding: "y-xl", children: _jsx(Div, { paddingX: "x-page", className: "container mx-auto max-w-[1920px]", children: _jsx(Row, { as: "ul", wrap: true, justify: "center", gap: "lg", className: "lg:gap-[var(--appkit-space-10)]", children: visibleTrustItems.map((item, i) => (_jsx(Li, { children: _jsxs(Row, { textSize: "sm", gap: "sm", className: "min-w-[160px]", children: [_jsx(Span, { className: "flex-shrink-0 text-primary-600 dark:text-secondary-400 w-5 h-5", children: item.icon }), _jsxs(Span, { children: [_jsx(Span, { size: "sm", weight: "bold", className: "block", color: "primary", children: item.label }), item.subtitle && (_jsx(Span, { size: "xs", className: "block", color: "muted", children: item.subtitle }))] })] }) }, item.id ?? String(i)))) }) }) })), _jsxs(Div, { paddingX: "x-page", className: "container mx-auto max-w-[1920px] lg:py-[var(--appkit-space-14)]", padding: "y-2xl", children: [_jsxs(Div, { className: "grid grid-cols-1 lg:grid-cols-5 gap-[var(--appkit-space-10)] lg:gap-[var(--appkit-space-16)]", children: [_jsxs(Stack, { className: "lg:col-span-2", gap: "md", children: [_jsx(Heading, { level: 5, size: "xl", weight: "bold", color: "primary", children: brandName }), _jsx(Text, { className: "leading-relaxed max-w-sm", color: "muted", size: "sm", children: brandDescription }), socialLinks.length > 0 && (_jsx(Row, { as: Ul, gap: "sm", children: socialLinks.map((link) => (_jsx(Li, { children: _jsx(Link, { href: link.href, "aria-label": link.ariaLabel, target: "_blank", rel: "noopener noreferrer", className: "flex items-center justify-center w-9 h-9 rounded-full border border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)] hover:text-primary dark:hover:text-secondary hover:border-primary/40 dark:hover:border-secondary/40 transition-colors", children: link.icon }) }, link.platform))) })), newsletterEnabled && newsletterSlot && (_jsx(Div, { padding: "t-xs", children: newsletterSlot }))] }), _jsx(Div, { className: `lg:col-span-3 grid grid-cols-1 gap-[var(--appkit-space-0)] lg:gap-[var(--appkit-space-8)] ${linkGroups.length <= 3 ? "lg:grid-cols-3" :
12
12
  linkGroups.length === 4 ? "lg:grid-cols-4" :
13
- "lg:grid-cols-5"}`, children: linkGroups.map((group, idx) => (_jsxs(Div, { children: [_jsxs(Button, { type: "button", variant: "ghost", onClick: () => toggleGroup(idx), className: "w-full justify-between border-b border-zinc-200 py-[var(--appkit-space-3)] text-left text-[length:var(--appkit-text-sm)] font-semibold text-zinc-800 transition-colors hover:text-zinc-950 border-[var(--appkit-color-border-subtle)] text-[var(--appkit-color-text)] dark:hover:text-white lg:hidden", "aria-expanded": !!openGroups[idx], children: [group.heading, _jsx(ChevronDown, { className: `w-4 h-4 transition-transform duration-200 ${openGroups[idx] ? "rotate-180" : ""}` })] }), _jsx(Ul, { className: `lg:hidden overflow-hidden transition-all duration-200 ${openGroups[idx] ? "max-h-96 py-[var(--appkit-space-3)]" : "max-h-0"} space-y-2.5`, children: group.links.map((link) => (_jsx(Li, { children: _jsx(Link, { href: link.href, className: "text-[length:var(--appkit-text-sm)] text-[var(--appkit-color-text-muted)] hover:text-primary dark:hover:text-secondary transition-colors", children: link.label }) }, link.href))) }), _jsxs(Div, { className: "hidden lg:block", children: [_jsx(Text, { className: "tracking-wider mb-3", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: group.heading }), _jsx(Ul, { className: "space-y-2.5", children: group.links.map((link) => (_jsx(Li, { children: _jsx(Link, { href: link.href, className: "text-[length:var(--appkit-text-sm)] text-[var(--appkit-color-text-muted)] hover:text-primary dark:hover:text-secondary transition-colors", children: link.label }) }, link.href))) })] })] }, idx))) })] }), _jsxs(Stack, { direction: "sm-row", color: "muted", textSize: "xs", justify: "between", border: "default", className: "mt-10 border-t border-[var(--appkit-color-border-subtle)] text-[var(--appkit-color-text-muted)]", padding: "t-lg", align: "center", gap: "3", children: [_jsx(Text, { size: "xs", color: "muted", children: copyrightText }), bottomLinks.length > 0 && (_jsx(Nav, { "aria-label": "Site utilities", children: _jsx(Ul, { className: "flex flex-wrap items-center gap-x-4 gap-y-1 justify-center", children: bottomLinks.map((link) => (_jsx(Li, { children: _jsx(Link, { href: link.href, className: "text-[length:var(--appkit-text-xs)] text-[var(--appkit-color-text-muted)] hover:text-primary dark:hover:text-secondary transition-colors underline-offset-2 hover:underline", children: link.label }) }, link.href))) }) })), madeInText && (_jsx(Text, { size: "xs", color: "muted", children: madeInText }))] })] })] }));
13
+ "lg:grid-cols-5"}`, children: linkGroups.map((group, idx) => (_jsxs(Div, { children: [_jsxs(Button, { type: "button", variant: "ghost", onClick: () => toggleGroup(idx), className: "w-full justify-between border-b py-[var(--appkit-space-3)] text-left text-[length:var(--appkit-text-sm)] font-semibold transition-colors border-[var(--appkit-color-border-subtle)] text-[var(--appkit-color-text)] hover:text-primary dark:hover:text-secondary lg:hidden", "aria-expanded": !!openGroups[idx], children: [group.heading, _jsx(ChevronDown, { className: `w-4 h-4 transition-transform duration-200 ${openGroups[idx] ? "rotate-180" : ""}` })] }), _jsx(Ul, { className: `lg:hidden overflow-hidden transition-all duration-200 ${openGroups[idx] ? "max-h-96 py-[var(--appkit-space-3)]" : "max-h-0"} space-y-2.5`, children: group.links.map((link) => (_jsx(Li, { children: _jsx(Link, { href: link.href, className: "text-[length:var(--appkit-text-sm)] text-[var(--appkit-color-text-muted)] hover:text-primary dark:hover:text-secondary transition-colors", children: link.label }) }, link.href))) }), _jsxs(Div, { className: "hidden lg:block", children: [_jsx(Text, { className: "tracking-wider mb-3", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: group.heading }), _jsx(Ul, { className: "space-y-2.5", children: group.links.map((link) => (_jsx(Li, { children: _jsx(Link, { href: link.href, className: "text-[length:var(--appkit-text-sm)] text-[var(--appkit-color-text-muted)] hover:text-primary dark:hover:text-secondary transition-colors", children: link.label }) }, link.href))) })] })] }, idx))) })] }), _jsxs(Stack, { direction: "sm-row", color: "muted", textSize: "xs", justify: "between", border: "default", className: "mt-10 border-t border-[var(--appkit-color-border-subtle)] text-[var(--appkit-color-text-muted)]", padding: "t-lg", align: "center", gap: "3", children: [_jsx(Text, { size: "xs", color: "muted", children: copyrightText }), bottomLinks.length > 0 && (_jsx(Nav, { "aria-label": "Site utilities", children: _jsx(Ul, { className: "flex flex-wrap items-center gap-x-4 gap-y-1 justify-center", children: bottomLinks.map((link) => (_jsx(Li, { children: _jsx(Link, { href: link.href, className: "text-[length:var(--appkit-text-xs)] text-[var(--appkit-color-text-muted)] hover:text-primary dark:hover:text-secondary transition-colors underline-offset-2 hover:underline", children: link.label }) }, link.href))) }) })), madeInText && (_jsx(Text, { size: "xs", color: "muted", children: madeInText }))] })] })] }));
14
14
  }
@@ -66,8 +66,8 @@ export declare const submitLotteryPullSchema: z.ZodEffects<z.ZodObject<{
66
66
  purchasedItemNumber: z.ZodNumber;
67
67
  userPhone: z.ZodString;
68
68
  }, "strip", z.ZodTypeAny, {
69
- userId: string;
70
69
  transactionId: string;
70
+ userId: string;
71
71
  userPhone: string;
72
72
  sourceType: "product" | "event";
73
73
  paymentTime: string;
@@ -77,8 +77,8 @@ export declare const submitLotteryPullSchema: z.ZodEffects<z.ZodObject<{
77
77
  userDisplayName?: string | undefined;
78
78
  eventId?: string | undefined;
79
79
  }, {
80
- userId: string;
81
80
  transactionId: string;
81
+ userId: string;
82
82
  userPhone: string;
83
83
  sourceType: "product" | "event";
84
84
  paymentTime: string;
@@ -88,8 +88,8 @@ export declare const submitLotteryPullSchema: z.ZodEffects<z.ZodObject<{
88
88
  userDisplayName?: string | undefined;
89
89
  eventId?: string | undefined;
90
90
  }>, {
91
- userId: string;
92
91
  transactionId: string;
92
+ userId: string;
93
93
  userPhone: string;
94
94
  sourceType: "product" | "event";
95
95
  paymentTime: string;
@@ -99,8 +99,8 @@ export declare const submitLotteryPullSchema: z.ZodEffects<z.ZodObject<{
99
99
  userDisplayName?: string | undefined;
100
100
  eventId?: string | undefined;
101
101
  }, {
102
- userId: string;
103
102
  transactionId: string;
103
+ userId: string;
104
104
  userPhone: string;
105
105
  sourceType: "product" | "event";
106
106
  paymentTime: string;
@@ -66,6 +66,10 @@ export interface PayoutDocument extends BaseDocument {
66
66
  netAmount?: number;
67
67
  requestedAt: Date;
68
68
  processedAt?: Date;
69
+ /** UTR / UPI ref / bank transfer ID entered by admin when marking paid. */
70
+ transactionId?: string;
71
+ /** Seller-set personal follow-up flag — surfaced only to the owning seller, never mutated by admin. */
72
+ sellerReminderFlag?: boolean;
69
73
  }
70
74
  export declare const PAYOUT_COLLECTION: "payouts";
71
75
  export declare const PAYOUT_INDEXED_FIELDS: readonly ["storeId", "status", "requestedAt", "createdAt"];
@@ -88,6 +92,8 @@ export declare const PAYOUT_FIELDS: {
88
92
  };
89
93
  export declare const PAYOUT_PUBLIC_FIELDS: readonly ["id", "storeId", "amount", "currency", "status", "paymentMethod", "requestedAt", "processedAt", "createdAt"];
90
94
  export declare const PAYOUT_ADMIN_UPDATEABLE_FIELDS: readonly ["status", "adminNote", "processedAt"];
95
+ /** The only field a seller may write on their own payout doc. */
96
+ export declare const PAYOUT_SELLER_UPDATEABLE_FIELDS: readonly ["sellerReminderFlag"];
91
97
  export type PayoutCreateInput = Omit<PayoutDocument, "id" | "createdAt" | "updatedAt" | "status" | "requestedAt">;
92
98
  export type PayoutUpdateInput = Partial<Pick<PayoutDocument, (typeof PAYOUT_ADMIN_UPDATEABLE_FIELDS)[number]>>;
93
99
  export declare const payoutQueryHelpers: {
@@ -52,6 +52,8 @@ export const PAYOUT_ADMIN_UPDATEABLE_FIELDS = [
52
52
  "adminNote",
53
53
  "processedAt",
54
54
  ];
55
+ /** The only field a seller may write on their own payout doc. */
56
+ export const PAYOUT_SELLER_UPDATEABLE_FIELDS = ["sellerReminderFlag"];
55
57
  export const payoutQueryHelpers = {
56
58
  byStore: (storeId) => ["storeId", "==", storeId],
57
59
  byStatus: (status) => ["status", "==", status],
@@ -1,8 +1,7 @@
1
1
  import React from "react";
2
2
  export interface SellerBundlesViewProps {
3
- getEditHref: (row: {
4
- id: string;
5
- }) => string;
3
+ /** Plain string with an `{id}` placeholder — safe to build in a Server Component page.tsx. */
4
+ editHrefTemplate: string;
6
5
  newHref: string;
7
6
  }
8
- export declare function SellerBundlesView({ getEditHref, newHref }: SellerBundlesViewProps): React.JSX.Element;
7
+ export declare function SellerBundlesView({ editHrefTemplate, newHref }: SellerBundlesViewProps): React.JSX.Element;
@@ -37,7 +37,7 @@ const COLUMNS = [
37
37
  },
38
38
  { key: "updatedAt", header: "Updated", className: "w-28" },
39
39
  ];
40
- export function SellerBundlesView({ getEditHref, newHref }) {
40
+ export function SellerBundlesView({ editHrefTemplate, newHref }) {
41
41
  const config = {
42
42
  portal: "seller",
43
43
  title: "Bundles",
@@ -78,7 +78,7 @@ export function SellerBundlesView({ getEditHref, newHref }) {
78
78
  parts.push(sieveFilter("bundleStockStatus", SIEVE_OP.EQ, filterState.bundleStockStatus));
79
79
  return parts.join(",") || undefined;
80
80
  },
81
- getRowHref: getEditHref,
81
+ rowHrefTemplate: editHrefTemplate,
82
82
  toolbarExtra: (_jsx(Button, { asChild: true, size: "sm", variant: "primary", children: _jsx(TextLink, { href: newHref, layout: "flex", align: "center", gap: "xs", children: "+ New Bundle" }) })),
83
83
  // Rule #7: bulk-action array sourced from the SELLER_BULK_ACTIONS preset.
84
84
  buildBulkActions: (selection) => {
@@ -1,7 +1,4 @@
1
1
  import React from "react";
2
2
  import type { ListingLayoutProps } from "../../../ui";
3
- export interface SellerPayoutsViewProps extends ListingLayoutProps {
4
- onViewClick?: (id: string) => void;
5
- onExportClick?: (id: string) => void;
6
- }
7
- export declare function SellerPayoutsView({ children, onViewClick, onExportClick, ...props }: SellerPayoutsViewProps): React.JSX.Element;
3
+ export type SellerPayoutsViewProps = ListingLayoutProps;
4
+ export declare function SellerPayoutsView({ children, ...props }: SellerPayoutsViewProps): React.JSX.Element;
@@ -1,18 +1,77 @@
1
1
  "use client";
2
- import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { normalizeError } from "../../../errors/normalize";
3
4
  import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit";
4
5
  import { sortBy } from "@mohasinac/appkit";
5
- import React from "react";
6
- import { FilterChipGroup, ListingLayout, RowActionMenu } from "../../../ui";
6
+ import React, { useState } from "react";
7
+ import { Badge, Div, FilterChipGroup, ListingLayout, Row, RowActionMenu, SideDrawer, Span, Stack, Text, Toggle, useToast } from "../../../ui";
7
8
  import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
8
9
  import { ADMIN_PAYOUT_STATUS_TABS } from "../../admin/constants/filter-tabs";
9
10
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
11
+ import { buildBulkAction } from "../../../_internal/shared/actions/bulk-helpers";
12
+ import { apiClient } from "../../../http";
10
13
  import { toRecordArray, toRelativeDate, toCurrency, toStringValue, } from "../../admin/hooks/useAdminListingData";
11
14
  import { DataListingView } from "../../admin/components/DataListingView";
12
- export function SellerPayoutsView({ children, onViewClick, onExportClick, ...props }) {
15
+ const PAYOUT_STAGES = ["pending", "processing", "paid"];
16
+ const PAYOUT_CYCLE_DAYS = 7;
17
+ function formatDate(value) {
18
+ if (!value)
19
+ return "—";
20
+ const d = new Date(value);
21
+ return Number.isNaN(d.getTime()) ? "—" : d.toLocaleDateString("en-IN", { day: "numeric", month: "short", year: "numeric" });
22
+ }
23
+ function StatusProgress({ status }) {
24
+ const normalized = status.toLowerCase();
25
+ if (normalized === "failed") {
26
+ return _jsx(Badge, { variant: "danger", children: "Failed" });
27
+ }
28
+ const currentIndex = PAYOUT_STAGES.indexOf(normalized);
29
+ return (_jsx(Row, { gap: "xs", align: "center", children: PAYOUT_STAGES.map((stage, i) => (_jsxs(React.Fragment, { children: [i > 0 && _jsx(Div, { className: `h-0.5 w-6 ${i <= currentIndex ? "bg-primary" : "bg-[var(--appkit-color-border)]"}` }), _jsx(Span, { size: "xs", weight: i === currentIndex ? "bold" : "medium", className: i <= currentIndex ? "text-primary" : "text-[var(--appkit-color-text-muted)]", children: stage[0].toUpperCase() + stage.slice(1) })] }, stage))) }));
30
+ }
31
+ export function SellerPayoutsView({ children, ...props }) {
32
+ const { showToast } = useToast();
33
+ const [selectedPayout, setSelectedPayout] = useState(null);
34
+ const [reminderPending, setReminderPending] = useState(false);
35
+ // Mirrors the raw API record per row id so the detail panel can open
36
+ // instantly from data already in memory (list already fetched it) —
37
+ // matches AdminProductsView's rawByIdRef pattern.
38
+ const rawByIdRef = React.useRef({});
13
39
  if (React.Children.count(children) > 0) {
14
40
  return (_jsx(ListingLayout, { portal: "seller", ...props, children: children }));
15
41
  }
42
+ const handleExport = (rows) => {
43
+ const header = ["id", "amount", "currency", "status", "requestedAt", "processedAt", "transactionId"];
44
+ const lines = [header.join(",")];
45
+ for (const p of rows) {
46
+ lines.push(header.map((k) => JSON.stringify(p[k] ?? "")).join(","));
47
+ }
48
+ const blob = new Blob([lines.join("\n")], { type: "text/csv" });
49
+ const url = URL.createObjectURL(blob);
50
+ const a = document.createElement("a");
51
+ a.href = url;
52
+ a.download = `payouts-${new Date().toISOString().slice(0, 10)}.csv`;
53
+ a.click();
54
+ URL.revokeObjectURL(url);
55
+ };
56
+ const handleToggleReminder = async (next) => {
57
+ if (!selectedPayout)
58
+ return;
59
+ setReminderPending(true);
60
+ try {
61
+ await apiClient.patch(SELLER_ENDPOINTS.PAYOUT_BY_ID(String(selectedPayout.id)), {
62
+ sellerReminderFlag: next,
63
+ });
64
+ setSelectedPayout((prev) => (prev ? { ...prev, sellerReminderFlag: next } : prev));
65
+ showToast(next ? "Reminder set." : "Reminder cleared.", "success");
66
+ }
67
+ catch (err) {
68
+ void normalizeError(err);
69
+ showToast("Failed to update reminder.", "error");
70
+ }
71
+ finally {
72
+ setReminderPending(false);
73
+ }
74
+ };
16
75
  const config = {
17
76
  portal: "seller",
18
77
  title: "Payouts",
@@ -26,29 +85,49 @@ export function SellerPayoutsView({ children, onViewClick, onExportClick, ...pro
26
85
  { value: sortBy("createdAt", "DESC"), label: "Newest" },
27
86
  { value: sortBy("createdAt", "ASC"), label: "Oldest" },
28
87
  ],
29
- mapRows: (response) => toRecordArray(response.payouts).map((item, index) => ({
30
- id: toStringValue(item.id, `payout-${index}`),
31
- primary: `Payout #${toStringValue(item.payoutNumber ?? item.id, "Unknown")}`,
32
- secondary: [
33
- toCurrency(item.amount ?? item.totalAmount),
34
- `Requested: ${toRelativeDate(item.requestedAt ?? item.createdAt)}`,
35
- ].join(" · "),
36
- status: toStringValue(item.status, "Pending"),
37
- updatedAt: toRelativeDate(item.processedAt ?? item.updatedAt ?? item.createdAt),
38
- })),
88
+ mapRows: (response) => toRecordArray(response.payouts).map((item, index) => {
89
+ const id = toStringValue(item.id, `payout-${index}`);
90
+ rawByIdRef.current[id] = item;
91
+ return {
92
+ id,
93
+ primary: `Payout #${toStringValue(item.payoutNumber ?? item.id, "Unknown")}`,
94
+ secondary: [
95
+ toCurrency(item.amount ?? item.totalAmount),
96
+ `Requested: ${toRelativeDate(item.requestedAt ?? item.createdAt)}`,
97
+ ].join(" · "),
98
+ status: toStringValue(item.status, "Pending"),
99
+ updatedAt: toRelativeDate(item.processedAt ?? item.updatedAt ?? item.createdAt),
100
+ };
101
+ }),
39
102
  getTotal: (response, mappedRows) => typeof response.meta?.total === "number"
40
103
  ? response.meta.total
41
104
  : mappedRows.length,
42
105
  buildFilters: (state) => state.status && state.status !== "All" ? sieveFilter("status", SIEVE_OP.EQ, state.status) : undefined,
106
+ // Rule #7: bulk-action array sourced from the CTA registry, not inline objects.
107
+ buildBulkActions: (selection) => [
108
+ buildBulkAction(ACTIONS.STORE["export-payout"], () => {
109
+ const rows = selection.selectedIds
110
+ .map((id) => rawByIdRef.current[id])
111
+ .filter((r) => Boolean(r));
112
+ handleExport(rows);
113
+ selection.clearSelection();
114
+ }),
115
+ ],
43
116
  renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
44
- ...(onViewClick
45
- ? [{ label: ACTIONS.STORE["view-payout"].label, onClick: () => onViewClick(row.id) }]
46
- : []),
47
- ...(onExportClick
48
- ? [{ label: ACTIONS.STORE["export-payout"].label, onClick: () => onExportClick(row.id) }]
49
- : []),
117
+ {
118
+ label: ACTIONS.STORE["view-payout"].label,
119
+ onClick: () => setSelectedPayout(rawByIdRef.current[row.id] ?? { id: row.id }),
120
+ },
121
+ {
122
+ label: ACTIONS.STORE["export-payout"].label,
123
+ onClick: () => handleExport([rawByIdRef.current[row.id] ?? { id: row.id }]),
124
+ },
50
125
  ] })),
51
126
  renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsx(FilterChipGroup, { label: "Status", tabs: ADMIN_PAYOUT_STATUS_TABS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) })),
52
127
  };
53
- return _jsx(DataListingView, { config: config });
128
+ const expectedByDate = selectedPayout?.requestedAt
129
+ ? new Date(new Date(selectedPayout.requestedAt).getTime() + PAYOUT_CYCLE_DAYS * 24 * 60 * 60 * 1000)
130
+ : null;
131
+ const orderIds = Array.isArray(selectedPayout?.orderIds) ? selectedPayout.orderIds : [];
132
+ return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(SideDrawer, { isOpen: Boolean(selectedPayout), onClose: () => setSelectedPayout(null), title: selectedPayout ? `Payout #${toStringValue(selectedPayout.payoutNumber ?? selectedPayout.id, "")}` : "Payout", mode: "view", children: selectedPayout && (_jsxs(Stack, { gap: "lg", children: [_jsx(StatusProgress, { status: toStringValue(selectedPayout.status, "pending") }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Amount" }), _jsx(Text, { size: "xl", weight: "bold", children: toCurrency(selectedPayout.amount ?? selectedPayout.totalAmount) })] }), selectedPayout.transactionId ? (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Transaction / reference ID" }), _jsx(Text, { size: "sm", className: "font-mono", children: String(selectedPayout.transactionId) })] })) : null, _jsxs(Row, { gap: "lg", wrap: true, children: [_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Requested" }), _jsx(Text, { size: "sm", children: formatDate(selectedPayout.requestedAt ?? selectedPayout.createdAt) })] }), selectedPayout.status === "paid" ? (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Paid on" }), _jsx(Text, { size: "sm", children: formatDate(selectedPayout.processedAt) })] })) : (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Expected by" }), _jsx(Text, { size: "sm", children: expectedByDate ? formatDate(expectedByDate.toISOString()) : "—" })] })), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Payment method" }), _jsx(Text, { size: "sm", className: "capitalize", children: toStringValue(selectedPayout.paymentMethod, "—").replace("_", " ") })] })] }), orderIds.length > 0 && (_jsxs(Stack, { gap: "xs", children: [_jsxs(Text, { size: "xs", color: "muted", children: ["Orders included (", orderIds.length, ")"] }), _jsx(Div, { className: "max-h-40", overflow: "y-auto", children: _jsx(Stack, { gap: "xs", children: orderIds.map((oid) => (_jsx(Text, { size: "xs", className: "font-mono", color: "muted", children: oid }, oid))) }) })] })), _jsxs(Row, { align: "center", justify: "between", border: "default", rounded: "lg", padding: "inline", children: [_jsxs(Stack, { gap: "none", children: [_jsx(Text, { size: "sm", weight: "medium", children: "Remind me" }), _jsx(Text, { size: "xs", color: "muted", children: "Flag this payout for a personal follow-up" })] }), _jsx(Toggle, { checked: Boolean(selectedPayout.sellerReminderFlag), onChange: handleToggleReminder, disabled: reminderPending, size: "md", "aria-label": ACTIONS.STORE["set-payout-reminder"].ariaLabel })] })] })) })] }));
54
133
  }
@@ -111,7 +111,7 @@ export function SellerPreOrdersView({ children, onDelete, ...props }) {
111
111
  const status = state.status && state.status !== "All" ? sieveFilter("status", SIEVE_OP.EQ, state.status) : null;
112
112
  return ["listingType==pre-order", status].filter(Boolean).join(",");
113
113
  },
114
- getRowHref: (row) => String(ROUTES.STORE.PRE_ORDERS_EDIT(row.id)),
114
+ rowHrefTemplate: String(ROUTES.STORE.PRE_ORDERS_EDIT("{id}")),
115
115
  renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
116
116
  {
117
117
  label: ACTIONS.STORE["edit-listing"].label,
@@ -108,7 +108,7 @@ export function SellerPrizeDrawsView({ children, onDelete, ...props }) {
108
108
  const status = state.status && state.status !== "All" ? sieveFilter("status", SIEVE_OP.EQ, state.status) : null;
109
109
  return ["listingType==prize-draw", status].filter(Boolean).join(",");
110
110
  },
111
- getRowHref: (row) => String(ROUTES.STORE.PRIZE_DRAWS_EDIT(row.id)),
111
+ rowHrefTemplate: String(ROUTES.STORE.PRIZE_DRAWS_EDIT("{id}")),
112
112
  renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
113
113
  {
114
114
  label: ACTIONS.STORE["edit-listing"].label,
@@ -18,6 +18,7 @@ import { ROUTES } from "../../../constants";
18
18
  import { normalizeListingType } from "../../products/utils/listing-type";
19
19
  import { toRecordArray, toRelativeDate, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
20
20
  import { DataTable } from "../../admin/components/DataTable";
21
+ import { useDataViewMode } from "../../account/hooks/useDataViewMode";
21
22
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
22
23
  import { buildBulkAction } from "../../../_internal/shared/actions/bulk-helpers";
23
24
  import { useListingTypeFlags } from "../../../react/hooks/useListingTypeFlags";
@@ -114,7 +115,7 @@ const PRODUCT_COLUMNS = [
114
115
  ];
115
116
  export function SellerProductsView({ onDeleteProduct, onCreateClick, children, ...props }) {
116
117
  const hasChildren = React.Children.count(children) > 0;
117
- const [view, setView] = useState("table");
118
+ const { view, setView } = useDataViewMode("table");
118
119
  const dispatch = useActionDispatch();
119
120
  const { showToast } = useToast();
120
121
  const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
@@ -302,8 +303,11 @@ export function SellerProductsView({ onDeleteProduct, onCreateClick, children, .
302
303
  { label: "Show sold", active: showSold, onChange: (next) => table.set("showSold", next ? "true" : "") },
303
304
  ], extra: onCreateClick ? (_jsx(Button, { variant: "primary", size: "sm", onClick: onCreateClick, children: "+ New Listing" })) : null }), _jsx(TypeDropdown, { active: listingKind, onChange: handleKindChange }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "default", border: true, padding: "sm", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), selection.selectedIds.length > 0 && (_jsx(StickyToolbar, { offset: "header+bulk-actions", tone: "default", border: true, padding: "sm", z: "above-toolbar", children: _jsx(BulkActionBar, { selectedCount: selection.selectedIds.length, onClearSelection: selection.clearSelection, actions: bulkActions }) })), _jsxs(Div, { paddingX: "x-sm-lg-md", padding: "y-md", children: [errorMessage && (_jsx(Alert, { variant: "error", className: "mb-4", children: errorMessage })), view !== "table" && (_jsx(SellerProductsCards, { view: view, rows: visibleRows, isLoading: isLoading, listingKind: listingKind, selectedIds: selection.selectedIdSet, toggle: selection.toggle, onEdit: handleEdit, onDuplicate: (row) => void handleDuplicate(row), onDelete: onDeleteProduct ? (row) => void handleDelete(row) : undefined })), view === "table" && (_jsx(DataTable, { columns: PRODUCT_COLUMNS, rows: visibleRows, isLoading: isLoading, emptyLabel: listingKind !== "all"
304
305
  ? `No ${listingKind} listings found`
305
- : "No products listed yet", selectedIds: selection.selectedIdSet, onToggleSelect: selection.toggle, onToggleSelectAll: () => selection.toggleAll(), getRowHref: (row) =>
306
+ : "No products listed yet", selectedIds: selection.selectedIdSet, onToggleSelect: selection.toggle, onToggleSelectAll: () => selection.toggleAll(), rowHrefTemplate: (row) =>
306
307
  // S-STORE-2-D — row click → public detail/preview, not edit.
308
+ // A function is safe here: both this view and DataTable are
309
+ // already client components, and the target varies per row
310
+ // (not expressible as a single {id} template string).
307
311
  row.listingKind === "auction"
308
312
  ? `/auctions/${row.id}`
309
313
  : row.listingKind === "pre-order"
@@ -1,8 +1,4 @@
1
1
  import React from "react";
2
2
  import type { ListingLayoutProps } from "../../../ui";
3
- export interface AdminShipmentsViewProps extends ListingLayoutProps {
4
- getRowHref?: (row: {
5
- id: string;
6
- }) => string;
7
- }
3
+ export type AdminShipmentsViewProps = ListingLayoutProps;
8
4
  export declare function AdminShipmentsView({ children, ...props }: AdminShipmentsViewProps): React.JSX.Element;
package/dist/index.d.ts CHANGED
@@ -132,8 +132,6 @@ export type { UseGestureOptions } from "./react/index";
132
132
  export type { UseKeyPressOptions } from "./react/index";
133
133
  export type { UsePullToRefreshOptions } from "./react/index";
134
134
  export type { UsePullToRefreshReturn } from "./react/index";
135
- export type { UseVisibleItemsOptions } from "./react/index";
136
- export type { UseVisibleItemsResult } from "./react/index";
137
135
  export { CONFIRMATION_MESSAGES } from "./values/index";
138
136
  export { INFO_MESSAGES } from "./values/index";
139
137
  export { deepClone } from "./utils/index";
@@ -3051,9 +3049,9 @@ export { Button } from "./ui/index";
3051
3049
  export { Heading, Spinner, IconButton, Progress, IndeterminateProgress, Pagination, PageLoader } from "./ui/index";
3052
3050
  export { ModalFooter, UnsavedChangesModal, ResponsiveView, Textarea, Checkbox } from "./ui/index";
3053
3051
  export { ToastProvider, StarRating, StepperNav, ViewToggle, PriceDisplay, SummaryCard } from "./ui/index";
3054
- export { CountdownDisplay, ItemRow, HorizontalScroller, TabStrip } from "./ui/index";
3052
+ export { CountdownDisplay, ItemRow, HorizontalScroller } from "./ui/index";
3055
3053
  export { CardBody, MenuTrigger, MenuContent, MenuSeparator, RoleBadge, SkipToMain } from "./ui/index";
3056
- export { TabsList, TabsContent, PasswordStrengthIndicator, TablePagination } from "./ui/index";
3054
+ export { Tabs, TabsList, TabsTrigger, TabsContent, PasswordStrengthIndicator, TablePagination } from "./ui/index";
3057
3055
  export { Stack, classNames, mergeTailwindClasses, SideModal, SideDrawer, RichText, RichTextRenderer } from "./ui/index";
3058
3056
  export type { RichTextRendererProps } from "./ui/index";
3059
3057
  export { SlottedListingView, DetailViewShell, StackedViewShell } from "./ui/index";
@@ -3067,7 +3065,7 @@ export { API_ENDPOINTS, API_ROUTES, LOGS_ENDPOINTS, AUTH_ENDPOINTS, ACCOUNT_ENDP
3067
3065
  export { WishlistFullError } from "./features/wishlist/server";
3068
3066
  export { useHistory, useHistoryMergeOnLogin, getGuestHistory, trackGuestHistory, removeGuestHistoryItem, clearGuestHistory, getGuestHistoryCount, type GuestHistoryItem, type GuestHistoryType, type UserHistoryItem, type HistoryProductType, type HistoryItemSnapshot, type TrackArgs as TrackHistoryArgs, } from "./features/history";
3069
3067
  export { historyRepository, UserHistoryRepository, trackHistoryView, getHistoryForUser, removeHistoryItem, clearHistory, mergeGuestHistory, } from "./features/history/server";
3070
- export { useMediaQuery, useBreakpoint, useClickOutside, useKeyPress, useLongPress, useGesture, useSwipe, useSession, useAuth, useCountdown, useCamera, useBulkSelection, useUrlTable, usePendingFilters, usePendingTable, useUnsavedChanges, UNSAVED_CHANGES_EVENT, useBulkAction, useEntityDelete, useContainerGrid, useMessage, useVisibleItems, useModalStack, RTDBPayloadStatus, } from "./react/index";
3068
+ export { useMediaQuery, useBreakpoint, useClickOutside, useKeyPress, useLongPress, useGesture, useSwipe, useSession, useAuth, useCountdown, useCamera, useBulkSelection, useUrlTable, usePendingFilters, usePendingTable, useUnsavedChanges, UNSAVED_CHANGES_EVENT, useBulkAction, useEntityDelete, useContainerGrid, useMessage, useModalStack, RTDBPayloadStatus, } from "./react/index";
3071
3069
  export { RoleGate, ProtectedRoute, SocialAuthButtons, AuthStatusPanel, LoginForm, RegisterForm, ForgotPasswordView, ResetPasswordView, VerifyEmailView, OAuthLoadingView, } from "./features/auth/index";
3072
3070
  export type { RoleGateProps, ProtectedRouteProps, AuthGuardUser, AuthRouteConfig, LoginFormProps, LoginFormValues, RegisterFormProps, RegisterFormValues, ForgotPasswordViewProps, ResetPasswordViewProps, VerifyEmailViewProps, } from "./features/auth/index";
3073
3071
  export { CartItemRow, CartDrawer, CartView, CartSummary, ShippingPicker } from "./features/cart/index";
package/dist/index.js CHANGED
@@ -5468,9 +5468,9 @@ export { Button } from "./ui/index";
5468
5468
  export { Heading, Spinner, IconButton, Progress, IndeterminateProgress, Pagination, PageLoader } from "./ui/index";
5469
5469
  export { ModalFooter, UnsavedChangesModal, ResponsiveView, Textarea, Checkbox } from "./ui/index";
5470
5470
  export { ToastProvider, StarRating, StepperNav, ViewToggle, PriceDisplay, SummaryCard } from "./ui/index";
5471
- export { CountdownDisplay, ItemRow, HorizontalScroller, TabStrip } from "./ui/index";
5471
+ export { CountdownDisplay, ItemRow, HorizontalScroller } from "./ui/index";
5472
5472
  export { CardBody, MenuTrigger, MenuContent, MenuSeparator, RoleBadge, SkipToMain } from "./ui/index";
5473
- export { TabsList, TabsContent, PasswordStrengthIndicator, TablePagination } from "./ui/index";
5473
+ export { Tabs, TabsList, TabsTrigger, TabsContent, PasswordStrengthIndicator, TablePagination } from "./ui/index";
5474
5474
  export { Stack, classNames, mergeTailwindClasses, SideModal, SideDrawer, RichText, RichTextRenderer } from "./ui/index";
5475
5475
  export { SlottedListingView, DetailViewShell, StackedViewShell } from "./ui/index";
5476
5476
  export { buildColumns, createColumnBuilder } from "./ui/index";
@@ -5486,7 +5486,7 @@ export { WishlistFullError } from "./features/wishlist/server";
5486
5486
  export { useHistory, useHistoryMergeOnLogin, getGuestHistory, trackGuestHistory, removeGuestHistoryItem, clearGuestHistory, getGuestHistoryCount, } from "./features/history";
5487
5487
  export { historyRepository, UserHistoryRepository, trackHistoryView, getHistoryForUser, removeHistoryItem, clearHistory, mergeGuestHistory, } from "./features/history/server";
5488
5488
  // Missing React hooks and providers
5489
- export { useMediaQuery, useBreakpoint, useClickOutside, useKeyPress, useLongPress, useGesture, useSwipe, useSession, useAuth, useCountdown, useCamera, useBulkSelection, useUrlTable, usePendingFilters, usePendingTable, useUnsavedChanges, UNSAVED_CHANGES_EVENT, useBulkAction, useEntityDelete, useContainerGrid, useMessage, useVisibleItems, useModalStack, RTDBPayloadStatus, } from "./react/index";
5489
+ export { useMediaQuery, useBreakpoint, useClickOutside, useKeyPress, useLongPress, useGesture, useSwipe, useSession, useAuth, useCountdown, useCamera, useBulkSelection, useUrlTable, usePendingFilters, usePendingTable, useUnsavedChanges, UNSAVED_CHANGES_EVENT, useBulkAction, useEntityDelete, useContainerGrid, useMessage, useModalStack, RTDBPayloadStatus, } from "./react/index";
5490
5490
  // Missing core types (already exported above; skipped to avoid duplicates)
5491
5491
  // Missing auth feature components
5492
5492
  export { RoleGate, ProtectedRoute, SocialAuthButtons, AuthStatusPanel, LoginForm, RegisterForm, ForgotPasswordView, ResetPasswordView, VerifyEmailView, OAuthLoadingView, } from "./features/auth/index";
@@ -46,8 +46,6 @@ export type { BulkActionPayload, BulkActionResult, BulkActionSummary, BulkAction
46
46
  export { useContainerGrid } from "./hooks/useContainerGrid";
47
47
  export { useMessage } from "./hooks/useMessage";
48
48
  export type { UseContainerGridOptions, UseContainerGridResult, } from "./hooks/useContainerGrid";
49
- export { useVisibleItems } from "./hooks/useVisibleItems";
50
- export type { UseVisibleItemsOptions, UseVisibleItemsResult, } from "./hooks/useVisibleItems";
51
49
  export { useModalStack } from "./useModalStack";
52
50
  export type { ModalEntry } from "./useModalStack";
53
51
  export { ErrorBoundary } from "./ErrorBoundary";
@@ -46,8 +46,6 @@ export { useBulkAction } from "./hooks/useBulkAction";
46
46
  export { useContainerGrid } from "./hooks/useContainerGrid";
47
47
  // Success/error message management
48
48
  export { useMessage } from "./hooks/useMessage";
49
- // Visible-items counter for tab strips and overflow scrollers
50
- export { useVisibleItems } from "./hooks/useVisibleItems";
51
49
  // Modal stack management
52
50
  export { useModalStack } from "./useModalStack";
53
51
  // Error boundary