@mohasinac/appkit 2.7.30 → 2.7.32

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 (92) hide show
  1. package/dist/_internal/client/features/filters/filter-load-options.d.ts +29 -0
  2. package/dist/_internal/client/features/filters/filter-load-options.js +98 -0
  3. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +1 -1
  4. package/dist/_internal/server/features/classified/adapters.js +1 -1
  5. package/dist/_internal/server/features/digital-code/adapters.js +1 -1
  6. package/dist/_internal/server/features/live/adapters.js +1 -1
  7. package/dist/_internal/shared/actions/action-registry.js +194 -1
  8. package/dist/client.d.ts +2 -0
  9. package/dist/client.js +1 -0
  10. package/dist/constants/api-endpoints.d.ts +6 -0
  11. package/dist/constants/api-endpoints.js +2 -0
  12. package/dist/constants/field-names.d.ts +1 -0
  13. package/dist/constants/field-names.js +1 -0
  14. package/dist/features/about/components/FAQPageView.js +1 -1
  15. package/dist/features/about/components/PublicProfileView.js +2 -2
  16. package/dist/features/account/components/UserSidebar.js +1 -1
  17. package/dist/features/admin/components/AdminAddressEditorView.d.ts +7 -0
  18. package/dist/features/admin/components/AdminAddressEditorView.js +117 -0
  19. package/dist/features/admin/components/AdminCategoryEditorView.js +12 -9
  20. package/dist/features/admin/components/AdminFeatureFlagsView.js +58 -13
  21. package/dist/features/admin/components/AdminProductEditorView.d.ts +3 -1
  22. package/dist/features/admin/components/AdminProductEditorView.js +12 -9
  23. package/dist/features/admin/components/AdminReturnRequestsView.js +5 -4
  24. package/dist/features/admin/components/AdminReviewsView.js +5 -4
  25. package/dist/features/admin/components/AdminSidebar.js +1 -1
  26. package/dist/features/admin/components/index.d.ts +2 -0
  27. package/dist/features/admin/components/index.js +1 -0
  28. package/dist/features/auctions/components/AuctionBidsTable.d.ts +13 -0
  29. package/dist/features/auctions/components/AuctionBidsTable.js +62 -0
  30. package/dist/features/auctions/components/AuctionDetailPageView.js +2 -2
  31. package/dist/features/auctions/components/AuctionFilters.d.ts +7 -1
  32. package/dist/features/auctions/components/AuctionFilters.js +3 -2
  33. package/dist/features/auctions/components/index.d.ts +2 -0
  34. package/dist/features/auctions/components/index.js +1 -0
  35. package/dist/features/blog/components/BlogPostView.js +1 -1
  36. package/dist/features/cart/components/CartView.js +2 -1
  37. package/dist/features/cart/components/CheckoutView.js +2 -1
  38. package/dist/features/categories/components/BrandDetailTabs.d.ts +5 -1
  39. package/dist/features/categories/components/BrandDetailTabs.js +29 -15
  40. package/dist/features/categories/components/CategoryDetailTabs.d.ts +5 -1
  41. package/dist/features/categories/components/CategoryDetailTabs.js +30 -15
  42. package/dist/features/classified/components/ClassifiedFilters.d.ts +5 -1
  43. package/dist/features/classified/components/ClassifiedFilters.js +3 -2
  44. package/dist/features/digital-codes/components/DigitalCodeFilters.d.ts +5 -1
  45. package/dist/features/digital-codes/components/DigitalCodeFilters.js +3 -2
  46. package/dist/features/events/repository/event-entry.repository.d.ts +1 -0
  47. package/dist/features/events/repository/event-entry.repository.js +5 -0
  48. package/dist/features/filters/index.d.ts +2 -0
  49. package/dist/features/filters/index.js +1 -0
  50. package/dist/features/homepage/components/FAQSection.js +1 -1
  51. package/dist/features/homepage/components/FeaturedProductsSection.js +6 -1
  52. package/dist/features/homepage/components/HeroCarousel.js +21 -5
  53. package/dist/features/homepage/components/SectionCarousel.js +3 -1
  54. package/dist/features/homepage/components/ShopByCategorySection.js +2 -2
  55. package/dist/features/layout/AppLayoutShell.d.ts +1 -1
  56. package/dist/features/layout/AppLayoutShell.js +1 -1
  57. package/dist/features/live/components/LiveItemFilters.d.ts +5 -1
  58. package/dist/features/live/components/LiveItemFilters.js +3 -2
  59. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +2 -2
  60. package/dist/features/pre-orders/components/PreOrderFilters.d.ts +7 -1
  61. package/dist/features/pre-orders/components/PreOrderFilters.js +3 -2
  62. package/dist/features/products/columns/productTableColumns.js +1 -1
  63. package/dist/features/products/components/CompareOverlay.d.ts +2 -0
  64. package/dist/features/products/components/CompareOverlay.js +1 -1
  65. package/dist/features/products/components/ProductFilters.d.ts +7 -1
  66. package/dist/features/products/components/ProductFilters.js +3 -2
  67. package/dist/features/products/components/ProductForm.js +6 -6
  68. package/dist/features/products/components/ProductGrid.js +1 -1
  69. package/dist/features/products/repository/products.repository.d.ts +4 -0
  70. package/dist/features/products/repository/products.repository.js +22 -3
  71. package/dist/features/products/schemas/firestore.d.ts +7 -1
  72. package/dist/features/products/types/index.d.ts +4 -0
  73. package/dist/features/reviews/repository/reviews.repository.d.ts +1 -0
  74. package/dist/features/reviews/repository/reviews.repository.js +14 -3
  75. package/dist/features/seller/components/SellerSidebar.js +1 -1
  76. package/dist/features/stores/components/StoreAboutView.js +1 -1
  77. package/dist/features/stores/components/StoreDetailLayoutView.js +16 -2
  78. package/dist/features/stores/components/StoreHeader.js +1 -1
  79. package/dist/index.d.ts +6 -0
  80. package/dist/index.js +6 -0
  81. package/dist/next/routing/route-map.d.ts +14 -0
  82. package/dist/next/routing/route-map.js +7 -0
  83. package/dist/seed/bids-seed-data.js +7 -4
  84. package/dist/seed/events-seed-data.js +23 -0
  85. package/dist/seed/history-seed-data.js +13 -0
  86. package/dist/seed/orders-seed-data.js +108 -1
  87. package/dist/seed/products-auctions-seed-data.js +40 -40
  88. package/dist/seed/products-preorders-seed-data.js +16 -16
  89. package/dist/seed/products-prize-draws-seed-data.js +4 -4
  90. package/dist/seed/products-standard-seed-data.js +202 -202
  91. package/dist/tailwind-utilities.css +1 -1
  92. package/package.json +1 -1
@@ -12,25 +12,39 @@ function tabLabel(label, count) {
12
12
  return label;
13
13
  return `${label} (${count.toLocaleString()})`;
14
14
  }
15
- export function BrandDetailTabs({ brandName, initialProductsData, initialBundles = [], counts, }) {
16
- const [activeTab, setActiveTab] = useState("products");
15
+ const TAB_TYPE_MAP = {
16
+ products: { kind: "listing", type: "standard" },
17
+ auctions: { kind: "listing", type: "auction" },
18
+ "pre-orders": { kind: "listing", type: "pre-order" },
19
+ "prize-draws": { kind: "listing", type: "prize-draw" },
20
+ bundles: { kind: "category", type: "bundle" },
21
+ };
22
+ export function BrandDetailTabs({ brandName, initialProductsData, initialBundles = [], counts, enabledListingTypes, enabledCategoryTypes, }) {
23
+ const visibleTabs = CATEGORY_PAGE_TABS.filter((t) => {
24
+ const mapping = TAB_TYPE_MAP[t.id];
25
+ if (!mapping)
26
+ return true;
27
+ if (mapping.kind === "listing" && enabledListingTypes) {
28
+ return enabledListingTypes.includes(mapping.type);
29
+ }
30
+ if (mapping.kind === "category" && enabledCategoryTypes) {
31
+ return enabledCategoryTypes.includes(mapping.type);
32
+ }
33
+ return true;
34
+ });
35
+ const firstTabId = (visibleTabs[0]?.id ?? "products");
36
+ const [activeTab, setActiveTab] = useState(firstTabId);
17
37
  const countFor = (id) => {
18
38
  switch (id) {
19
- case "products":
20
- return counts?.products;
21
- case "auctions":
22
- return counts?.auctions;
23
- case "pre-orders":
24
- return counts?.preOrders;
25
- case "prize-draws":
26
- return counts?.prizeDraws;
27
- case "bundles":
28
- return counts?.bundles;
29
- default:
30
- return undefined;
39
+ case "products": return counts?.products;
40
+ case "auctions": return counts?.auctions;
41
+ case "pre-orders": return counts?.preOrders;
42
+ case "prize-draws": return counts?.prizeDraws;
43
+ case "bundles": return counts?.bundles;
44
+ default: return undefined;
31
45
  }
32
46
  };
33
- return (_jsxs(_Fragment, { children: [_jsx("div", { className: "flex border-b border-zinc-200 dark:border-slate-700 mb-6 overflow-x-auto", children: CATEGORY_PAGE_TABS.map((t) => (_jsx("button", { type: "button", onClick: () => setActiveTab(t.id), className: `px-5 py-2.5 text-sm font-medium whitespace-nowrap transition-colors -mb-px border-b-2 ${activeTab === t.id
47
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: "flex border-b border-zinc-200 dark:border-slate-700 mb-6 overflow-x-auto", children: visibleTabs.map((t) => (_jsx("button", { type: "button", onClick: () => setActiveTab(t.id), className: `px-5 py-2.5 text-sm font-medium whitespace-nowrap transition-colors -mb-px border-b-2 ${activeTab === t.id
34
48
  ? "border-primary text-primary"
35
49
  : "border-transparent text-zinc-500 hover:text-zinc-900 dark:hover:text-zinc-100"}`, children: tabLabel(t.label, countFor(t.id)) }, t.id))) }), activeTab === "products" && (_jsx(CategoryProductsListing, { categorySlug: "", brandName: brandName, initialData: initialProductsData })), activeTab === "auctions" && (_jsx(AuctionsIndexListing, { brandName: brandName })), activeTab === "pre-orders" && (_jsx(PreOrdersIndexListing, { brandName: brandName })), activeTab === "prize-draws" && (_jsx(PrizeDrawsIndexListing, { brandName: brandName })), activeTab === "bundles" && (_jsx(CategoryBundlesListing, { initialBundles: initialBundles, brandName: brandName }))] }));
36
50
  }
@@ -11,5 +11,9 @@ export interface CategoryDetailTabsProps {
11
11
  prizeDraws?: number;
12
12
  bundles?: number;
13
13
  };
14
+ /** Enabled listing types (e.g. ["standard","auction","pre-order"]). When omitted, all tabs shown. */
15
+ enabledListingTypes?: string[];
16
+ /** Enabled category types (e.g. ["category","brand","bundle"]). When omitted, all tabs shown. */
17
+ enabledCategoryTypes?: string[];
14
18
  }
15
- export declare function CategoryDetailTabs({ categorySlug, categoryId, initialProductsData, initialBundles, counts, }: CategoryDetailTabsProps): import("react/jsx-runtime").JSX.Element;
19
+ export declare function CategoryDetailTabs({ categorySlug, categoryId, initialProductsData, initialBundles, counts, enabledListingTypes, enabledCategoryTypes, }: CategoryDetailTabsProps): import("react/jsx-runtime").JSX.Element;
@@ -12,25 +12,40 @@ function tabLabel(label, count) {
12
12
  return label;
13
13
  return `${label} (${count.toLocaleString()})`;
14
14
  }
15
- export function CategoryDetailTabs({ categorySlug, categoryId, initialProductsData, initialBundles = [], counts, }) {
16
- const [activeTab, setActiveTab] = useState("products");
15
+ /** Maps CATEGORY_PAGE_TABS id listing type / category type key for flag filtering. */
16
+ const TAB_TYPE_MAP = {
17
+ products: { kind: "listing", type: "standard" },
18
+ auctions: { kind: "listing", type: "auction" },
19
+ "pre-orders": { kind: "listing", type: "pre-order" },
20
+ "prize-draws": { kind: "listing", type: "prize-draw" },
21
+ bundles: { kind: "category", type: "bundle" },
22
+ };
23
+ export function CategoryDetailTabs({ categorySlug, categoryId, initialProductsData, initialBundles = [], counts, enabledListingTypes, enabledCategoryTypes, }) {
24
+ const visibleTabs = CATEGORY_PAGE_TABS.filter((t) => {
25
+ const mapping = TAB_TYPE_MAP[t.id];
26
+ if (!mapping)
27
+ return true;
28
+ if (mapping.kind === "listing" && enabledListingTypes) {
29
+ return enabledListingTypes.includes(mapping.type);
30
+ }
31
+ if (mapping.kind === "category" && enabledCategoryTypes) {
32
+ return enabledCategoryTypes.includes(mapping.type);
33
+ }
34
+ return true;
35
+ });
36
+ const firstTabId = (visibleTabs[0]?.id ?? "products");
37
+ const [activeTab, setActiveTab] = useState(firstTabId);
17
38
  const countFor = (id) => {
18
39
  switch (id) {
19
- case "products":
20
- return counts?.products;
21
- case "auctions":
22
- return counts?.auctions;
23
- case "pre-orders":
24
- return counts?.preOrders;
25
- case "prize-draws":
26
- return counts?.prizeDraws;
27
- case "bundles":
28
- return counts?.bundles;
29
- default:
30
- return undefined;
40
+ case "products": return counts?.products;
41
+ case "auctions": return counts?.auctions;
42
+ case "pre-orders": return counts?.preOrders;
43
+ case "prize-draws": return counts?.prizeDraws;
44
+ case "bundles": return counts?.bundles;
45
+ default: return undefined;
31
46
  }
32
47
  };
33
- return (_jsxs(_Fragment, { children: [_jsx("div", { className: "flex border-b border-zinc-200 dark:border-slate-700 mb-6 overflow-x-auto", children: CATEGORY_PAGE_TABS.map((t) => (_jsx("button", { type: "button", onClick: () => setActiveTab(t.id), className: `px-5 py-2.5 text-sm font-medium whitespace-nowrap transition-colors -mb-px border-b-2 ${activeTab === t.id
48
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: "flex border-b border-zinc-200 dark:border-slate-700 mb-6 overflow-x-auto", children: visibleTabs.map((t) => (_jsx("button", { type: "button", onClick: () => setActiveTab(t.id), className: `px-5 py-2.5 text-sm font-medium whitespace-nowrap transition-colors -mb-px border-b-2 ${activeTab === t.id
34
49
  ? "border-primary text-primary"
35
50
  : "border-transparent text-zinc-500 hover:text-zinc-900 dark:hover:text-zinc-100"}`, children: tabLabel(t.label, countFor(t.id)) }, t.id))) }), activeTab === "products" && (_jsx(CategoryProductsListing, { categorySlug: categorySlug, categoryId: categoryId, initialData: initialProductsData })), activeTab === "auctions" && (_jsx(AuctionsIndexListing, { categorySlug: categorySlug })), activeTab === "pre-orders" && (_jsx(PreOrdersIndexListing, { categorySlug: categorySlug })), activeTab === "prize-draws" && (_jsx(PrizeDrawsIndexListing, { categorySlug: categorySlug })), activeTab === "bundles" && (_jsx(CategoryBundlesListing, { initialBundles: initialBundles }))] }));
36
51
  }
@@ -1,8 +1,12 @@
1
1
  import type { FacetOption } from "../../filters/FilterFacetSection";
2
2
  import type { UrlTable } from "../../filters/FilterPanel";
3
+ import type { AsyncFacetSectionProps } from "../../filters/AsyncFacetSection";
4
+ type LoadOptionsFn = AsyncFacetSectionProps["loadOptions"];
3
5
  export interface ClassifiedFiltersProps {
4
6
  table: UrlTable;
5
7
  categoryOptions?: FacetOption[];
8
+ loadCategoryOptions?: LoadOptionsFn;
6
9
  currencyPrefix?: string;
7
10
  }
8
- export declare function ClassifiedFilters({ table, categoryOptions, currencyPrefix, }: ClassifiedFiltersProps): import("react/jsx-runtime").JSX.Element;
11
+ export declare function ClassifiedFilters({ table, categoryOptions, loadCategoryOptions, currencyPrefix, }: ClassifiedFiltersProps): import("react/jsx-runtime").JSX.Element;
12
+ export {};
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { FilterFacetSection } from "../../filters/FilterFacetSection";
4
+ import { AsyncFacetSection } from "../../filters/AsyncFacetSection";
4
5
  import { RangeFilter } from "../../filters/RangeFilter";
5
6
  import { Div } from "../../../ui";
6
7
  const NEGOTIABLE_OPTIONS = [
@@ -9,11 +10,11 @@ const NEGOTIABLE_OPTIONS = [
9
10
  const SHIPPING_OPTIONS = [
10
11
  { value: "true", label: "Accepts shipping" },
11
12
  ];
12
- export function ClassifiedFilters({ table, categoryOptions = [], currencyPrefix = "₹", }) {
13
+ export function ClassifiedFilters({ table, categoryOptions = [], loadCategoryOptions, currencyPrefix = "₹", }) {
13
14
  const selectedCategories = table.get("category")
14
15
  ? table.get("category").split("|").filter(Boolean)
15
16
  : [];
16
17
  const selectedNegotiable = table.get("negotiable") ? [table.get("negotiable")] : [];
17
18
  const selectedShipping = table.get("acceptsShipping") ? [table.get("acceptsShipping")] : [];
18
- return (_jsxs(Div, { children: [categoryOptions.length > 0 && (_jsx(FilterFacetSection, { title: "Category", options: categoryOptions, selected: selectedCategories, onChange: (vals) => table.set("category", vals.join("|")), searchable: true, defaultCollapsed: categoryOptions.length > 6 })), _jsxs("div", { className: "border-t border-[var(--appkit-color-border)] pt-4 mt-4", children: [_jsx("label", { className: "block text-sm font-medium text-[var(--appkit-color-text)] mb-2", children: "City / Area" }), _jsx("input", { type: "text", value: table.get("city") || "", onChange: (e) => table.set("city", e.target.value), placeholder: "e.g. Mumbai", className: "w-full rounded-lg border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-3 py-2 text-sm text-[var(--appkit-color-text)] placeholder-[var(--appkit-color-text-faint)] focus:outline-none focus:ring-2 focus:ring-[var(--appkit-color-primary)]" })] }), _jsx(FilterFacetSection, { title: "Negotiable", options: NEGOTIABLE_OPTIONS, selected: selectedNegotiable, onChange: (vals) => table.set("negotiable", vals[0] ?? ""), searchable: false, selectionMode: "single", defaultCollapsed: false }), _jsx(FilterFacetSection, { title: "Shipping", options: SHIPPING_OPTIONS, selected: selectedShipping, onChange: (vals) => table.set("acceptsShipping", vals[0] ?? ""), searchable: false, selectionMode: "single", defaultCollapsed: false }), _jsx(RangeFilter, { title: "Asking Price", minValue: table.get("minPrice"), maxValue: table.get("maxPrice"), onMinChange: (v) => table.set("minPrice", v), onMaxChange: (v) => table.set("maxPrice", v), prefix: currencyPrefix, showSlider: true, minBound: 0, maxBound: 500000, step: 100, minPlaceholder: "Min price", maxPlaceholder: "Max price", defaultCollapsed: false })] }));
19
+ return (_jsxs(Div, { children: [loadCategoryOptions ? (_jsx(AsyncFacetSection, { title: "Category", loadOptions: loadCategoryOptions, selected: selectedCategories, onChange: (vals) => table.set("category", vals.join("|")), defaultCollapsed: false })) : categoryOptions.length > 0 ? (_jsx(FilterFacetSection, { title: "Category", options: categoryOptions, selected: selectedCategories, onChange: (vals) => table.set("category", vals.join("|")), searchable: true, defaultCollapsed: categoryOptions.length > 6 })) : null, _jsxs("div", { className: "border-t border-[var(--appkit-color-border)] pt-4 mt-4", children: [_jsx("label", { className: "block text-sm font-medium text-[var(--appkit-color-text)] mb-2", children: "City / Area" }), _jsx("input", { type: "text", value: table.get("city") || "", onChange: (e) => table.set("city", e.target.value), placeholder: "e.g. Mumbai", className: "w-full rounded-lg border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-3 py-2 text-sm text-[var(--appkit-color-text)] placeholder-[var(--appkit-color-text-faint)] focus:outline-none focus:ring-2 focus:ring-[var(--appkit-color-primary)]" })] }), _jsx(FilterFacetSection, { title: "Negotiable", options: NEGOTIABLE_OPTIONS, selected: selectedNegotiable, onChange: (vals) => table.set("negotiable", vals[0] ?? ""), searchable: false, selectionMode: "single", defaultCollapsed: false }), _jsx(FilterFacetSection, { title: "Shipping", options: SHIPPING_OPTIONS, selected: selectedShipping, onChange: (vals) => table.set("acceptsShipping", vals[0] ?? ""), searchable: false, selectionMode: "single", defaultCollapsed: false }), _jsx(RangeFilter, { title: "Asking Price", minValue: table.get("minPrice"), maxValue: table.get("maxPrice"), onMinChange: (v) => table.set("minPrice", v), onMaxChange: (v) => table.set("maxPrice", v), prefix: currencyPrefix, showSlider: true, minBound: 0, maxBound: 500000, step: 100, minPlaceholder: "Min price", maxPlaceholder: "Max price", defaultCollapsed: false })] }));
19
20
  }
@@ -1,8 +1,12 @@
1
1
  import type { FacetOption } from "../../filters/FilterFacetSection";
2
2
  import type { UrlTable } from "../../filters/FilterPanel";
3
+ import type { AsyncFacetSectionProps } from "../../filters/AsyncFacetSection";
4
+ type LoadOptionsFn = AsyncFacetSectionProps["loadOptions"];
3
5
  export interface DigitalCodeFiltersProps {
4
6
  table: UrlTable;
5
7
  categoryOptions?: FacetOption[];
8
+ loadCategoryOptions?: LoadOptionsFn;
6
9
  currencyPrefix?: string;
7
10
  }
8
- export declare function DigitalCodeFilters({ table, categoryOptions, currencyPrefix, }: DigitalCodeFiltersProps): import("react/jsx-runtime").JSX.Element;
11
+ export declare function DigitalCodeFilters({ table, categoryOptions, loadCategoryOptions, currencyPrefix, }: DigitalCodeFiltersProps): import("react/jsx-runtime").JSX.Element;
12
+ export {};
@@ -1,16 +1,17 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { FilterFacetSection } from "../../filters/FilterFacetSection";
4
+ import { AsyncFacetSection } from "../../filters/AsyncFacetSection";
4
5
  import { RangeFilter } from "../../filters/RangeFilter";
5
6
  import { Div } from "../../../ui";
6
7
  const DELIVERY_OPTIONS = [
7
8
  { value: "auto-claim", label: "Instant (auto-claim)" },
8
9
  { value: "manual-email", label: "Manual (sent by seller)" },
9
10
  ];
10
- export function DigitalCodeFilters({ table, categoryOptions = [], currencyPrefix = "₹", }) {
11
+ export function DigitalCodeFilters({ table, categoryOptions = [], loadCategoryOptions, currencyPrefix = "₹", }) {
11
12
  const selectedCategories = table.get("category")
12
13
  ? table.get("category").split("|").filter(Boolean)
13
14
  : [];
14
15
  const selectedDelivery = table.get("deliveryMethod") ? [table.get("deliveryMethod")] : [];
15
- return (_jsxs(Div, { children: [categoryOptions.length > 0 && (_jsx(FilterFacetSection, { title: "Category", options: categoryOptions, selected: selectedCategories, onChange: (vals) => table.set("category", vals.join("|")), searchable: true, defaultCollapsed: categoryOptions.length > 6 })), _jsx(FilterFacetSection, { title: "Delivery Method", options: DELIVERY_OPTIONS, selected: selectedDelivery, onChange: (vals) => table.set("deliveryMethod", vals[0] ?? ""), searchable: false, selectionMode: "single", defaultCollapsed: false }), _jsx(RangeFilter, { title: "Price per Code", minValue: table.get("minPrice"), maxValue: table.get("maxPrice"), onMinChange: (v) => table.set("minPrice", v), onMaxChange: (v) => table.set("maxPrice", v), prefix: currencyPrefix, showSlider: true, minBound: 0, maxBound: 50000, step: 50, minPlaceholder: "Min price", maxPlaceholder: "Max price", defaultCollapsed: false })] }));
16
+ return (_jsxs(Div, { children: [loadCategoryOptions ? (_jsx(AsyncFacetSection, { title: "Category", loadOptions: loadCategoryOptions, selected: selectedCategories, onChange: (vals) => table.set("category", vals.join("|")), defaultCollapsed: false })) : categoryOptions.length > 0 ? (_jsx(FilterFacetSection, { title: "Category", options: categoryOptions, selected: selectedCategories, onChange: (vals) => table.set("category", vals.join("|")), searchable: true, defaultCollapsed: categoryOptions.length > 6 })) : null, _jsx(FilterFacetSection, { title: "Delivery Method", options: DELIVERY_OPTIONS, selected: selectedDelivery, onChange: (vals) => table.set("deliveryMethod", vals[0] ?? ""), searchable: false, selectionMode: "single", defaultCollapsed: false }), _jsx(RangeFilter, { title: "Price per Code", minValue: table.get("minPrice"), maxValue: table.get("maxPrice"), onMinChange: (v) => table.set("minPrice", v), onMaxChange: (v) => table.set("maxPrice", v), prefix: currencyPrefix, showSlider: true, minBound: 0, maxBound: 50000, step: 50, minPlaceholder: "Min price", maxPlaceholder: "Max price", defaultCollapsed: false })] }));
16
17
  }
@@ -6,6 +6,7 @@ declare class EventEntryRepository extends BaseRepository<EventEntryDocument> {
6
6
  constructor();
7
7
  protected mapDoc<D = EventEntryDocument>(snap: import("../../../providers/db-firebase").DocumentSnapshot): D;
8
8
  listForEvent(eventId: string, model: SieveModel): Promise<FirebaseSieveResult<EventEntryDocument>>;
9
+ listForUser(userId: string, model: SieveModel): Promise<FirebaseSieveResult<EventEntryDocument>>;
9
10
  hasUserEntered(eventId: string, userId: string): Promise<boolean>;
10
11
  countUserEntries(eventId: string, userId: string): Promise<number>;
11
12
  getLeaderboard(eventId: string, limit?: number): Promise<EventEntryDocument[]>;
@@ -18,6 +18,11 @@ class EventEntryRepository extends BaseRepository {
18
18
  baseQuery: this.getCollection().where(EVENT_ENTRY_FIELDS.EVENT_ID, "==", eventId),
19
19
  });
20
20
  }
21
+ async listForUser(userId, model) {
22
+ return this.sieveQuery(model, EventEntryRepository.SIEVE_FIELDS, {
23
+ baseQuery: this.getCollection().where(EVENT_ENTRY_FIELDS.USER_ID, "==", userId),
24
+ });
25
+ }
21
26
  async hasUserEntered(eventId, userId) {
22
27
  try {
23
28
  const snapshot = await this.getCollection()
@@ -1,5 +1,7 @@
1
1
  export { FilterFacetSection } from "./FilterFacetSection";
2
2
  export type { FilterFacetSectionProps, FacetOption, } from "./FilterFacetSection";
3
+ export { AsyncFacetSection } from "./AsyncFacetSection";
4
+ export type { AsyncFacetSectionProps } from "./AsyncFacetSection";
3
5
  export { RangeFilter } from "./RangeFilter";
4
6
  export type { RangeFilterProps } from "./RangeFilter";
5
7
  export { SwitchFilter } from "./SwitchFilter";
@@ -1,5 +1,6 @@
1
1
  // Public API for @mohasinac/feat-filters
2
2
  export { FilterFacetSection } from "./FilterFacetSection";
3
+ export { AsyncFacetSection } from "./AsyncFacetSection";
3
4
  export { RangeFilter } from "./RangeFilter";
4
5
  export { SwitchFilter } from "./SwitchFilter";
5
6
  export { FilterPanel } from "./FilterPanel";
@@ -65,6 +65,6 @@ export function FAQSection({ title, subtitle, items, tabs: tabsProp, showCategor
65
65
  }, [items, showTabs, activeTab]);
66
66
  return (_jsx(Section, { className: `py-16 px-4 sm:px-8 ${themed.bgSecondary} ${className}`, children: _jsxs("div", { className: "w-full max-w-4xl mx-auto", "data-section": "faqsection-div-320", children: [_jsxs("div", { className: "text-center mb-10", "data-section": "faqsection-div-321", children: [_jsx(Heading, { level: 2, variant: "none", className: "bg-gradient-to-r from-primary to-cobalt bg-clip-text text-transparent text-3xl md:text-4xl font-bold mb-3", children: title }), subtitle && (_jsx(Text, { className: `text-base max-w-xl mx-auto ${themed.textSecondary}`, children: subtitle }))] }), showTabs && (_jsxs("div", { className: `${flex.center} flex-wrap gap-2 mb-8`, "data-section": "faqsection-div-322", children: [_jsx(Button, { variant: activeTab === "all" ? "primary" : "ghost", size: "sm", onClick: () => setActiveTab("all"), className: "rounded-full", children: "All" }), derivedTabs.map((tab) => (_jsx(Button, { variant: activeTab === tab.value ? "primary" : "ghost", size: "sm", onClick: () => setActiveTab(tab.value), className: "rounded-full", children: tab.label }, tab.value)))] })), _jsxs("div", { className: "space-y-2", "data-section": "faqsection-div-323", children: [visibleItems.length === 0 && (_jsx(Text, { className: `text-center py-12 ${themed.textSecondary}`, children: "No FAQs in this category yet." })), visibleItems.map((faq) => {
67
67
  const isOpen = openIds.has(faq.id);
68
- return (_jsxs("div", { className: `${themed.bgPrimary} rounded-xl overflow-hidden border transition-all duration-200 ${isOpen ? "border-primary/40 shadow-sm" : `${themed.border}`}`, "data-section": "faqsection-div-324", children: [_jsxs(Button, { variant: "ghost", className: `w-full text-left px-5 py-4 ${flex.between} gap-4 hover:${themed.bgTertiary} transition-colors rounded-none`, onClick: () => toggle(faq.id), "aria-expanded": isOpen, children: [_jsx(Span, { className: `text-sm font-medium flex-1 leading-snug ${isOpen ? "text-primary" : themed.textPrimary}`, children: faq.question }), _jsx(ChevronDown, { className: `w-4 h-4 flex-shrink-0 transition-transform duration-250 ${isOpen ? "rotate-180 text-primary" : themed.textSecondary}` })] }), _jsx("div", { className: `grid transition-all duration-300 ease-out ${isOpen ? "grid-rows-[1fr] opacity-100" : "grid-rows-[0fr] opacity-0"}`, "data-section": "faqsection-div-325", children: _jsx("div", { className: "overflow-hidden", "data-section": "faqsection-div-326", children: _jsx("div", { className: "px-5 pb-5 pt-0", children: isHtml(faq.answer) ? (_jsx(RichText, { html: faq.answer, proseClass: "prose prose-sm max-w-none dark:prose-invert", className: themed.textSecondary })) : (_jsx(Text, { className: `text-sm leading-relaxed ${themed.textSecondary}`, children: faq.answer })) }) }) })] }, faq.id));
68
+ return (_jsxs("div", { className: `${themed.bgPrimary} rounded-xl overflow-hidden border transition-all duration-200 ${isOpen ? "border-primary/40 shadow-sm" : `${themed.border}`}`, "data-section": "faqsection-div-324", children: [_jsxs(Button, { variant: "ghost", className: `w-full text-left px-5 py-4 ${flex.between} gap-4 hover:${themed.bgTertiary} transition-colors rounded-none`, onClick: () => toggle(faq.id), "aria-expanded": isOpen, children: [_jsx(Span, { className: `text-sm font-medium flex-1 leading-snug ${isOpen ? "text-primary" : themed.textPrimary}`, children: faq.question }), _jsx(ChevronDown, { className: `w-4 h-4 flex-shrink-0 transition-transform duration-250 ${isOpen ? "rotate-180 text-primary" : themed.textSecondary}` })] }), _jsx("div", { className: `grid transition-all duration-300 ease-out ${isOpen ? "grid-rows-[1fr] opacity-100" : "grid-rows-[0fr] opacity-0"}`, "data-section": "faqsection-div-325", children: _jsx("div", { className: "overflow-hidden", "data-section": "faqsection-div-326", children: _jsx("div", { className: "px-5 pb-5 pt-0", children: isHtml(faq.answer) ? (_jsx(RichText, { html: faq.answer, proseClass: "prose prose-sm max-w-none dark:prose-invert" })) : (_jsx(Text, { className: `text-sm leading-relaxed ${themed.textSecondary}`, children: faq.answer })) }) }) })] }, faq.id));
69
69
  })] }), viewMoreHref && (_jsx("div", { className: "text-center mt-10", "data-section": "faqsection-div-327", children: _jsxs(TextLink, { href: viewMoreHref, className: "inline-flex items-center gap-2 px-6 py-2.5 rounded-full text-sm font-medium bg-primary/10 text-primary hover:bg-primary/20 dark:bg-primary/15 transition-colors", children: [viewMoreLabel, hasMore && moreCount > 0 && (_jsxs(Span, { className: "bg-primary text-white text-xs px-2 py-0.5 rounded-full", children: ["+", moreCount] }))] }) }))] }) }));
70
70
  }
@@ -4,6 +4,7 @@ import { useState, useEffect, useRef } from "react";
4
4
  import Link from "next/link";
5
5
  import { SectionCarousel } from "./SectionCarousel";
6
6
  import { useFeaturedProducts } from "../hooks/useFeaturedProducts";
7
+ import { useMediaQuery } from "../../../react";
7
8
  import { InteractiveProductCard } from "../../products/components/InteractiveProductCard";
8
9
  import { ROUTES } from "../../../next";
9
10
  import { Section, Heading, Text } from "../../../ui";
@@ -11,7 +12,11 @@ import { THEME_CONSTANTS } from "../../../tokens";
11
12
  // --- Multi-row grid + pagination -----------------------------------------------
12
13
  function ProductGrid({ items, rows, maxItems, pagination, viewMoreHref, viewMoreLabel, title, description, }) {
13
14
  const { themed } = THEME_CONSTANTS;
14
- const pageSize = Math.min(rows * 5, maxItems);
15
+ // On mobile (<sm, 2-col grid) a second row doubles the section height to ~2 screens.
16
+ // Collapse to 1 row automatically so the section fits within one viewport.
17
+ const isMobile = useMediaQuery("(max-width: 639px)");
18
+ const effectiveRows = isMobile ? 1 : rows;
19
+ const pageSize = Math.min(effectiveRows * 5, maxItems);
15
20
  const [offset, setOffset] = useState(0);
16
21
  const timerRef = useRef(null);
17
22
  const totalItems = Math.min(items.length, maxItems);
@@ -43,11 +43,27 @@ function getHoverClass(effect) {
43
43
  return "";
44
44
  }
45
45
  function getSlideHeightClass(height) {
46
- if (height === "viewport")
47
- return "min-h-screen";
48
- if (height === "tall")
49
- return "min-h-[80vh]";
50
- return "min-h-[60vh] md:min-h-[clamp(420px,72vh,680px)]";
46
+ // BN-1 (fixed bottom nav) = h-16 = 4rem, shown only below lg — must be subtracted on mobile.
47
+ // --header-height is the measured sticky header height set by AppLayoutShell.
48
+ if (height === "viewport") {
49
+ return [
50
+ // mobile: full dvh minus header minus BN-1
51
+ "min-h-[calc(100dvh-var(--header-height,3.5rem)-4rem)]",
52
+ // desktop: full dvh minus header only (no BN-1)
53
+ "lg:min-h-[calc(100dvh-var(--header-height,3.5rem))]",
54
+ ].join(" ");
55
+ }
56
+ if (height === "tall") {
57
+ return [
58
+ "min-h-[calc(72dvh-var(--header-height,3.5rem)-4rem)]",
59
+ "lg:min-h-[clamp(480px,76dvh,840px)]",
60
+ ].join(" ");
61
+ }
62
+ // medium (default) — comfortable hero without forcing full-screen
63
+ return [
64
+ "min-h-[calc(52dvh-var(--header-height,3.5rem)-4rem)]",
65
+ "lg:min-h-[clamp(420px,65dvh,680px)]",
66
+ ].join(" ");
51
67
  }
52
68
  /** Renders the slide background — image, video, solid colour, or gradient. */
53
69
  function SlideBackground({ bg, legacy, mobileLegacy, isMobile, priority, }) {
@@ -24,7 +24,9 @@ export function SectionCarousel({ title, description, headingVariant = "editoria
24
24
  return (_jsxs(Section, { className: [
25
25
  "relative overflow-hidden w-full",
26
26
  hasBg ? "" : themed.bgSecondary,
27
- "p-8",
27
+ // Vertical padding: 5rem on desktop, 3rem on mobile to leave room for adjacent sections.
28
+ // Horizontal: 1rem mobile → 2rem desktop; handled via inner max-w container.
29
+ "py-10 px-4 md:py-12 md:px-8",
28
30
  className,
29
31
  ]
30
32
  .filter(Boolean)
@@ -15,7 +15,7 @@ function CategoryChip({ category }) {
15
15
  const coverImage = category.display?.coverImage;
16
16
  const initial = category.name[0]?.toUpperCase() ?? "?";
17
17
  const productCount = category.metrics?.productCount ?? 0;
18
- return (_jsxs(Link, { href: ROUTES.PUBLIC.CATEGORY_DETAIL(category.slug), className: "group flex w-full min-h-[220px] flex-col overflow-hidden rounded-xl border border-zinc-200 bg-white shadow-sm transition-all hover:border-primary-300 hover:shadow-md dark:border-slate-700 dark:bg-slate-900 dark:hover:border-primary-600", children: [coverImage && isImageUrl(coverImage) ? (_jsx("div", { className: "aspect-video w-full overflow-hidden bg-zinc-100 dark:bg-slate-800", children: _jsx(Image, { src: coverImage, alt: category.name, width: 320, height: 180, className: "h-full w-full object-cover transition-transform duration-300 group-hover:scale-105" }) })) : (_jsx("div", { className: "aspect-video w-full bg-gradient-to-br from-zinc-100 to-zinc-200 dark:from-slate-800 dark:to-slate-700" })), _jsxs("div", { className: "flex flex-1 flex-col p-3 text-left", children: [_jsx("div", { className: "mb-2 flex h-9 w-9 items-center justify-center rounded-lg bg-primary-100 text-sm font-bold text-primary-700 dark:bg-primary-900 dark:text-primary-300", children: iconSrc && isImageUrl(iconSrc) ? (_jsx(Image, { src: iconSrc, alt: "", width: 24, height: 24, className: "h-6 w-6 rounded object-cover", "aria-hidden": true })) : iconSrc ? (_jsx("span", { "aria-hidden": "true", className: "text-lg leading-none", children: iconSrc })) : (initial) }), _jsx(Text, { className: `${THEME_CONSTANTS.utilities.textClamp2} text-sm font-semibold text-zinc-800 dark:text-zinc-200`, children: category.name }), _jsxs(Text, { className: "mt-1 text-xs text-zinc-500 dark:text-zinc-400", children: [productCount.toLocaleString(), " items"] }), _jsx(Text, { className: "mt-auto pt-3 text-xs font-medium text-primary dark:text-primary-400", children: "Browse category \u2192" })] })] }));
18
+ return (_jsxs(Link, { href: ROUTES.PUBLIC.CATEGORY_DETAIL(category.slug), className: "group flex w-full min-h-[180px] sm:min-h-[220px] flex-col overflow-hidden rounded-xl border border-zinc-200 bg-white shadow-sm transition-all hover:border-primary-300 hover:shadow-md dark:border-slate-700 dark:bg-slate-900 dark:hover:border-primary-600", children: [coverImage && isImageUrl(coverImage) ? (_jsx("div", { className: "aspect-video w-full overflow-hidden bg-zinc-100 dark:bg-slate-800", children: _jsx(Image, { src: coverImage, alt: category.name, width: 320, height: 180, className: "h-full w-full object-cover transition-transform duration-300 group-hover:scale-105" }) })) : (_jsx("div", { className: "aspect-video w-full bg-gradient-to-br from-zinc-100 to-zinc-200 dark:from-slate-800 dark:to-slate-700" })), _jsxs("div", { className: "flex flex-1 flex-col p-3 text-left", children: [_jsx("div", { className: "mb-2 flex h-9 w-9 items-center justify-center rounded-lg bg-primary-100 text-sm font-bold text-primary-700 dark:bg-primary-900 dark:text-primary-300", children: iconSrc && isImageUrl(iconSrc) ? (_jsx(Image, { src: iconSrc, alt: "", width: 24, height: 24, className: "h-6 w-6 rounded object-cover", "aria-hidden": true })) : iconSrc ? (_jsx("span", { "aria-hidden": "true", className: "text-lg leading-none", children: iconSrc })) : (initial) }), _jsx(Text, { className: `${THEME_CONSTANTS.utilities.textClamp2} text-sm font-semibold text-zinc-800 dark:text-zinc-200`, children: category.name }), _jsxs(Text, { className: "mt-1 text-xs text-zinc-500 dark:text-zinc-400", children: [productCount.toLocaleString(), " items"] }), _jsx(Text, { className: "mt-auto pt-3 text-xs font-medium text-primary dark:text-primary-400", children: "Browse category \u2192" })] })] }));
19
19
  }
20
20
  const CTA_CLASSES = {
21
21
  filled: "rounded-lg bg-[var(--appkit-color-primary)] px-5 py-2 text-sm font-semibold text-white hover:opacity-90",
@@ -56,7 +56,7 @@ export function ShopByCategorySection({ title = "Shop by Category", subtitle, li
56
56
  const categories = filtered.length > 0 ? filtered : allCategories;
57
57
  if (!isLoading && allCategories.length === 0)
58
58
  return null;
59
- return (_jsx(Section, { className: `py-12 px-4 ${themed.bgSecondary} ${className}`, children: _jsxs("div", { className: "mx-auto max-w-7xl", children: [_jsxs("div", { className: "mb-6 text-center", children: [_jsx(Heading, { level: 2, className: `text-2xl font-bold md:text-3xl ${themed.textPrimary}`, children: title }), subtitle && (_jsx(Text, { variant: "secondary", className: "mt-1 text-sm", children: subtitle }))] }), hasFilters && !isLoading && (_jsxs("div", { className: "mb-4 flex flex-wrap gap-2", children: [_jsx(FilterChip, { label: "All", active: activeFilter === "all", onClick: () => setActiveFilter("all") }), rootIds.slice(0, 5).map((id) => {
59
+ return (_jsx(Section, { className: `py-10 px-4 md:py-12 ${themed.bgSecondary} ${className}`, children: _jsxs("div", { className: "mx-auto max-w-7xl", children: [_jsxs("div", { className: "mb-6 text-center", children: [_jsx(Heading, { level: 2, className: `text-2xl font-bold md:text-3xl ${themed.textPrimary}`, children: title }), subtitle && (_jsx(Text, { variant: "secondary", className: "mt-1 text-sm", children: subtitle }))] }), hasFilters && !isLoading && (_jsxs("div", { className: "mb-4 flex flex-wrap gap-2", children: [_jsx(FilterChip, { label: "All", active: activeFilter === "all", onClick: () => setActiveFilter("all") }), rootIds.slice(0, 5).map((id) => {
60
60
  const cat = allCategories.find((c) => c.id === id);
61
61
  if (!cat)
62
62
  return null;
@@ -90,7 +90,7 @@ export interface AppLayoutShellProps {
90
90
  eventBannerSlot?: React.ReactNode;
91
91
  /**
92
92
  * Override className for the main content wrapper div.
93
- * When set, replaces the default `container mx-auto w-full max-w-screen-2xl px-4 py-6 …`
93
+ * When set, replaces the default `w-full px-4 py-6 …`
94
94
  * Use `"w-full"` for dashboard layouts that provide their own padding via DashboardLayoutClient.
95
95
  */
96
96
  contentClassName?: string;
@@ -147,5 +147,5 @@ export function AppLayoutShell({ children, navItems, sidebarItems = [], sidebarS
147
147
  opacity: darkBackground.overlay?.opacity ?? 0,
148
148
  },
149
149
  };
150
- return (_jsx(QueryClientProvider, { client: queryClient, children: _jsxs(Div, { className: "flex min-h-screen w-full flex-col overflow-x-clip transition-colors duration-300", children: [_jsx(BackgroundRenderer, { mode: theme === "dark" ? "dark" : "light", lightMode: normalizedLightBackground, darkMode: normalizedDarkBackground }), _jsxs(Div, { ref: headerRef, className: "sticky top-0 z-50 w-full", children: [_jsx(TitleBar, { onToggleSidebar: handleTogglePublicSidebar, sidebarOpen: sidebarOpen, onSearchToggle: () => setSearchOpen((prev) => !prev), searchOpen: searchOpen, brandName: brandName, brandShortName: brandShortName, siteLogoUrl: siteLogoUrl, logoHref: logoHref, promotionsHref: promotionsHref, cartHref: cartHref, wishlistHref: wishlistHref, userId: userId, profileHref: profileHref, loginHref: loginHref, registerHref: registerHref, user: user, navSlot: titleBarNavSlot, notificationSlot: titleBarNotificationSlot, devSlot: titleBarDevSlot, promoStripText: titleBarPromoStripText, isDark: theme === "dark", onToggleTheme: showThemeToggle ? toggleTheme : undefined, onBeforeToggleDashboardNav: handleBeforeDashboardNavToggle, suppressDashboardNav: suppressDashboardNav, hideSidebarToggle: hideSidebarToggle }), _jsx(NavbarWithSettings, { navItems: navItems, hiddenNavItems: hiddenNavItems, permissions: authUser?.permissions }), searchOpen && (searchSlotRenderer ? searchSlotRenderer(() => setSearchOpen(false)) : searchSlot)] }), eventBannerSlot, _jsx(AutoBreadcrumbs, {}), _jsxs(Div, { className: "relative flex w-full flex-1 overflow-x-clip", children: [_jsx(SidebarLayout, { isOpen: sidebarOpen, ariaLabel: "Secondary navigation", header: user ? (_jsx(SidebarUserHeader, { user: user, onClose: () => setSidebarOpen(false) })) : (_jsx(SidebarGuestHeader, { sidebarTitle: sidebarTitle, onClose: () => setSidebarOpen(false) })), onClose: () => setSidebarOpen(false), children: sidebarContent }), _jsx(Main, { id: "main-content", className: `w-full flex-1 ${hasBottomActions ? "mb-28" : "mb-16"} md:mb-0`, children: _jsx(Div, { className: contentClassName ?? "container mx-auto w-full max-w-screen-2xl px-4 py-6 md:px-6 lg:px-8", children: children }) })] }), _jsx(BackToTop, {}), _jsx(FooterLayout, { ...footer }), _jsx(BottomActions, {}), _jsx(BottomNavbar, { user: user, homeHref: homeHref, shopHref: shopHref, cartHref: cartHref, profileHref: profileHref, loginHref: loginHref, onSearchToggle: () => setSearchOpen((prev) => !prev), navItems: navItems, onMoreToggle: hasDashboardNav ? toggleDashboardNav : handleTogglePublicSidebar }), _jsx(UnsavedChangesModal, {})] }) }));
150
+ return (_jsx(QueryClientProvider, { client: queryClient, children: _jsxs(Div, { className: "flex min-h-screen w-full flex-col overflow-x-clip transition-colors duration-300", children: [_jsx(BackgroundRenderer, { mode: theme === "dark" ? "dark" : "light", lightMode: normalizedLightBackground, darkMode: normalizedDarkBackground }), _jsxs(Div, { ref: headerRef, className: "sticky top-0 z-50 w-full", children: [_jsx(TitleBar, { onToggleSidebar: handleTogglePublicSidebar, sidebarOpen: sidebarOpen, onSearchToggle: () => setSearchOpen((prev) => !prev), searchOpen: searchOpen, brandName: brandName, brandShortName: brandShortName, siteLogoUrl: siteLogoUrl, logoHref: logoHref, promotionsHref: promotionsHref, cartHref: cartHref, wishlistHref: wishlistHref, userId: userId, profileHref: profileHref, loginHref: loginHref, registerHref: registerHref, user: user, navSlot: titleBarNavSlot, notificationSlot: titleBarNotificationSlot, devSlot: titleBarDevSlot, promoStripText: titleBarPromoStripText, isDark: theme === "dark", onToggleTheme: showThemeToggle ? toggleTheme : undefined, onBeforeToggleDashboardNav: handleBeforeDashboardNavToggle, suppressDashboardNav: suppressDashboardNav, hideSidebarToggle: hideSidebarToggle }), _jsx(NavbarWithSettings, { navItems: navItems, hiddenNavItems: hiddenNavItems, permissions: authUser?.permissions }), searchOpen && (searchSlotRenderer ? searchSlotRenderer(() => setSearchOpen(false)) : searchSlot)] }), eventBannerSlot, _jsx(AutoBreadcrumbs, {}), _jsxs(Div, { className: "relative flex w-full flex-1 overflow-x-clip", children: [_jsx(SidebarLayout, { isOpen: sidebarOpen, ariaLabel: "Secondary navigation", header: user ? (_jsx(SidebarUserHeader, { user: user, onClose: () => setSidebarOpen(false) })) : (_jsx(SidebarGuestHeader, { sidebarTitle: sidebarTitle, onClose: () => setSidebarOpen(false) })), onClose: () => setSidebarOpen(false), children: sidebarContent }), _jsx(Main, { id: "main-content", className: `w-full flex-1 ${hasBottomActions ? "mb-28" : "mb-16"} md:mb-0`, children: _jsx(Div, { className: contentClassName ?? "w-full px-4 py-6 md:px-6 lg:px-8", children: children }) })] }), _jsx(BackToTop, {}), _jsx(FooterLayout, { ...footer }), _jsx(BottomActions, {}), _jsx(BottomNavbar, { user: user, homeHref: homeHref, shopHref: shopHref, cartHref: cartHref, profileHref: profileHref, loginHref: loginHref, onSearchToggle: () => setSearchOpen((prev) => !prev), navItems: navItems, onMoreToggle: hasDashboardNav ? toggleDashboardNav : handleTogglePublicSidebar }), _jsx(UnsavedChangesModal, {})] }) }));
151
151
  }
@@ -1,8 +1,12 @@
1
1
  import type { FacetOption } from "../../filters/FilterFacetSection";
2
2
  import type { UrlTable } from "../../filters/FilterPanel";
3
+ import type { AsyncFacetSectionProps } from "../../filters/AsyncFacetSection";
4
+ type LoadOptionsFn = AsyncFacetSectionProps["loadOptions"];
3
5
  export interface LiveItemFiltersProps {
4
6
  table: UrlTable;
5
7
  categoryOptions?: FacetOption[];
8
+ loadCategoryOptions?: LoadOptionsFn;
6
9
  currencyPrefix?: string;
7
10
  }
8
- export declare function LiveItemFilters({ table, categoryOptions, currencyPrefix, }: LiveItemFiltersProps): import("react/jsx-runtime").JSX.Element;
11
+ export declare function LiveItemFilters({ table, categoryOptions, loadCategoryOptions, currencyPrefix, }: LiveItemFiltersProps): import("react/jsx-runtime").JSX.Element;
12
+ export {};
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { FilterFacetSection } from "../../filters/FilterFacetSection";
4
+ import { AsyncFacetSection } from "../../filters/AsyncFacetSection";
4
5
  import { RangeFilter } from "../../filters/RangeFilter";
5
6
  import { Div } from "../../../ui";
6
7
  const SEX_OPTIONS = [
@@ -13,11 +14,11 @@ const TRANSPORT_OPTIONS = [
13
14
  { value: "courier", label: "Live-animal courier" },
14
15
  { value: "specialist", label: "Specialist transport" },
15
16
  ];
16
- export function LiveItemFilters({ table, categoryOptions = [], currencyPrefix = "₹", }) {
17
+ export function LiveItemFilters({ table, categoryOptions = [], loadCategoryOptions, currencyPrefix = "₹", }) {
17
18
  const selectedCategories = table.get("category")
18
19
  ? table.get("category").split("|").filter(Boolean)
19
20
  : [];
20
21
  const selectedSex = table.get("liveSex") ? [table.get("liveSex")] : [];
21
22
  const selectedTransport = table.get("liveTransportMethod") ? [table.get("liveTransportMethod")] : [];
22
- return (_jsxs(Div, { children: [categoryOptions.length > 0 && (_jsx(FilterFacetSection, { title: "Category", options: categoryOptions, selected: selectedCategories, onChange: (vals) => table.set("category", vals.join("|")), searchable: true, defaultCollapsed: categoryOptions.length > 6 })), _jsxs("div", { className: "border-t border-[var(--appkit-color-border)] pt-4 mt-4", children: [_jsx("label", { className: "block text-sm font-medium text-[var(--appkit-color-text)] mb-2", children: "Species / Animal" }), _jsx("input", { type: "text", value: table.get("species") || "", onChange: (e) => table.set("species", e.target.value), placeholder: "e.g. Axolotl, Parrot", className: "w-full rounded-lg border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-3 py-2 text-sm text-[var(--appkit-color-text)] placeholder-[var(--appkit-color-text-faint)] focus:outline-none focus:ring-2 focus:ring-[var(--appkit-color-primary)]" })] }), _jsxs("div", { className: "border-t border-[var(--appkit-color-border)] pt-4 mt-4", children: [_jsx("label", { className: "block text-sm font-medium text-[var(--appkit-color-text)] mb-2", children: "Jurisdiction (state/UT)" }), _jsx("input", { type: "text", value: table.get("jurisdiction") || "", onChange: (e) => table.set("jurisdiction", e.target.value), placeholder: "e.g. Maharashtra", className: "w-full rounded-lg border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-3 py-2 text-sm text-[var(--appkit-color-text)] placeholder-[var(--appkit-color-text-faint)] focus:outline-none focus:ring-2 focus:ring-[var(--appkit-color-primary)]" })] }), _jsx(FilterFacetSection, { title: "Sex", options: SEX_OPTIONS, selected: selectedSex, onChange: (vals) => table.set("liveSex", vals[0] ?? ""), searchable: false, selectionMode: "single", defaultCollapsed: false }), _jsx(FilterFacetSection, { title: "Transport Method", options: TRANSPORT_OPTIONS, selected: selectedTransport, onChange: (vals) => table.set("liveTransportMethod", vals[0] ?? ""), searchable: false, selectionMode: "single", defaultCollapsed: false }), _jsx(RangeFilter, { title: "Price", minValue: table.get("minPrice"), maxValue: table.get("maxPrice"), onMinChange: (v) => table.set("minPrice", v), onMaxChange: (v) => table.set("maxPrice", v), prefix: currencyPrefix, showSlider: true, minBound: 0, maxBound: 200000, step: 100, minPlaceholder: "Min price", maxPlaceholder: "Max price", defaultCollapsed: false })] }));
23
+ return (_jsxs(Div, { children: [loadCategoryOptions ? (_jsx(AsyncFacetSection, { title: "Category", loadOptions: loadCategoryOptions, selected: selectedCategories, onChange: (vals) => table.set("category", vals.join("|")), defaultCollapsed: false })) : categoryOptions.length > 0 ? (_jsx(FilterFacetSection, { title: "Category", options: categoryOptions, selected: selectedCategories, onChange: (vals) => table.set("category", vals.join("|")), searchable: true, defaultCollapsed: categoryOptions.length > 6 })) : null, _jsxs("div", { className: "border-t border-[var(--appkit-color-border)] pt-4 mt-4", children: [_jsx("label", { className: "block text-sm font-medium text-[var(--appkit-color-text)] mb-2", children: "Species / Animal" }), _jsx("input", { type: "text", value: table.get("species") || "", onChange: (e) => table.set("species", e.target.value), placeholder: "e.g. Axolotl, Parrot", className: "w-full rounded-lg border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-3 py-2 text-sm text-[var(--appkit-color-text)] placeholder-[var(--appkit-color-text-faint)] focus:outline-none focus:ring-2 focus:ring-[var(--appkit-color-primary)]" })] }), _jsxs("div", { className: "border-t border-[var(--appkit-color-border)] pt-4 mt-4", children: [_jsx("label", { className: "block text-sm font-medium text-[var(--appkit-color-text)] mb-2", children: "Jurisdiction (state/UT)" }), _jsx("input", { type: "text", value: table.get("jurisdiction") || "", onChange: (e) => table.set("jurisdiction", e.target.value), placeholder: "e.g. Maharashtra", className: "w-full rounded-lg border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-3 py-2 text-sm text-[var(--appkit-color-text)] placeholder-[var(--appkit-color-text-faint)] focus:outline-none focus:ring-2 focus:ring-[var(--appkit-color-primary)]" })] }), _jsx(FilterFacetSection, { title: "Sex", options: SEX_OPTIONS, selected: selectedSex, onChange: (vals) => table.set("liveSex", vals[0] ?? ""), searchable: false, selectionMode: "single", defaultCollapsed: false }), _jsx(FilterFacetSection, { title: "Transport Method", options: TRANSPORT_OPTIONS, selected: selectedTransport, onChange: (vals) => table.set("liveTransportMethod", vals[0] ?? ""), searchable: false, selectionMode: "single", defaultCollapsed: false }), _jsx(RangeFilter, { title: "Price", minValue: table.get("minPrice"), maxValue: table.get("maxPrice"), onMinChange: (v) => table.set("minPrice", v), onMaxChange: (v) => table.set("maxPrice", v), prefix: currencyPrefix, showSlider: true, minBound: 0, maxBound: 200000, step: 100, minPlaceholder: "Min price", maxPlaceholder: "Max price", defaultCollapsed: false })] }));
23
24
  }
@@ -112,8 +112,8 @@ export async function PreOrderDetailPageView({ id, initialPreOrder, onReserveNow
112
112
  const storeHref = storeSlug
113
113
  ? String(ROUTES.PUBLIC.STORE_DETAIL(storeSlug))
114
114
  : null;
115
- const category = typeof p.category === "string" ? p.category : null;
116
- const categoryName = typeof p.categoryName === "string" ? p.categoryName : null;
115
+ const category = Array.isArray(p.categorySlugs) && p.categorySlugs.length > 0 ? p.categorySlugs[0] : (typeof p.category === "string" ? p.category : null);
116
+ const categoryName = Array.isArray(p.categoryNames) && p.categoryNames.length > 0 ? p.categoryNames[0] : (typeof p.categoryName === "string" ? p.categoryName : null);
117
117
  const brand = typeof p.brand === "string" ? p.brand : null;
118
118
  const brandSlug = typeof p.brandSlug === "string" ? p.brandSlug : null;
119
119
  const features = Array.isArray(p.features) ? p.features : [];
@@ -1,10 +1,16 @@
1
1
  import type { FacetOption } from "../../filters/FilterFacetSection";
2
2
  import type { UrlTable } from "../../filters/FilterPanel";
3
+ import type { AsyncFacetSectionProps } from "../../filters/AsyncFacetSection";
4
+ type LoadOptionsFn = AsyncFacetSectionProps["loadOptions"];
3
5
  export interface PreOrderFiltersProps {
4
6
  table: UrlTable;
5
7
  categoryOptions?: FacetOption[];
6
8
  brandOptions?: FacetOption[];
7
9
  storeOptions?: FacetOption[];
10
+ loadCategoryOptions?: LoadOptionsFn;
11
+ loadBrandOptions?: LoadOptionsFn;
12
+ loadStoreOptions?: LoadOptionsFn;
8
13
  currencyPrefix?: string;
9
14
  }
10
- export declare function PreOrderFilters({ table, categoryOptions, brandOptions, storeOptions, currencyPrefix, }: PreOrderFiltersProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare function PreOrderFilters({ table, categoryOptions, brandOptions, storeOptions, loadCategoryOptions, loadBrandOptions, loadStoreOptions, currencyPrefix, }: PreOrderFiltersProps): import("react/jsx-runtime").JSX.Element;
16
+ export {};
@@ -2,9 +2,10 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useTranslations } from "next-intl";
4
4
  import { FilterFacetSection } from "../../filters/FilterFacetSection";
5
+ import { AsyncFacetSection } from "../../filters/AsyncFacetSection";
5
6
  import { RangeFilter } from "../../filters/RangeFilter";
6
7
  import { Div } from "../../../ui";
7
- export function PreOrderFilters({ table, categoryOptions = [], brandOptions = [], storeOptions = [], currencyPrefix = "", }) {
8
+ export function PreOrderFilters({ table, categoryOptions = [], brandOptions = [], storeOptions = [], loadCategoryOptions, loadBrandOptions, loadStoreOptions, currencyPrefix = "", }) {
8
9
  const t = useTranslations("filters");
9
10
  const selectedCategories = table.get("category")
10
11
  ? table.get("category").split("|").filter(Boolean)
@@ -21,5 +22,5 @@ export function PreOrderFilters({ table, categoryOptions = [], brandOptions = []
21
22
  const selectedStores = table.get("storeId")
22
23
  ? table.get("storeId").split("|").filter(Boolean)
23
24
  : [];
24
- return (_jsxs(Div, { children: [categoryOptions.length > 0 && (_jsx(FilterFacetSection, { title: t("category"), options: categoryOptions, selected: selectedCategories, onChange: (vals) => table.set("category", vals.join("|")), searchable: true, defaultCollapsed: categoryOptions.length > 6 })), brandOptions.length > 0 && (_jsx(FilterFacetSection, { title: t("brand"), options: brandOptions, selected: selectedBrands, onChange: (vals) => table.set("brand", vals[0] ?? ""), searchable: brandOptions.length > 4, defaultCollapsed: brandOptions.length > 6 })), _jsx(FilterFacetSection, { title: t("productionStatus"), options: productionStatusOptions, selected: selectedProductionStatuses, onChange: (vals) => table.set("preOrderProductionStatus", vals[0] ?? ""), searchable: false, selectionMode: "single", defaultCollapsed: false }), _jsx(RangeFilter, { title: t("priceRange"), minValue: table.get("minPrice"), maxValue: table.get("maxPrice"), onMinChange: (v) => table.set("minPrice", v), onMaxChange: (v) => table.set("maxPrice", v), prefix: currencyPrefix, showSlider: true, minBound: 0, maxBound: 500000, step: 100, minPlaceholder: t("minPrice"), maxPlaceholder: t("maxPrice"), defaultCollapsed: false }), storeOptions.length > 0 && (_jsx(FilterFacetSection, { title: t("store"), options: storeOptions, selected: selectedStores, onChange: (vals) => table.set("storeId", vals[0] ?? ""), searchable: storeOptions.length > 4, selectionMode: "single", defaultCollapsed: storeOptions.length > 6 })), _jsx(RangeFilter, { title: "Delivery Date Range", type: "date", minValue: table.get("dateFrom"), maxValue: table.get("dateTo"), onMinChange: (v) => table.set("dateFrom", v), onMaxChange: (v) => table.set("dateTo", v), minPlaceholder: t("minDate"), maxPlaceholder: t("maxDate"), defaultCollapsed: false })] }));
25
+ return (_jsxs(Div, { children: [loadCategoryOptions ? (_jsx(AsyncFacetSection, { title: t("category"), loadOptions: loadCategoryOptions, selected: selectedCategories, onChange: (vals) => table.set("category", vals.join("|")), defaultCollapsed: false })) : categoryOptions.length > 0 ? (_jsx(FilterFacetSection, { title: t("category"), options: categoryOptions, selected: selectedCategories, onChange: (vals) => table.set("category", vals.join("|")), searchable: true, defaultCollapsed: categoryOptions.length > 6 })) : null, loadBrandOptions ? (_jsx(AsyncFacetSection, { title: t("brand"), loadOptions: loadBrandOptions, selected: selectedBrands, onChange: (vals) => table.set("brand", vals[0] ?? ""), defaultCollapsed: false })) : brandOptions.length > 0 ? (_jsx(FilterFacetSection, { title: t("brand"), options: brandOptions, selected: selectedBrands, onChange: (vals) => table.set("brand", vals[0] ?? ""), searchable: brandOptions.length > 4, defaultCollapsed: brandOptions.length > 6 })) : null, _jsx(FilterFacetSection, { title: t("productionStatus"), options: productionStatusOptions, selected: selectedProductionStatuses, onChange: (vals) => table.set("preOrderProductionStatus", vals[0] ?? ""), searchable: false, selectionMode: "single", defaultCollapsed: false }), _jsx(RangeFilter, { title: t("priceRange"), minValue: table.get("minPrice"), maxValue: table.get("maxPrice"), onMinChange: (v) => table.set("minPrice", v), onMaxChange: (v) => table.set("maxPrice", v), prefix: currencyPrefix, showSlider: true, minBound: 0, maxBound: 500000, step: 100, minPlaceholder: t("minPrice"), maxPlaceholder: t("maxPrice"), defaultCollapsed: false }), loadStoreOptions ? (_jsx(AsyncFacetSection, { title: t("store"), loadOptions: loadStoreOptions, selected: selectedStores, onChange: (vals) => table.set("storeId", vals[0] ?? ""), defaultCollapsed: false })) : storeOptions.length > 0 ? (_jsx(FilterFacetSection, { title: t("store"), options: storeOptions, selected: selectedStores, onChange: (vals) => table.set("storeId", vals[0] ?? ""), searchable: storeOptions.length > 4, selectionMode: "single", defaultCollapsed: storeOptions.length > 6 })) : null, _jsx(RangeFilter, { title: "Delivery Date Range", type: "date", minValue: table.get("dateFrom"), maxValue: table.get("dateTo"), onMinChange: (v) => table.set("dateFrom", v), onMaxChange: (v) => table.set("dateTo", v), minPlaceholder: t("minDate"), maxPlaceholder: t("maxDate"), defaultCollapsed: false })] }));
25
26
  }
@@ -23,7 +23,7 @@ export function getProductTableColumns({ labels, onEdit, onDelete, currencyCode,
23
23
  header: labels.category,
24
24
  sortable: true,
25
25
  width: "12%",
26
- render: (product) => _jsx(Span, { children: product.category ?? "-" }),
26
+ render: (product) => _jsx(Span, { children: (Array.isArray(product.categorySlugs) ? product.categorySlugs[0] : product.category) ?? "-" }),
27
27
  },
28
28
  {
29
29
  key: "price",
@@ -12,6 +12,8 @@ export interface CompareProductLike {
12
12
  brand?: string;
13
13
  category?: string;
14
14
  categoryName?: string;
15
+ categorySlugs?: string[];
16
+ categoryNames?: string[];
15
17
  storeName?: string;
16
18
  storeSlug?: string;
17
19
  /** Canonical discriminator (SB1-G Phase 4). */
@@ -70,7 +70,7 @@ function CompareColumn({ item, productType, labels, onRemove, onClose }) {
70
70
  const img = item.mainImage ?? item.images?.[0];
71
71
  return (_jsxs(Stack, { gap: "md", className: COLUMN_CARD_CLASS, children: [_jsxs(Row, { justify: "between", align: "start", gap: "sm", children: [_jsx(Link, { href: href, target: "_blank", rel: REL_NOOPENER, className: "text-sm font-semibold text-zinc-900 dark:text-zinc-100 hover:underline line-clamp-2", children: item.title ?? item.id }), onRemove && (_jsx("button", { type: "button", onClick: () => onRemove(item.id), "aria-label": `${labels.remove} ${item.title ?? item.id}`, className: "shrink-0 rounded-full p-1 text-zinc-400 hover:bg-zinc-100 hover:text-rose-500 dark:hover:bg-zinc-800", children: _jsx(X, { className: "h-4 w-4" }) }))] }), _jsx(FieldRow, { label: labels.field.image, children: _jsx(Link, { href: href, target: "_blank", rel: REL_NOOPENER, children: _jsx(Div, { className: "relative aspect-square overflow-hidden rounded-lg bg-zinc-100 dark:bg-zinc-800", children: img ? (
72
72
  // eslint-disable-next-line @next/next/no-img-element
73
- _jsx("img", { src: img, alt: item.title ?? item.id, className: "h-full w-full object-cover" })) : null }) }) }), _jsx(FieldRow, { label: labels.field.price, children: _jsx(Text, { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: priceLabel(item) }) }), _jsx(FieldRow, { label: labels.field.condition, children: _jsx(Text, { children: item.condition ? _jsx("span", { className: CHIP_CLASS, children: item.condition }) : "—" }) }), _jsx(FieldRow, { label: labels.field.brand, children: _jsx(Text, { children: item.brand ? _jsx("span", { className: CHIP_CLASS, children: item.brand }) : "—" }) }), _jsx(FieldRow, { label: labels.field.category, children: _jsx(Text, { children: item.categoryName || item.category ? (_jsx("span", { className: CHIP_CLASS, children: item.categoryName ?? item.category })) : ("—") }) }), _jsx(FieldRow, { label: labels.field.store, children: _jsx(Text, { className: "text-sm text-zinc-700 dark:text-zinc-300", children: item.storeName ?? "—" }) }), _jsx(Button, { asChild: true, variant: "primary", size: "sm", className: "mt-auto", children: _jsx(Link, { href: href, target: "_blank", rel: REL_NOOPENER, onClick: onClose, children: labels.view }) })] }));
73
+ _jsx("img", { src: img, alt: item.title ?? item.id, className: "h-full w-full object-cover" })) : null }) }) }), _jsx(FieldRow, { label: labels.field.price, children: _jsx(Text, { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: priceLabel(item) }) }), _jsx(FieldRow, { label: labels.field.condition, children: _jsx(Text, { children: item.condition ? _jsx("span", { className: CHIP_CLASS, children: item.condition }) : "—" }) }), _jsx(FieldRow, { label: labels.field.brand, children: _jsx(Text, { children: item.brand ? _jsx("span", { className: CHIP_CLASS, children: item.brand }) : "—" }) }), _jsx(FieldRow, { label: labels.field.category, children: _jsx(Text, { children: (Array.isArray(item.categoryNames) ? item.categoryNames[0] : item.categoryName) || (Array.isArray(item.categorySlugs) ? item.categorySlugs[0] : item.category) ? (_jsx("span", { className: CHIP_CLASS, children: (Array.isArray(item.categoryNames) ? item.categoryNames[0] : item.categoryName) ?? (Array.isArray(item.categorySlugs) ? item.categorySlugs[0] : item.category) })) : ("—") }) }), _jsx(FieldRow, { label: labels.field.store, children: _jsx(Text, { className: "text-sm text-zinc-700 dark:text-zinc-300", children: item.storeName ?? "—" }) }), _jsx(Button, { asChild: true, variant: "primary", size: "sm", className: "mt-auto", children: _jsx(Link, { href: href, target: "_blank", rel: REL_NOOPENER, onClick: onClose, children: labels.view }) })] }));
74
74
  }
75
75
  function useFetchedProducts(productIds, passedItems, isOpen) {
76
76
  const [fetched, setFetched] = useState([]);
@@ -1,5 +1,7 @@
1
1
  import type { FacetOption } from "../../filters/FilterFacetSection";
2
2
  import type { UrlTable } from "../../filters/FilterPanel";
3
+ import type { AsyncFacetSectionProps } from "../../filters/AsyncFacetSection";
4
+ type LoadOptionsFn = AsyncFacetSectionProps["loadOptions"];
3
5
  export type { FacetOption, UrlTable };
4
6
  export type ProductFilterVariant = "admin" | "seller" | "public";
5
7
  export declare const PRODUCT_FILTER_KEYS: {
@@ -81,6 +83,10 @@ export interface ProductFiltersProps {
81
83
  /** @deprecated use storeOptions */
82
84
  sellerOptions?: FacetOption[];
83
85
  tagOptions?: FacetOption[];
86
+ /** Async load functions — when provided, use AsyncFacetSection instead of static FilterFacetSection */
87
+ loadCategoryOptions?: LoadOptionsFn;
88
+ loadBrandOptions?: LoadOptionsFn;
89
+ loadStoreOptions?: LoadOptionsFn;
84
90
  /** Sublisting category options — separate from main category filter */
85
91
  sublistingCategoryOptions?: FacetOption[];
86
92
  /** Feature badge options for filtering by product features */
@@ -94,4 +100,4 @@ export interface ProductFiltersProps {
94
100
  /** Show "part of a bundle" switch filter (default true) */
95
101
  showBundleFilter?: boolean;
96
102
  }
97
- export declare function ProductFilters({ table, categoryOptions, brandOptions, storeOptions, sellerOptions, tagOptions, sublistingCategoryOptions, featureOptions, showStatus, variant, statusOptions, currencyPrefix, showShipping, showBundleFilter, }: ProductFiltersProps): import("react/jsx-runtime").JSX.Element;
103
+ export declare function ProductFilters({ table, categoryOptions, brandOptions, storeOptions, sellerOptions, tagOptions, sublistingCategoryOptions, featureOptions, showStatus, variant, statusOptions, currencyPrefix, showShipping, showBundleFilter, loadCategoryOptions, loadBrandOptions, loadStoreOptions, }: ProductFiltersProps): import("react/jsx-runtime").JSX.Element;