@mohasinac/appkit 4.11.2 → 4.12.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 (246) hide show
  1. package/dist/_internal/server/features/checkout/actions.d.ts +40 -3
  2. package/dist/_internal/server/features/checkout/actions.js +232 -47
  3. package/dist/_internal/server/features/checkout/data.d.ts +10 -0
  4. package/dist/_internal/server/features/orders/adapters.js +20 -0
  5. package/dist/_internal/server/features/products/data.d.ts +12 -3
  6. package/dist/_internal/server/features/products/data.js +55 -4
  7. package/dist/_internal/server/features/products/index.d.ts +1 -1
  8. package/dist/_internal/server/features/products/index.js +1 -1
  9. package/dist/_internal/server/features/products/list-public.d.ts +47 -0
  10. package/dist/_internal/server/features/products/list-public.js +131 -6
  11. package/dist/_internal/server/features/reviews/data.d.ts +1 -1
  12. package/dist/_internal/server/features/reviews/data.js +3 -2
  13. package/dist/_internal/server/features/tester/visibility.js +3 -3
  14. package/dist/_internal/server/jobs/core/auctionSettlement.js +5 -2
  15. package/dist/_internal/server/jobs/core/testerSandboxCleanup.d.ts +1 -1
  16. package/dist/_internal/server/jobs/core/testerSandboxCleanup.js +4 -1
  17. package/dist/_internal/server/jobs/core/testerSandboxRefresh.js +2 -0
  18. package/dist/_internal/server/jobs/handlers/_helpers.js +4 -1
  19. package/dist/_internal/shared/checkout/lanes.d.ts +20 -0
  20. package/dist/_internal/shared/checkout/lanes.js +28 -0
  21. package/dist/_internal/shared/features/checkout/config.d.ts +4 -0
  22. package/dist/_internal/shared/features/checkout/config.js +8 -0
  23. package/dist/_internal/shared/features/promotions/schema.d.ts +0 -16
  24. package/dist/_internal/shared/features/promotions/schema.js +0 -2
  25. package/dist/_internal/shared/features/reviews/config.d.ts +8 -1
  26. package/dist/_internal/shared/features/reviews/config.js +8 -1
  27. package/dist/_internal/shared/fees/calculator.d.ts +34 -2
  28. package/dist/_internal/shared/fees/calculator.js +45 -1
  29. package/dist/_internal/shared/listing-types/_registry.d.ts +88 -1
  30. package/dist/_internal/shared/listing-types/_registry.js +63 -1
  31. package/dist/_internal/shared/listing-types/art/config.d.ts +59 -0
  32. package/dist/_internal/shared/listing-types/art/config.js +12 -0
  33. package/dist/_internal/shared/listing-types/auction/config.d.ts +53 -0
  34. package/dist/_internal/shared/listing-types/auction/config.js +17 -0
  35. package/dist/_internal/shared/listing-types/classified/config.d.ts +59 -0
  36. package/dist/_internal/shared/listing-types/classified/config.js +14 -0
  37. package/dist/_internal/shared/listing-types/digital-code/config.d.ts +59 -0
  38. package/dist/_internal/shared/listing-types/digital-code/config.js +12 -0
  39. package/dist/_internal/shared/listing-types/live/config.d.ts +59 -0
  40. package/dist/_internal/shared/listing-types/live/config.js +14 -0
  41. package/dist/_internal/shared/listing-types/pre-order/config.d.ts +110 -0
  42. package/dist/_internal/shared/listing-types/pre-order/config.js +14 -0
  43. package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +44 -0
  44. package/dist/_internal/shared/listing-types/prize-draw/config.js +10 -0
  45. package/dist/_internal/shared/listing-types/standard/config.d.ts +59 -0
  46. package/dist/_internal/shared/listing-types/standard/config.js +9 -0
  47. package/dist/_internal/shared/listing-types/stickers/config.d.ts +59 -0
  48. package/dist/_internal/shared/listing-types/stickers/config.js +12 -0
  49. package/dist/client.d.ts +12 -2
  50. package/dist/client.js +8 -2
  51. package/dist/constants/api-endpoints.d.ts +6 -0
  52. package/dist/constants/api-endpoints.js +2 -0
  53. package/dist/constants/field-names.d.ts +12 -0
  54. package/dist/constants/field-names.js +12 -0
  55. package/dist/constants/table-keys.d.ts +2 -0
  56. package/dist/constants/table-keys.js +2 -0
  57. package/dist/features/account/components/UserOrdersView.js +27 -5
  58. package/dist/features/admin/components/AdminAddressesView.js +21 -11
  59. package/dist/features/admin/components/AdminArtView.d.ts +9 -0
  60. package/dist/features/admin/components/AdminArtView.js +11 -35
  61. package/dist/features/admin/components/AdminClassifiedView.d.ts +9 -0
  62. package/dist/features/admin/components/AdminClassifiedView.js +11 -35
  63. package/dist/features/admin/components/AdminCouponEditorView.js +1 -4
  64. package/dist/features/admin/components/AdminDigitalCodesView.d.ts +9 -0
  65. package/dist/features/admin/components/AdminDigitalCodesView.js +11 -42
  66. package/dist/features/admin/components/AdminLiveView.d.ts +9 -0
  67. package/dist/features/admin/components/AdminLiveView.js +11 -41
  68. package/dist/features/admin/components/AdminOrderEditorView.d.ts +8 -1
  69. package/dist/features/admin/components/AdminOrderEditorView.js +4 -3
  70. package/dist/features/admin/components/AdminOrdersView.js +14 -1
  71. package/dist/features/admin/components/AdminPaymentMethodsView.js +18 -11
  72. package/dist/features/admin/components/AdminProductsView.js +34 -18
  73. package/dist/features/admin/components/AdminSiteConfigGuideView.js +1 -1
  74. package/dist/features/admin/components/AdminSiteSettingsView.js +4 -2
  75. package/dist/features/admin/components/AdminStickersView.d.ts +9 -0
  76. package/dist/features/admin/components/AdminStickersView.js +11 -35
  77. package/dist/features/admin/constants/filter-tabs.d.ts +26 -9
  78. package/dist/features/admin/constants/filter-tabs.js +22 -9
  79. package/dist/features/admin/hooks/useAdminListing.js +7 -2
  80. package/dist/features/admin/schemas/firestore.d.ts +5 -0
  81. package/dist/features/admin/schemas/firestore.js +1 -0
  82. package/dist/features/auctions/actions/bid-actions.js +2 -2
  83. package/dist/features/auctions/components/AuctionBidsTable.js +1 -1
  84. package/dist/features/auctions/components/AuctionBottomActions.js +1 -0
  85. package/dist/features/auctions/components/AuctionDetailPageView.js +13 -11
  86. package/dist/features/cart/components/CartDrawer.d.ts +9 -1
  87. package/dist/features/cart/components/CartDrawer.js +4 -3
  88. package/dist/features/cart/components/CartPriceBreakdown.d.ts +61 -0
  89. package/dist/features/cart/components/CartPriceBreakdown.js +25 -0
  90. package/dist/features/cart/components/StoreAddonsPicker.d.ts +47 -0
  91. package/dist/features/cart/components/StoreAddonsPicker.js +21 -0
  92. package/dist/features/cart/components/index.d.ts +4 -0
  93. package/dist/features/cart/components/index.js +2 -0
  94. package/dist/features/cart/repository/cart.repository.d.ts +20 -2
  95. package/dist/features/cart/repository/cart.repository.js +49 -0
  96. package/dist/features/cart/schemas/firestore.d.ts +26 -2
  97. package/dist/features/categories/components/BrandDetailTabs.js +31 -11
  98. package/dist/features/categories/components/CategoryDetailTabs.js +27 -7
  99. package/dist/features/categories/components/CategoryProductsListing.d.ts +9 -1
  100. package/dist/features/categories/components/CategoryProductsListing.js +5 -2
  101. package/dist/features/classified/components/ClassifiedDetailPageView.js +2 -1
  102. package/dist/features/contact/email.js +5 -1
  103. package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +17 -16
  104. package/dist/features/homepage/components/FeaturedResultsSection.js +1 -1
  105. package/dist/features/homepage/components/SectionCarousel.js +1 -1
  106. package/dist/features/homepage/components/ShopByCategorySection.js +1 -1
  107. package/dist/features/layout/AppLayoutShell.js +9 -2
  108. package/dist/features/layout/BottomActions.js +62 -6
  109. package/dist/features/layout/BottomActionsContext.d.ts +26 -0
  110. package/dist/features/layout/BottomActionsContext.js +18 -1
  111. package/dist/features/layout/hooks/useBottomActions.d.ts +12 -1
  112. package/dist/features/layout/hooks/useBottomActions.js +14 -1
  113. package/dist/features/layout/index.d.ts +1 -1
  114. package/dist/features/live/components/LiveItemDetailPageView.js +7 -6
  115. package/dist/features/orders/components/OrderAddonBadges.d.ts +36 -0
  116. package/dist/features/orders/components/OrderAddonBadges.js +28 -0
  117. package/dist/features/orders/components/index.d.ts +1 -0
  118. package/dist/features/orders/components/index.js +1 -0
  119. package/dist/features/orders/repository/orders.repository.d.ts +36 -0
  120. package/dist/features/orders/repository/orders.repository.js +18 -0
  121. package/dist/features/orders/types/index.d.ts +38 -0
  122. package/dist/features/pre-orders/components/PreOrderBottomActions.d.ts +1 -1
  123. package/dist/features/pre-orders/components/PreOrderBottomActions.js +3 -19
  124. package/dist/features/products/components/ArtStickersListView.js +5 -4
  125. package/dist/features/products/components/AuctionsIndexListing.js +1 -2
  126. package/dist/features/products/components/ListingBottomActions.d.ts +28 -0
  127. package/dist/features/products/components/ListingBottomActions.js +25 -0
  128. package/dist/features/products/components/PrizeDrawBottomActions.d.ts +1 -1
  129. package/dist/features/products/components/PrizeDrawBottomActions.js +3 -21
  130. package/dist/features/products/components/PrizeDrawsListingView.js +18 -33
  131. package/dist/features/products/components/ProductDetailActions.js +4 -0
  132. package/dist/features/products/components/ProductDetailPageView.js +7 -7
  133. package/dist/features/products/components/ProductsIndexListing.js +87 -11
  134. package/dist/features/products/components/ProductsIndexPageView.js +14 -2
  135. package/dist/features/products/config/listing-type-listing-config.d.ts +31 -0
  136. package/dist/features/products/config/listing-type-listing-config.js +74 -0
  137. package/dist/features/products/constants/listing-tabs.d.ts +43 -198
  138. package/dist/features/products/constants/listing-tabs.js +71 -58
  139. package/dist/features/products/constants/sieve.d.ts +104 -1
  140. package/dist/features/products/constants/sieve.js +27 -7
  141. package/dist/features/products/hooks/useProducts.js +14 -0
  142. package/dist/features/products/repository/products.repository.d.ts +45 -1
  143. package/dist/features/products/repository/products.repository.js +26 -3
  144. package/dist/features/products/types/index.d.ts +15 -0
  145. package/dist/features/products/utils/listing-badge-variant.d.ts +20 -1
  146. package/dist/features/products/utils/listing-badge-variant.js +26 -1
  147. package/dist/features/products/utils/listing-type.d.ts +24 -0
  148. package/dist/features/products/utils/listing-type.js +48 -0
  149. package/dist/features/promotions/actions/coupon-actions.d.ts +7 -0
  150. package/dist/features/promotions/actions/coupon-actions.js +12 -1
  151. package/dist/features/promotions/actions/coupon-stacking.d.ts +24 -0
  152. package/dist/features/promotions/actions/coupon-stacking.js +21 -0
  153. package/dist/features/promotions/actions/index.d.ts +1 -0
  154. package/dist/features/promotions/actions/index.js +1 -0
  155. package/dist/features/promotions/actions/seller-coupon-actions.d.ts +0 -1
  156. package/dist/features/promotions/actions/seller-coupon-actions.js +0 -1
  157. package/dist/features/promotions/components/CouponHelpDetails.d.ts +20 -0
  158. package/dist/features/promotions/components/CouponHelpDetails.js +17 -0
  159. package/dist/features/promotions/components/CouponsIndexListing.js +2 -1
  160. package/dist/features/promotions/components/index.d.ts +2 -0
  161. package/dist/features/promotions/components/index.js +1 -0
  162. package/dist/features/promotions/constants/coupon-help.d.ts +27 -0
  163. package/dist/features/promotions/constants/coupon-help.js +42 -0
  164. package/dist/features/promotions/repository/coupons.repository.d.ts +10 -1
  165. package/dist/features/promotions/repository/coupons.repository.js +22 -8
  166. package/dist/features/promotions/schemas/firestore.d.ts +0 -1
  167. package/dist/features/promotions/schemas/firestore.js +1 -1
  168. package/dist/features/promotions/schemas/index.d.ts +0 -20
  169. package/dist/features/promotions/schemas/index.js +0 -1
  170. package/dist/features/reviews/actions/review-actions.js +5 -1
  171. package/dist/features/reviews/components/ReviewDetailPageView.js +2 -1
  172. package/dist/features/reviews/components/ReviewFilters.d.ts +7 -1
  173. package/dist/features/reviews/components/ReviewFilters.js +4 -3
  174. package/dist/features/reviews/components/ReviewsIndexListing.d.ts +6 -0
  175. package/dist/features/reviews/components/ReviewsIndexListing.js +9 -109
  176. package/dist/features/reviews/components/ReviewsListingPanel.d.ts +41 -0
  177. package/dist/features/reviews/components/ReviewsListingPanel.js +226 -0
  178. package/dist/features/reviews/components/index.d.ts +2 -0
  179. package/dist/features/reviews/components/index.js +1 -0
  180. package/dist/features/reviews/hooks/useReviews.d.ts +8 -0
  181. package/dist/features/reviews/hooks/useReviews.js +14 -6
  182. package/dist/features/reviews/repository/reviews.repository.d.ts +29 -1
  183. package/dist/features/reviews/repository/reviews.repository.js +77 -41
  184. package/dist/features/reviews/types/index.d.ts +8 -1
  185. package/dist/features/seller/components/SellerOrdersView.js +2 -1
  186. package/dist/features/seller/components/SellerProductsCards.js +2 -2
  187. package/dist/features/seller/components/SellerProductsView.js +21 -18
  188. package/dist/features/stores/actions/store-query-actions.js +1 -1
  189. package/dist/features/stores/components/StoreArtStickersPageView.d.ts +21 -0
  190. package/dist/features/stores/components/StoreArtStickersPageView.js +30 -0
  191. package/dist/features/stores/components/StoreAuctionsListing.js +5 -11
  192. package/dist/features/stores/components/StoreAuctionsPageView.d.ts +4 -1
  193. package/dist/features/stores/components/StoreAuctionsPageView.js +17 -17
  194. package/dist/features/stores/components/StoreClassifiedsListing.js +7 -0
  195. package/dist/features/stores/components/StoreClassifiedsPageView.d.ts +4 -1
  196. package/dist/features/stores/components/StoreClassifiedsPageView.js +16 -12
  197. package/dist/features/stores/components/StoreDetailLayoutView.js +4 -3
  198. package/dist/features/stores/components/StoreDigitalCodesListing.js +5 -0
  199. package/dist/features/stores/components/StoreDigitalCodesPageView.d.ts +4 -1
  200. package/dist/features/stores/components/StoreDigitalCodesPageView.js +16 -12
  201. package/dist/features/stores/components/StoreLiveItemsListing.js +7 -0
  202. package/dist/features/stores/components/StoreLiveItemsPageView.d.ts +4 -1
  203. package/dist/features/stores/components/StoreLiveItemsPageView.js +16 -12
  204. package/dist/features/stores/components/StorePreOrdersListing.js +6 -11
  205. package/dist/features/stores/components/StorePreOrdersPageView.d.ts +4 -1
  206. package/dist/features/stores/components/StorePreOrdersPageView.js +17 -17
  207. package/dist/features/stores/components/StorePrizeDrawsPageView.d.ts +4 -8
  208. package/dist/features/stores/components/StorePrizeDrawsPageView.js +17 -22
  209. package/dist/features/stores/components/StoreProductsListing.d.ts +7 -1
  210. package/dist/features/stores/components/StoreProductsListing.js +3 -2
  211. package/dist/features/stores/components/StoreProductsPageView.d.ts +1 -1
  212. package/dist/features/stores/components/StoreProductsPageView.js +16 -21
  213. package/dist/features/stores/components/StoreReviewsListing.d.ts +4 -0
  214. package/dist/features/stores/components/StoreReviewsListing.js +7 -108
  215. package/dist/features/stores/schemas/index.d.ts +2 -2
  216. package/dist/features/tester/seed-data/coupons-tester-seed-data.js +3 -3
  217. package/dist/features/tester/seed-data/index.d.ts +1 -0
  218. package/dist/features/tester/seed-data/index.js +1 -0
  219. package/dist/features/tester/seed-data/offers-tester-seed-data.d.ts +2 -0
  220. package/dist/features/tester/seed-data/offers-tester-seed-data.js +61 -0
  221. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +939 -1
  222. package/dist/index.d.ts +9 -3
  223. package/dist/index.js +11 -2
  224. package/dist/next/routing/route-map.d.ts +2 -0
  225. package/dist/next/routing/route-map.js +5 -0
  226. package/dist/react/hooks/useListingTypeFlags.d.ts +12 -19
  227. package/dist/react/hooks/useListingTypeFlags.js +4 -9
  228. package/dist/schemas/registry.d.ts +0 -12
  229. package/dist/seed/claimed-coupons-seed-data.js +3 -3
  230. package/dist/seed/coupons-seed-data.js +29 -10
  231. package/dist/seed/faq-seed-data.js +2 -2
  232. package/dist/seed/manifest.js +2 -2
  233. package/dist/seed/reviews-seed-data.js +52 -0
  234. package/dist/server-entry.d.ts +1 -0
  235. package/dist/server-entry.js +1 -0
  236. package/dist/styles.css +55 -39
  237. package/dist/tailwind-utilities.css +1 -1
  238. package/dist/ui/components/Checkbox.d.ts +10 -1
  239. package/dist/ui/components/Checkbox.js +14 -2
  240. package/dist/ui/components/Checkbox.style.css +11 -0
  241. package/dist/ui/components/FilterChipGroup.d.ts +21 -3
  242. package/dist/ui/components/FilterChipGroup.js +33 -4
  243. package/dist/ui/components/HorizontalScroller.d.ts +1 -2
  244. package/dist/ui/components/HorizontalScroller.js +9 -5
  245. package/dist/ui/components/HorizontalScroller.style.css +43 -38
  246. package/package.json +1 -1
@@ -17,9 +17,11 @@ import { ROUTES } from "../../../constants";
17
17
  import { normalizeListingType } from "../../products/utils/listing-type";
18
18
  import { toRecordArray, toRelativeDate, toStringValue } from "../hooks/useSellerListingData";
19
19
  import { useListingTypeFlags } from "../../../react/hooks/useListingTypeFlags";
20
+ import { ALL_LISTING_TYPES } from "../../../_internal/shared/listing-types/feature-flags";
21
+ import { pluginFor } from "../../../_internal/shared/listing-types/_registry";
20
22
  import { SellerProductsCards } from "./SellerProductsCards";
21
23
  import { SellerProductsFilterFields } from "./SellerProductsFilterDrawer";
22
- import { LISTING_BADGE_VARIANT } from "../../products/utils/listing-badge-variant";
24
+ import { listingBadgeVariant } from "../../products/utils/listing-badge-variant";
23
25
  import { DataListingView } from "../../admin/components/DataListingView";
24
26
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
25
27
  import { buildBulkAction } from "../../../_internal/shared/actions/bulk-helpers";
@@ -43,21 +45,24 @@ const SORT_OPTIONS = [
43
45
  { value: sortBy("title", "DESC"), label: "Title Z–A" },
44
46
  { value: sortBy("price", "DESC"), label: "Price High" },
45
47
  { value: sortBy("price", "ASC"), label: "Price Low" },
48
+ // Now genuinely sortable — see the note on AdminProductsView's sortOptions.
49
+ { value: sortBy("featured", "DESC"), label: "Featured first" },
50
+ { value: sortBy("isPromoted", "DESC"), label: "Promoted first" },
46
51
  ];
47
52
  const STATUS_OPTIONS = SELLER_PRODUCT_STATUS_TABS;
48
53
  function TypeDropdown({ active, onChange, }) {
49
54
  const flags = useListingTypeFlags();
55
+ // Derived from ALL_LISTING_TYPES + the plugin registry (2026-08-21). This
56
+ // used to be a hand-written list that had no `art`/`stickers` entries and
57
+ // still offered `bundle` — which stopped being a listingType in SB-UNI-D, so
58
+ // picking it filtered on a value no product can hold and returned nothing.
50
59
  const options = [
51
60
  { value: "all", label: "All listings" },
52
- flags.standard && { value: "standard", label: "Standard" },
53
- flags.auction && { value: "auction", label: "Auction" },
54
- flags["pre-order"] && { value: "pre-order", label: "Pre-order" },
55
- flags["prize-draw"] && { value: "prize-draw", label: "Prize Draw" },
56
- { value: "bundle", label: "Bundle" },
57
- flags.classified && { value: "classified", label: "Classified" },
58
- flags["digital-code"] && { value: "digital-code", label: "Digital Code" },
59
- flags.live && { value: "live", label: "Live" },
60
- ].filter(Boolean);
61
+ ...ALL_LISTING_TYPES.filter(flags.isEnabled).map((type) => ({
62
+ value: type,
63
+ label: pluginFor(type).typeLabel,
64
+ })),
65
+ ];
61
66
  return (_jsxs(Row, { paddingX: "x-sm-lg-md", border: "bottom", padding: "y-xs", gap: "sm", children: [_jsx(Text, { className: "tracking-wide text-[var(--appkit-color-text-muted)]", size: "xs", weight: "semibold", transform: "uppercase", children: "Listing type" }), _jsx(Select, { options: options, value: active, onValueChange: (v) => onChange(v), wrapperClassName: "sm:max-w-xs", "aria-label": "Filter by listing type" })] }));
62
67
  }
63
68
  const PRODUCT_COLUMNS = [
@@ -70,7 +75,7 @@ const PRODUCT_COLUMNS = [
70
75
  {
71
76
  key: "primary",
72
77
  header: "Product",
73
- render: (row) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { className: "text-[var(--appkit-color-text)] line-clamp-1", weight: "medium", children: row.primary }), _jsxs(Row, { gap: "sm", children: [_jsx(Badge, { variant: LISTING_BADGE_VARIANT[row.listingKind] ?? "default", children: row.listingKind }), _jsx(Span, { size: "xs", color: "muted", children: row.secondary })] })] })),
78
+ render: (row) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { className: "text-[var(--appkit-color-text)] line-clamp-1", weight: "medium", children: row.primary }), _jsxs(Row, { gap: "sm", children: [_jsx(Badge, { variant: listingBadgeVariant(row.listingKind), children: row.listingKind }), _jsx(Span, { size: "xs", color: "muted", children: row.secondary })] })] })),
74
79
  },
75
80
  {
76
81
  key: "price",
@@ -206,13 +211,11 @@ export function SellerProductsView({ onDeleteProduct, onCreateClick, }) {
206
211
  mapRows: (response) => {
207
212
  const rows = toRecordArray(response.products).map((item, index) => {
208
213
  const lt = normalizeListingType(item);
209
- const kind = lt === "auction"
210
- ? "auction"
211
- : lt === "pre-order"
212
- ? "pre-order"
213
- : lt === "prize-draw"
214
- ? "prize-draw"
215
- : "standard";
214
+ // The row's own type, verbatim. This used to be a 4-branch ternary
215
+ // that collapsed classified / digital-code / live / art / stickers all
216
+ // down to "standard", so five of nine types displayed the wrong badge
217
+ // in the seller table (2026-08-21).
218
+ const kind = lt;
216
219
  const priceRaw = typeof item.price === "number" ? item.price : 0;
217
220
  const auctionSecondary = kind === "auction"
218
221
  ? [
@@ -85,7 +85,7 @@ export async function getStoreReviews(storeSlug) {
85
85
  const publishedProducts = allProducts
86
86
  .filter((p) => p.status === ProductStatusValues.PUBLISHED)
87
87
  .slice(0, 20);
88
- const reviewArrays = await Promise.all(publishedProducts.map((p) => reviewRepository.findApprovedByProduct(p.id)));
88
+ const reviewArrays = await Promise.all(publishedProducts.map((p) => reviewRepository.findApprovedByProduct(p.id, 50)));
89
89
  const allReviews = reviewArrays
90
90
  .flat()
91
91
  .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
@@ -0,0 +1,21 @@
1
+ import React from "react";
2
+ type SearchParams = Record<string, string | string[]>;
3
+ export interface StoreArtStickersPageViewProps {
4
+ storeSlug: string;
5
+ searchParams?: SearchParams;
6
+ }
7
+ /**
8
+ * A store's combined Art & Stickers tab.
9
+ *
10
+ * This page did not exist until 2026-08-21: `STORE_PAGE_TABS` had an
11
+ * "Art & Stickers" entry with a real count query behind it, but its href
12
+ * pointed at `STORE_PRODUCTS` — a page that filters `listingType == standard`.
13
+ * So the tab advertised a non-zero count and then rendered none of those items,
14
+ * with no error. Same shape as the category/brand tabs that rendered blank
15
+ * panels (see `audit-tab-body-coverage.mjs`), one level up.
16
+ *
17
+ * Mirrors the public `/art` page in spanning both types at once, since neither
18
+ * has enough inventory to justify a tab of its own.
19
+ */
20
+ export declare function StoreArtStickersPageView({ storeSlug, searchParams, }: StoreArtStickersPageViewProps): Promise<React.JSX.Element | null>;
21
+ export {};
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { PRODUCT_FIELDS } from "../../../constants/field-names";
3
+ import { sortBy } from "../../../constants/sort";
4
+ import { listStoreProducts } from "../../../_internal/server/features/products/list-public";
5
+ import { ART_STICKERS_LISTING_TYPES } from "../../products/constants/listing-tabs";
6
+ import { getStoreBySlug } from "./StoreDetailLayoutView";
7
+ import { StoreProductsListing } from "./StoreProductsListing";
8
+ const DEFAULT_PAGE_SIZE = 24;
9
+ const DEFAULT_SORT = sortBy(PRODUCT_FIELDS.CREATED_AT);
10
+ /**
11
+ * A store's combined Art & Stickers tab.
12
+ *
13
+ * This page did not exist until 2026-08-21: `STORE_PAGE_TABS` had an
14
+ * "Art & Stickers" entry with a real count query behind it, but its href
15
+ * pointed at `STORE_PRODUCTS` — a page that filters `listingType == standard`.
16
+ * So the tab advertised a non-zero count and then rendered none of those items,
17
+ * with no error. Same shape as the category/brand tabs that rendered blank
18
+ * panels (see `audit-tab-body-coverage.mjs`), one level up.
19
+ *
20
+ * Mirrors the public `/art` page in spanning both types at once, since neither
21
+ * has enough inventory to justify a tab of its own.
22
+ */
23
+ export async function StoreArtStickersPageView({ storeSlug, searchParams, }) {
24
+ const store = await getStoreBySlug(storeSlug);
25
+ const storeId = store?.id;
26
+ if (typeof storeId !== "string" || !storeId)
27
+ return null;
28
+ const result = await listStoreProducts(storeId, ART_STICKERS_LISTING_TYPES, searchParams ?? {}, { pageSize: DEFAULT_PAGE_SIZE, sorts: DEFAULT_SORT });
29
+ return (_jsx(StoreProductsListing, { storeId: storeId, listingTypes: ART_STICKERS_LISTING_TYPES, initialData: result ?? undefined }));
30
+ }
@@ -12,19 +12,13 @@ import { AuctionFilters } from "../../auctions/components/AuctionFilters";
12
12
  import { getDefaultCurrency } from "../../../core/baseline-resolver";
13
13
  import { useGuestWishlist } from "../../wishlist/hooks/useGuestWishlist";
14
14
  import { pushWishlistOp } from "../../cart/utils/pending-ops";
15
- import { PRODUCT_FIELDS } from "../../../constants/field-names";
16
- import { sortBy } from "../../../constants/sort";
15
+ import { AUCTION_PUBLIC_SORT_OPTIONS } from "../../products/constants/sieve";
17
16
  const __P = {
18
17
  p3: "p-[var(--appkit-space-3)]",
19
18
  };
20
- const DEFAULT_SORT = sortBy(PRODUCT_FIELDS.AUCTION_END_DATE, "ASC");
21
- const AUCTION_SORT_OPTIONS = [
22
- { value: sortBy(PRODUCT_FIELDS.AUCTION_END_DATE, "ASC"), label: "Ending Soonest" },
23
- { value: sortBy(PRODUCT_FIELDS.AUCTION_END_DATE), label: "Ending Latest" },
24
- { value: sortBy(PRODUCT_FIELDS.CURRENT_BID), label: "Highest Bid" },
25
- { value: sortBy(PRODUCT_FIELDS.PRICE, "ASC"), label: "Price: Low to High" },
26
- { value: sortBy(PRODUCT_FIELDS.PRICE), label: "Price: High to Low" },
27
- ];
19
+ // Shared with /auctions — a local copy here drifted ("Ending Soonest" vs
20
+ // "Ending Soon", and it silently omitted Most Bids / Buy It Now).
21
+ const DEFAULT_SORT = AUCTION_PUBLIC_SORT_OPTIONS[0].value;
28
22
  const FILTER_KEYS = ["minBid", "maxBid", "dateFrom", "dateTo"];
29
23
  export function StoreAuctionsListing({ storeId, initialData }) {
30
24
  const table = useUrlTable({ defaults: { pageSize: "24", sort: DEFAULT_SORT } });
@@ -106,7 +100,7 @@ export function StoreAuctionsListing({ storeId, initialData }) {
106
100
  isWishlisted: (productId) => wishlistedIds.has(productId),
107
101
  };
108
102
  const gridClass = "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-[var(--appkit-space-4)]";
109
- return (_jsxs(Div, { className: "min-h-[200px]", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search store auctions...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: AUCTION_SORT_OPTIONS, onSortChange: (v) => {
103
+ return (_jsxs(Div, { className: "min-h-[200px]", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search store auctions...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: AUCTION_PUBLIC_SORT_OPTIONS, onSortChange: (v) => {
110
104
  table.set("sort", v);
111
105
  }, view: view, onViewChange: (v) => {
112
106
  if (v === "table")
@@ -1,5 +1,8 @@
1
1
  import React from "react";
2
+ type SearchParams = Record<string, string | string[]>;
2
3
  export interface StoreAuctionsPageViewProps {
3
4
  storeSlug: string;
5
+ searchParams?: SearchParams;
4
6
  }
5
- export declare function StoreAuctionsPageView({ storeSlug }: StoreAuctionsPageViewProps): Promise<React.JSX.Element | null>;
7
+ export declare function StoreAuctionsPageView({ storeSlug, searchParams }: StoreAuctionsPageViewProps): Promise<React.JSX.Element | null>;
8
+ export {};
@@ -1,24 +1,24 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { sieveFilter, sieveAnd, SIEVE_OP } from "@mohasinac/appkit";
3
- import { sortBy } from "@mohasinac/appkit";
4
- import { productRepository } from "../../../repositories";
2
+ import { PRODUCT_FIELDS } from "../../../constants/field-names";
3
+ import { sortBy } from "../../../constants/sort";
4
+ import { listStoreProducts } from "../../../_internal/server/features/products/list-public";
5
5
  import { getStoreBySlug } from "./StoreDetailLayoutView";
6
6
  import { StoreAuctionsListing } from "./StoreAuctionsListing";
7
- export async function StoreAuctionsPageView({ storeSlug }) {
7
+ const LISTING_TYPES = ["auction"];
8
+ const DEFAULT_PAGE_SIZE = 24;
9
+ const DEFAULT_SORT = sortBy(PRODUCT_FIELDS.AUCTION_END_DATE, "ASC");
10
+ export async function StoreAuctionsPageView({ storeSlug, searchParams }) {
8
11
  const store = await getStoreBySlug(storeSlug);
9
12
  const storeId = store?.id;
10
- const result = storeId
11
- ? await productRepository
12
- .list({
13
- filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("listingType", SIEVE_OP.EQ, "auction")),
14
- sorts: sortBy("auctionEndDate", "ASC"),
15
- page: 1,
16
- pageSize: 24,
17
- })
18
- .catch(() => null)
19
- : null;
20
- if (!storeId) {
13
+ if (typeof storeId !== "string" || !storeId)
21
14
  return null;
22
- }
23
- return (_jsx(StoreAuctionsListing, { storeId: storeId, initialData: result ?? undefined }));
15
+ // Shared query — see listStoreProducts. This view used to call
16
+ // productRepository.list() with an inline filter string and swallow every
17
+ // failure via a bare .catch(() => null), so a missing index rendered as an
18
+ // empty store tab with nothing logged (Root Cause #30's family).
19
+ const result = await listStoreProducts(storeId, LISTING_TYPES, searchParams ?? {}, {
20
+ pageSize: DEFAULT_PAGE_SIZE,
21
+ sorts: DEFAULT_SORT,
22
+ });
23
+ return _jsx(StoreAuctionsListing, { storeId: storeId, initialData: result ?? undefined });
24
24
  }
@@ -37,6 +37,13 @@ export function StoreClassifiedsListing({ storeId, initialData }) {
37
37
  perPage: table.getNumber("pageSize", 24),
38
38
  storeId: storeId || undefined,
39
39
  listingType: "classified",
40
+ // Per-type facets — declared in FILTER_KEYS (so they counted toward the
41
+ // filter badge) and rendered in the drawer, but never sent until 2026-08-21.
42
+ typeFacets: {
43
+ [TABLE_KEYS.CITY]: table.get(TABLE_KEYS.CITY),
44
+ [TABLE_KEYS.NEGOTIABLE]: table.get(TABLE_KEYS.NEGOTIABLE),
45
+ [TABLE_KEYS.ACCEPTS_SHIPPING]: table.get(TABLE_KEYS.ACCEPTS_SHIPPING),
46
+ },
40
47
  };
41
48
  const { products, totalPages, page, isLoading } = useProducts(params, { initialData });
42
49
  const gridClass = "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-[var(--appkit-space-4)]";
@@ -1,5 +1,8 @@
1
1
  import React from "react";
2
+ type SearchParams = Record<string, string | string[]>;
2
3
  export interface StoreClassifiedsPageViewProps {
3
4
  storeSlug: string;
5
+ searchParams?: SearchParams;
4
6
  }
5
- export declare function StoreClassifiedsPageView({ storeSlug }: StoreClassifiedsPageViewProps): Promise<React.JSX.Element | null>;
7
+ export declare function StoreClassifiedsPageView({ storeSlug, searchParams }: StoreClassifiedsPageViewProps): Promise<React.JSX.Element | null>;
8
+ export {};
@@ -1,20 +1,24 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { sieveFilter, sieveAnd, SIEVE_OP, sortBy, PRODUCT_FIELDS } from "@mohasinac/appkit";
3
- import { productRepository } from "../../../repositories";
2
+ import { PRODUCT_FIELDS } from "../../../constants/field-names";
3
+ import { sortBy } from "../../../constants/sort";
4
+ import { listStoreProducts } from "../../../_internal/server/features/products/list-public";
4
5
  import { getStoreBySlug } from "./StoreDetailLayoutView";
5
6
  import { StoreClassifiedsListing } from "./StoreClassifiedsListing";
6
- export async function StoreClassifiedsPageView({ storeSlug }) {
7
+ const LISTING_TYPES = ["classified"];
8
+ const DEFAULT_PAGE_SIZE = 24;
9
+ const DEFAULT_SORT = sortBy(PRODUCT_FIELDS.CREATED_AT);
10
+ export async function StoreClassifiedsPageView({ storeSlug, searchParams }) {
7
11
  const store = await getStoreBySlug(storeSlug);
8
12
  const storeId = store?.id;
9
- if (!storeId)
13
+ if (typeof storeId !== "string" || !storeId)
10
14
  return null;
11
- const result = await productRepository
12
- .list({
13
- filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("listingType", SIEVE_OP.EQ, "classified")),
14
- sorts: sortBy(PRODUCT_FIELDS.CREATED_AT),
15
- page: 1,
16
- pageSize: 24,
17
- })
18
- .catch(() => null);
15
+ // Shared query see listStoreProducts. This view used to call
16
+ // productRepository.list() with an inline filter string and swallow every
17
+ // failure via a bare .catch(() => null), so a missing index rendered as an
18
+ // empty store tab with nothing logged (Root Cause #30's family).
19
+ const result = await listStoreProducts(storeId, LISTING_TYPES, searchParams ?? {}, {
20
+ pageSize: DEFAULT_PAGE_SIZE,
21
+ sorts: DEFAULT_SORT,
22
+ });
19
23
  return _jsx(StoreClassifiedsListing, { storeId: storeId, initialData: result ?? undefined });
20
24
  }
@@ -18,9 +18,10 @@ const STORE_LISTING_HREF = {
18
18
  classifieds: (slug) => String(ROUTES.PUBLIC.STORE_CLASSIFIEDS(slug)),
19
19
  "digital-codes": (slug) => String(ROUTES.PUBLIC.STORE_DIGITAL_CODES(slug)),
20
20
  live: (slug) => String(ROUTES.PUBLIC.STORE_LIVE(slug)),
21
- // Art & Stickers has no dedicated storefront tab page browsable
22
- // (alongside everything else the store sells) on the "Products" tab.
23
- art: (slug) => String(ROUTES.PUBLIC.STORE_PRODUCTS(slug)),
21
+ // Combined art + stickers, mirroring the public /art page. This used to
22
+ // point at STORE_PRODUCTS, which filters to `standard` — so the tab showed
23
+ // a real non-zero count and landed on a page with none of those items.
24
+ art: (slug) => String(ROUTES.PUBLIC.STORE_ART(slug)),
24
25
  };
25
26
  export const getStoreBySlug = cache((slug) => storeRepository.findBySlug(slug).catch(() => undefined));
26
27
  function tabLabel(base, count) {
@@ -37,6 +37,11 @@ export function StoreDigitalCodesListing({ storeId, initialData }) {
37
37
  perPage: table.getNumber("pageSize", 24),
38
38
  storeId: storeId || undefined,
39
39
  listingType: "digital-code",
40
+ // Per-type facets — declared in FILTER_KEYS (so they counted toward the
41
+ // filter badge) and rendered in the drawer, but never sent until 2026-08-21.
42
+ typeFacets: {
43
+ [TABLE_KEYS.DELIVERY_METHOD]: table.get(TABLE_KEYS.DELIVERY_METHOD),
44
+ },
40
45
  };
41
46
  const { products, totalPages, page, isLoading } = useProducts(params, { initialData });
42
47
  const gridClass = "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-[var(--appkit-space-4)]";
@@ -1,5 +1,8 @@
1
1
  import React from "react";
2
+ type SearchParams = Record<string, string | string[]>;
2
3
  export interface StoreDigitalCodesPageViewProps {
3
4
  storeSlug: string;
5
+ searchParams?: SearchParams;
4
6
  }
5
- export declare function StoreDigitalCodesPageView({ storeSlug }: StoreDigitalCodesPageViewProps): Promise<React.JSX.Element | null>;
7
+ export declare function StoreDigitalCodesPageView({ storeSlug, searchParams }: StoreDigitalCodesPageViewProps): Promise<React.JSX.Element | null>;
8
+ export {};
@@ -1,20 +1,24 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { sieveFilter, sieveAnd, SIEVE_OP, sortBy, PRODUCT_FIELDS } from "@mohasinac/appkit";
3
- import { productRepository } from "../../../repositories";
2
+ import { PRODUCT_FIELDS } from "../../../constants/field-names";
3
+ import { sortBy } from "../../../constants/sort";
4
+ import { listStoreProducts } from "../../../_internal/server/features/products/list-public";
4
5
  import { getStoreBySlug } from "./StoreDetailLayoutView";
5
6
  import { StoreDigitalCodesListing } from "./StoreDigitalCodesListing";
6
- export async function StoreDigitalCodesPageView({ storeSlug }) {
7
+ const LISTING_TYPES = ["digital-code"];
8
+ const DEFAULT_PAGE_SIZE = 24;
9
+ const DEFAULT_SORT = sortBy(PRODUCT_FIELDS.CREATED_AT);
10
+ export async function StoreDigitalCodesPageView({ storeSlug, searchParams }) {
7
11
  const store = await getStoreBySlug(storeSlug);
8
12
  const storeId = store?.id;
9
- if (!storeId)
13
+ if (typeof storeId !== "string" || !storeId)
10
14
  return null;
11
- const result = await productRepository
12
- .list({
13
- filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("listingType", SIEVE_OP.EQ, "digital-code")),
14
- sorts: sortBy(PRODUCT_FIELDS.CREATED_AT),
15
- page: 1,
16
- pageSize: 24,
17
- })
18
- .catch(() => null);
15
+ // Shared query see listStoreProducts. This view used to call
16
+ // productRepository.list() with an inline filter string and swallow every
17
+ // failure via a bare .catch(() => null), so a missing index rendered as an
18
+ // empty store tab with nothing logged (Root Cause #30's family).
19
+ const result = await listStoreProducts(storeId, LISTING_TYPES, searchParams ?? {}, {
20
+ pageSize: DEFAULT_PAGE_SIZE,
21
+ sorts: DEFAULT_SORT,
22
+ });
19
23
  return _jsx(StoreDigitalCodesListing, { storeId: storeId, initialData: result ?? undefined });
20
24
  }
@@ -37,6 +37,13 @@ export function StoreLiveItemsListing({ storeId, initialData }) {
37
37
  perPage: table.getNumber("pageSize", 24),
38
38
  storeId: storeId || undefined,
39
39
  listingType: "live",
40
+ // Per-type facets — declared in FILTER_KEYS (so they counted toward the
41
+ // filter badge) and rendered in the drawer, but never sent until 2026-08-21.
42
+ typeFacets: {
43
+ [TABLE_KEYS.SPECIES]: table.get(TABLE_KEYS.SPECIES),
44
+ [TABLE_KEYS.LIVE_SEX]: table.get(TABLE_KEYS.LIVE_SEX),
45
+ [TABLE_KEYS.JURISDICTION]: table.get(TABLE_KEYS.JURISDICTION),
46
+ },
40
47
  };
41
48
  const { products, totalPages, page, isLoading } = useProducts(params, { initialData });
42
49
  const gridClass = "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-[var(--appkit-space-4)]";
@@ -1,5 +1,8 @@
1
1
  import React from "react";
2
+ type SearchParams = Record<string, string | string[]>;
2
3
  export interface StoreLiveItemsPageViewProps {
3
4
  storeSlug: string;
5
+ searchParams?: SearchParams;
4
6
  }
5
- export declare function StoreLiveItemsPageView({ storeSlug }: StoreLiveItemsPageViewProps): Promise<React.JSX.Element | null>;
7
+ export declare function StoreLiveItemsPageView({ storeSlug, searchParams }: StoreLiveItemsPageViewProps): Promise<React.JSX.Element | null>;
8
+ export {};
@@ -1,20 +1,24 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { sieveFilter, sieveAnd, SIEVE_OP, sortBy, PRODUCT_FIELDS } from "@mohasinac/appkit";
3
- import { productRepository } from "../../../repositories";
2
+ import { PRODUCT_FIELDS } from "../../../constants/field-names";
3
+ import { sortBy } from "../../../constants/sort";
4
+ import { listStoreProducts } from "../../../_internal/server/features/products/list-public";
4
5
  import { getStoreBySlug } from "./StoreDetailLayoutView";
5
6
  import { StoreLiveItemsListing } from "./StoreLiveItemsListing";
6
- export async function StoreLiveItemsPageView({ storeSlug }) {
7
+ const LISTING_TYPES = ["live"];
8
+ const DEFAULT_PAGE_SIZE = 24;
9
+ const DEFAULT_SORT = sortBy(PRODUCT_FIELDS.CREATED_AT);
10
+ export async function StoreLiveItemsPageView({ storeSlug, searchParams }) {
7
11
  const store = await getStoreBySlug(storeSlug);
8
12
  const storeId = store?.id;
9
- if (!storeId)
13
+ if (typeof storeId !== "string" || !storeId)
10
14
  return null;
11
- const result = await productRepository
12
- .list({
13
- filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("listingType", SIEVE_OP.EQ, "live")),
14
- sorts: sortBy(PRODUCT_FIELDS.CREATED_AT),
15
- page: 1,
16
- pageSize: 24,
17
- })
18
- .catch(() => null);
15
+ // Shared query see listStoreProducts. This view used to call
16
+ // productRepository.list() with an inline filter string and swallow every
17
+ // failure via a bare .catch(() => null), so a missing index rendered as an
18
+ // empty store tab with nothing logged (Root Cause #30's family).
19
+ const result = await listStoreProducts(storeId, LISTING_TYPES, searchParams ?? {}, {
20
+ pageSize: DEFAULT_PAGE_SIZE,
21
+ sorts: DEFAULT_SORT,
22
+ });
19
23
  return _jsx(StoreLiveItemsListing, { storeId: storeId, initialData: result ?? undefined });
20
24
  }
@@ -8,19 +8,14 @@ import { Div, FilterDrawer, ListingToolbar, Pagination, Row, Stack, Text, Sticky
8
8
  import { MarketplacePreorderCard } from "../../pre-orders/components/MarketplacePreorderCard";
9
9
  import { ProductFilters } from "../../products/components/ProductFilters";
10
10
  import { ROUTES } from "../../../next";
11
- import { PRODUCT_FIELDS } from "../../../constants/field-names";
12
- import { sortBy } from "../../../constants/sort";
11
+ import { PREORDER_PUBLIC_SORT_OPTIONS } from "../../products/constants/sieve";
13
12
  const __P = {
14
13
  p3: "p-[var(--appkit-space-3)]",
15
14
  };
16
- const DEFAULT_SORT = sortBy(PRODUCT_FIELDS.CREATED_AT);
17
- const PREORDER_SORT_OPTIONS = [
18
- { value: sortBy(PRODUCT_FIELDS.CREATED_AT), label: "Newest First" },
19
- { value: sortBy(PRODUCT_FIELDS.CREATED_AT, "ASC"), label: "Oldest First" },
20
- { value: sortBy(PRODUCT_FIELDS.PRE_ORDER_DELIVERY_DATE, "ASC"), label: "Delivery Soon" },
21
- { value: sortBy(PRODUCT_FIELDS.PRICE, "ASC"), label: "Price: Low to High" },
22
- { value: sortBy(PRODUCT_FIELDS.PRICE), label: "Price: High to Low" },
23
- ];
15
+ // Shared with /pre-orders. The local copy also defaulted to -createdAt,
16
+ // so a store tab opened Newest-first while the public page opened
17
+ // Earliest-Delivery-first for the same data.
18
+ const DEFAULT_SORT = PREORDER_PUBLIC_SORT_OPTIONS[0].value;
24
19
  const FILTER_KEYS = ["minPrice", "maxPrice"];
25
20
  export function StorePreOrdersListing({ storeId, initialData }) {
26
21
  const table = useUrlTable({ defaults: { pageSize: "24", sort: DEFAULT_SORT } });
@@ -59,7 +54,7 @@ export function StorePreOrdersListing({ storeId, initialData }) {
59
54
  table.set("q", searchInput.trim());
60
55
  }, [searchInput, table]);
61
56
  const gridClass = "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-[var(--appkit-space-4)]";
62
- return (_jsxs(Div, { className: "min-h-[200px]", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search store pre-orders...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: PREORDER_SORT_OPTIONS, onSortChange: (v) => {
57
+ return (_jsxs(Div, { className: "min-h-[200px]", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search store pre-orders...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: PREORDER_PUBLIC_SORT_OPTIONS, onSortChange: (v) => {
63
58
  table.set("sort", v);
64
59
  }, view: view, onViewChange: (v) => {
65
60
  if (v === "table")
@@ -1,5 +1,8 @@
1
1
  import React from "react";
2
+ type SearchParams = Record<string, string | string[]>;
2
3
  export interface StorePreOrdersPageViewProps {
3
4
  storeSlug: string;
5
+ searchParams?: SearchParams;
4
6
  }
5
- export declare function StorePreOrdersPageView({ storeSlug }: StorePreOrdersPageViewProps): Promise<React.JSX.Element | null>;
7
+ export declare function StorePreOrdersPageView({ storeSlug, searchParams }: StorePreOrdersPageViewProps): Promise<React.JSX.Element | null>;
8
+ export {};
@@ -1,24 +1,24 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { sieveFilter, sieveAnd, SIEVE_OP } from "@mohasinac/appkit";
3
- import { sortBy } from "@mohasinac/appkit";
4
- import { productRepository } from "../../../repositories";
2
+ import { PRODUCT_FIELDS } from "../../../constants/field-names";
3
+ import { sortBy } from "../../../constants/sort";
4
+ import { listStoreProducts } from "../../../_internal/server/features/products/list-public";
5
5
  import { getStoreBySlug } from "./StoreDetailLayoutView";
6
6
  import { StorePreOrdersListing } from "./StorePreOrdersListing";
7
- export async function StorePreOrdersPageView({ storeSlug }) {
7
+ const LISTING_TYPES = ["pre-order"];
8
+ const DEFAULT_PAGE_SIZE = 24;
9
+ const DEFAULT_SORT = sortBy(PRODUCT_FIELDS.PRE_ORDER_DELIVERY_DATE, "ASC");
10
+ export async function StorePreOrdersPageView({ storeSlug, searchParams }) {
8
11
  const store = await getStoreBySlug(storeSlug);
9
12
  const storeId = store?.id;
10
- const result = storeId
11
- ? await productRepository
12
- .list({
13
- filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("listingType", SIEVE_OP.EQ, "pre-order")),
14
- sorts: sortBy("createdAt", "DESC"),
15
- page: 1,
16
- pageSize: 24,
17
- })
18
- .catch(() => null)
19
- : null;
20
- if (!storeId) {
13
+ if (typeof storeId !== "string" || !storeId)
21
14
  return null;
22
- }
23
- return (_jsx(StorePreOrdersListing, { storeId: storeId, initialData: result ?? undefined }));
15
+ // Shared query — see listStoreProducts. This view used to call
16
+ // productRepository.list() with an inline filter string and swallow every
17
+ // failure via a bare .catch(() => null), so a missing index rendered as an
18
+ // empty store tab with nothing logged (Root Cause #30's family).
19
+ const result = await listStoreProducts(storeId, LISTING_TYPES, searchParams ?? {}, {
20
+ pageSize: DEFAULT_PAGE_SIZE,
21
+ sorts: DEFAULT_SORT,
22
+ });
23
+ return _jsx(StorePreOrdersListing, { storeId: storeId, initialData: result ?? undefined });
24
24
  }
@@ -1,12 +1,8 @@
1
1
  import React from "react";
2
+ type SearchParams = Record<string, string | string[]>;
2
3
  export interface StorePrizeDrawsPageViewProps {
3
4
  storeSlug: string;
5
+ searchParams?: SearchParams;
4
6
  }
5
- /**
6
- * Public store → Prize Draws tab (SB7-D).
7
- *
8
- * Server-fetches the seller's prize-draw products and hands them to the
9
- * client `PrizeDrawsIndexListing` scoped to this store. Mirrors the
10
- * StorePreOrdersPageView pattern.
11
- */
12
- export declare function StorePrizeDrawsPageView({ storeSlug, }: StorePrizeDrawsPageViewProps): Promise<React.JSX.Element | null>;
7
+ export declare function StorePrizeDrawsPageView({ storeSlug, searchParams }: StorePrizeDrawsPageViewProps): Promise<React.JSX.Element | null>;
8
+ export {};
@@ -1,29 +1,24 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { sieveFilter, sieveAnd, SIEVE_OP } from "@mohasinac/appkit";
3
- import { sortBy } from "@mohasinac/appkit";
4
- import { productRepository } from "../../../repositories";
2
+ import { PRODUCT_FIELDS } from "../../../constants/field-names";
3
+ import { sortBy } from "../../../constants/sort";
4
+ import { listStoreProducts } from "../../../_internal/server/features/products/list-public";
5
5
  import { getStoreBySlug } from "./StoreDetailLayoutView";
6
6
  import { PrizeDrawsIndexListing } from "../../products/components/PrizeDrawsIndexListing";
7
- /**
8
- * Public store → Prize Draws tab (SB7-D).
9
- *
10
- * Server-fetches the seller's prize-draw products and hands them to the
11
- * client `PrizeDrawsIndexListing` scoped to this store. Mirrors the
12
- * StorePreOrdersPageView pattern.
13
- */
14
- export async function StorePrizeDrawsPageView({ storeSlug, }) {
7
+ const LISTING_TYPES = ["prize-draw"];
8
+ const DEFAULT_PAGE_SIZE = 24;
9
+ const DEFAULT_SORT = sortBy(PRODUCT_FIELDS.CREATED_AT);
10
+ export async function StorePrizeDrawsPageView({ storeSlug, searchParams }) {
15
11
  const store = await getStoreBySlug(storeSlug);
16
12
  const storeId = store?.id;
17
- if (!storeId) {
13
+ if (typeof storeId !== "string" || !storeId)
18
14
  return null;
19
- }
20
- const result = await productRepository
21
- .list({
22
- filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("listingType", SIEVE_OP.EQ, "prize-draw")),
23
- sorts: sortBy("createdAt", "DESC"),
24
- page: 1,
25
- pageSize: 24,
26
- })
27
- .catch(() => null);
28
- return (_jsx(PrizeDrawsIndexListing, { storeId: storeId, initialData: result ?? undefined }));
15
+ // Shared query — see listStoreProducts. This view used to call
16
+ // productRepository.list() with an inline filter string and swallow every
17
+ // failure via a bare .catch(() => null), so a missing index rendered as an
18
+ // empty store tab with nothing logged (Root Cause #30's family).
19
+ const result = await listStoreProducts(storeId, LISTING_TYPES, searchParams ?? {}, {
20
+ pageSize: DEFAULT_PAGE_SIZE,
21
+ sorts: DEFAULT_SORT,
22
+ });
23
+ return _jsx(PrizeDrawsIndexListing, { storeId: storeId, initialData: result ?? undefined });
29
24
  }
@@ -2,6 +2,12 @@ import React from "react";
2
2
  export interface StoreProductsListingProps {
3
3
  /** Store document ID — used for filtering */
4
4
  storeId?: string;
5
+ /**
6
+ * Listing types this tab spans. Defaults to `["standard"]`. The combined
7
+ * Art & Stickers store tab passes both of its types so it renders real
8
+ * content instead of the standard-only set it used to land on.
9
+ */
10
+ listingTypes?: readonly string[];
5
11
  initialData?: any;
6
12
  }
7
- export declare function StoreProductsListing({ storeId, initialData }: StoreProductsListingProps): React.JSX.Element;
13
+ export declare function StoreProductsListing({ storeId, listingTypes, initialData }: StoreProductsListingProps): React.JSX.Element;