@mohasinac/appkit 2.8.3 → 2.8.4

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 (171) hide show
  1. package/dist/client.d.ts +2 -0
  2. package/dist/client.js +2 -0
  3. package/dist/core/hooks/useSiteSettings.d.ts +1 -1
  4. package/dist/features/account/hooks/useAccount.d.ts +2 -2
  5. package/dist/features/account/hooks/useAddressSelector.d.ts +1 -1
  6. package/dist/features/account/hooks/useAddresses.d.ts +2 -2
  7. package/dist/features/account/hooks/useNotifications.d.ts +1 -1
  8. package/dist/features/account/hooks/useProfile.d.ts +1 -1
  9. package/dist/features/account/hooks/usePublicProfile.d.ts +2 -2
  10. package/dist/features/admin/components/AdminAllEventEntriesView.js +5 -3
  11. package/dist/features/admin/components/AdminBidsView.js +6 -4
  12. package/dist/features/admin/components/AdminBlogView.js +6 -4
  13. package/dist/features/admin/components/AdminBrandsView.js +8 -6
  14. package/dist/features/admin/components/AdminBundlesView.js +10 -8
  15. package/dist/features/admin/components/AdminCartsView.js +6 -4
  16. package/dist/features/admin/components/AdminCategoriesView.js +7 -5
  17. package/dist/features/admin/components/AdminClassifiedView.js +4 -3
  18. package/dist/features/admin/components/AdminContactView.js +6 -4
  19. package/dist/features/admin/components/AdminCouponsView.js +6 -4
  20. package/dist/features/admin/components/AdminDigitalCodesView.js +4 -3
  21. package/dist/features/admin/components/AdminFaqsView.js +5 -3
  22. package/dist/features/admin/components/AdminFeaturesView.js +5 -4
  23. package/dist/features/admin/components/AdminGroupedListingsView.js +4 -3
  24. package/dist/features/admin/components/AdminHistoryView.js +4 -3
  25. package/dist/features/admin/components/AdminLiveView.js +4 -3
  26. package/dist/features/admin/components/AdminNewsletterView.js +5 -3
  27. package/dist/features/admin/components/AdminNotificationsView.js +6 -4
  28. package/dist/features/admin/components/AdminOrdersView.js +6 -4
  29. package/dist/features/admin/components/AdminPayoutsView.js +7 -5
  30. package/dist/features/admin/components/AdminPrizeDrawsView.js +6 -4
  31. package/dist/features/admin/components/AdminProductsView.js +7 -5
  32. package/dist/features/admin/components/AdminReturnRequestsView.js +4 -3
  33. package/dist/features/admin/components/AdminReviewsView.js +8 -6
  34. package/dist/features/admin/components/AdminScammersView.js +8 -6
  35. package/dist/features/admin/components/AdminSessionsView.js +6 -4
  36. package/dist/features/admin/components/AdminStoreAddressesView.js +2 -1
  37. package/dist/features/admin/components/AdminStoresView.js +6 -4
  38. package/dist/features/admin/components/AdminSublistingCategoriesView.js +6 -5
  39. package/dist/features/admin/components/AdminSupportTicketsView.js +8 -6
  40. package/dist/features/admin/components/AdminTeamView.js +6 -4
  41. package/dist/features/admin/components/AdminUsersView.js +6 -4
  42. package/dist/features/admin/components/AdminWishlistsView.js +4 -3
  43. package/dist/features/admin/constants/filter-tabs.d.ts +1 -1
  44. package/dist/features/admin/constants/filter-tabs.js +0 -11
  45. package/dist/features/admin/hooks/useAdmin.d.ts +1 -1
  46. package/dist/features/admin/hooks/useAdminSectionsListing.d.ts +1 -1
  47. package/dist/features/admin/hooks/useChat.d.ts +1 -1
  48. package/dist/features/admin/types/index.d.ts +1 -1
  49. package/dist/features/auctions/actions/bid-actions.js +4 -2
  50. package/dist/features/auctions/components/AuctionsListView.js +7 -6
  51. package/dist/features/auctions/hooks/useAuctions.d.ts +8 -8
  52. package/dist/features/auth/hooks/useAuth.d.ts +2 -2
  53. package/dist/features/blog/actions/blog-actions.js +3 -2
  54. package/dist/features/cart/hooks/useCart.d.ts +1 -1
  55. package/dist/features/cart/hooks/useCartQuery.d.ts +1 -1
  56. package/dist/features/cart/hooks/useCheckoutReadQueries.d.ts +2 -2
  57. package/dist/features/cart/hooks/useOrder.d.ts +2 -2
  58. package/dist/features/categories/components/BrandDetailPageView.js +10 -8
  59. package/dist/features/categories/components/CategoriesIndexListing.js +1 -1
  60. package/dist/features/categories/components/CategoriesIndexPageView.js +5 -4
  61. package/dist/features/categories/components/CategoryBundlesListing.js +5 -4
  62. package/dist/features/categories/components/CategoryDetailPageView.js +12 -10
  63. package/dist/features/categories/components/CategoryFilters.d.ts +12 -12
  64. package/dist/features/categories/components/CategoryFilters.js +13 -12
  65. package/dist/features/categories/components/CategoryTree.d.ts +1 -1
  66. package/dist/features/categories/components/CategoryTree.js +1 -1
  67. package/dist/features/categories/hooks/useCategories.d.ts +3 -3
  68. package/dist/features/categories/hooks/useCategorySelector.d.ts +3 -3
  69. package/dist/features/categories/hooks/useCategoryTree.d.ts +1 -1
  70. package/dist/features/categories/schemas/firestore.d.ts +2 -2
  71. package/dist/features/checkout/actions/checkout-actions.d.ts +1 -1
  72. package/dist/features/checkout/actions/checkout-actions.js +1 -1
  73. package/dist/features/checkout/hooks/useCheckoutApi.d.ts +2 -2
  74. package/dist/features/classified/components/ClassifiedListView.js +6 -5
  75. package/dist/features/collections/hooks/useCollections.d.ts +2 -2
  76. package/dist/features/cron/jobs/auction-expiry.job.d.ts +2 -2
  77. package/dist/features/cron/jobs/auction-expiry.job.js +2 -1
  78. package/dist/features/cron/jobs/preorder-reminder.job.d.ts +1 -1
  79. package/dist/features/cron/jobs/preorder-reminder.job.js +2 -1
  80. package/dist/features/digital-codes/components/DigitalCodesListView.js +4 -3
  81. package/dist/features/events/actions/event-actions.js +6 -4
  82. package/dist/features/events/components/AdminEventEditorView.js +1 -1
  83. package/dist/features/events/components/AdminEventsView.js +7 -5
  84. package/dist/features/events/components/EventFilters.d.ts +4 -4
  85. package/dist/features/events/components/EventFilters.js +2 -2
  86. package/dist/features/events/components/EventRafflesSection.js +4 -2
  87. package/dist/features/events/hooks/useEvent.d.ts +3 -3
  88. package/dist/features/events/hooks/useEvents.d.ts +1 -1
  89. package/dist/features/faq/actions/faq-actions.js +4 -2
  90. package/dist/features/faq/components/FAQPageContent.js +2 -1
  91. package/dist/features/faq/hooks/useFAQs.d.ts +1 -1
  92. package/dist/features/faq/hooks/useFaqList.d.ts +15 -15
  93. package/dist/features/homepage/components/MarketplaceHomepageView.js +4 -2
  94. package/dist/features/homepage/hooks/useBlogArticles.d.ts +1 -1
  95. package/dist/features/homepage/hooks/useFeaturedAuctions.d.ts +1 -1
  96. package/dist/features/homepage/hooks/useFeaturedPreOrders.d.ts +1 -1
  97. package/dist/features/homepage/hooks/useFeaturedProducts.d.ts +1 -1
  98. package/dist/features/homepage/hooks/useFeaturedStores.d.ts +1 -1
  99. package/dist/features/homepage/hooks/useHeroCarousel.d.ts +1 -1
  100. package/dist/features/homepage/hooks/useHomepageEvents.d.ts +1 -1
  101. package/dist/features/homepage/hooks/useHomepageReviews.d.ts +1 -1
  102. package/dist/features/homepage/hooks/useHomepageSections.d.ts +1 -1
  103. package/dist/features/homepage/hooks/useTopBrands.d.ts +1 -1
  104. package/dist/features/homepage/hooks/useTopCategories.d.ts +1 -1
  105. package/dist/features/layout/BottomActions.js +0 -27
  106. package/dist/features/layout/BottomActionsContext.d.ts +0 -36
  107. package/dist/features/layout/BottomActionsContext.js +0 -36
  108. package/dist/features/live/components/LiveItemsListView.js +6 -5
  109. package/dist/features/loyalty/hooks/useLoyaltyBalance.d.ts +1 -1
  110. package/dist/features/orders/hooks/useOrders.d.ts +2 -2
  111. package/dist/features/payments/hooks/usePayments.d.ts +1 -1
  112. package/dist/features/pre-orders/components/PreOrdersListView.js +5 -4
  113. package/dist/features/pre-orders/hooks/usePreOrders.d.ts +2 -2
  114. package/dist/features/products/actions/product-actions.js +17 -15
  115. package/dist/features/products/columns/index.d.ts +1 -1
  116. package/dist/features/products/columns/index.js +1 -1
  117. package/dist/features/products/components/PrizeDrawCollage.js +0 -14
  118. package/dist/features/products/components/PrizeDrawsListingView.js +5 -4
  119. package/dist/features/products/components/PrizeDrawsSection.js +4 -2
  120. package/dist/features/products/constants/sieve.d.ts +2 -2
  121. package/dist/features/products/constants/sieve.js +2 -2
  122. package/dist/features/products/hooks/useProductDetail.d.ts +1 -1
  123. package/dist/features/products/hooks/useRelatedProducts.d.ts +1 -1
  124. package/dist/features/products/hooks/useRelatedProducts.js +5 -4
  125. package/dist/features/promotions/hooks/usePromotions.d.ts +2 -2
  126. package/dist/features/reviews/actions/review-actions.js +2 -1
  127. package/dist/features/reviews/components/ReviewsIndexPageView.js +7 -6
  128. package/dist/features/reviews/hooks/useReviews.d.ts +2 -2
  129. package/dist/features/scams/actions/scam-actions.js +3 -2
  130. package/dist/features/scams/components/ScamRegistryView.js +5 -4
  131. package/dist/features/search/actions/search-actions.js +7 -6
  132. package/dist/features/search/hooks/useSearch.d.ts +2 -2
  133. package/dist/features/seller/components/CouponInlineSelect.js +2 -1
  134. package/dist/features/seller/components/SellerAuctionsView.js +7 -5
  135. package/dist/features/seller/components/SellerBidsView.js +5 -3
  136. package/dist/features/seller/components/SellerBundlesView.js +7 -6
  137. package/dist/features/seller/components/SellerClassifiedView.js +6 -5
  138. package/dist/features/seller/components/SellerCouponsView.js +6 -4
  139. package/dist/features/seller/components/SellerDigitalCodesView.js +5 -4
  140. package/dist/features/seller/components/SellerGroupedListingsView.js +5 -4
  141. package/dist/features/seller/components/SellerLiveView.js +6 -5
  142. package/dist/features/seller/components/SellerOffersView.js +6 -4
  143. package/dist/features/seller/components/SellerOrdersView.js +5 -3
  144. package/dist/features/seller/components/SellerPayoutMethodsView.js +3 -2
  145. package/dist/features/seller/components/SellerPayoutsView.js +6 -4
  146. package/dist/features/seller/components/SellerPreOrdersView.js +6 -4
  147. package/dist/features/seller/components/SellerPrizeDrawsView.js +6 -4
  148. package/dist/features/seller/components/SellerProductsView.js +9 -7
  149. package/dist/features/seller/components/SellerShippingConfigsView.js +3 -2
  150. package/dist/features/seller/components/SellerStoreCategoriesView.js +4 -3
  151. package/dist/features/seller/components/SellerTemplatesView.js +4 -3
  152. package/dist/features/seller/components/SublistingInlineSelect.js +2 -1
  153. package/dist/features/seller/hooks/useSellerPayouts.d.ts +3 -3
  154. package/dist/features/seller/hooks/useSellerStore.d.ts +6 -6
  155. package/dist/features/seller/hooks/useSellerStorefront.d.ts +2 -2
  156. package/dist/features/stores/actions/store-query-actions.js +3 -2
  157. package/dist/features/stores/components/StoreAuctionsPageView.js +4 -2
  158. package/dist/features/stores/components/StoreDetailLayoutView.d.ts +1 -1
  159. package/dist/features/stores/components/StoreDetailLayoutView.js +7 -6
  160. package/dist/features/stores/components/StorePreOrdersPageView.js +4 -2
  161. package/dist/features/stores/components/StorePrizeDrawsPageView.js +4 -2
  162. package/dist/features/stores/components/StoreProductsPageView.js +2 -1
  163. package/dist/features/stores/components/StoreProductsView.js +5 -4
  164. package/dist/features/stores/components/StoresIndexListing.js +4 -3
  165. package/dist/features/stores/hooks/useStoreAddressSelector.d.ts +1 -1
  166. package/dist/features/stores/hooks/useStores.d.ts +6 -6
  167. package/dist/features/wishlist/components/WishlistView.js +4 -3
  168. package/dist/features/wishlist/hooks/useUserWishlist.d.ts +15 -15
  169. package/dist/features/wishlist/hooks/useWishlist.d.ts +1 -1
  170. package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
  171. package/package.json +1 -1
@@ -1,41 +1,5 @@
1
1
  "use client";
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
- /**
4
- * BottomActionsContext
5
- *
6
- * Provides a context for registering page-level mobile action bars.
7
- * Features call `useBottomActions` to push actions; the `<BottomActions>`
8
- * layout component reads this context and renders the bar above BottomNavbar.
9
- *
10
- * Supports two modes:
11
- * - Page mode: primary page actions (Add to Cart, Buy Now, Place Bid, etc.)
12
- * - Bulk mode: activated when `bulk.selectedCount > 0` — shows selection
13
- * count + custom bulk action buttons (Delete, Archive, Export, etc.)
14
- *
15
- * @example — product detail page
16
- * ```tsx
17
- * useBottomActions({
18
- * actions: [
19
- * { id: "wishlist", icon: <Heart className="w-4 h-4" />, label: t("wishlist"), variant: "ghost", grow: false, onClick: handleWishlist },
20
- * { id: "cart", label: t("addToCart"), variant: "outline", onClick: handleAddToCart },
21
- * { id: "buy", label: t("buyNow"), variant: "primary", onClick: handleBuyNow },
22
- * ],
23
- * });
24
- * ```
25
- *
26
- * @example — admin listing with bulk select
27
- * ```tsx
28
- * useBottomActions({
29
- * bulk: {
30
- * selectedCount: selectedIds.length,
31
- * onClearSelection: () => setSelectedIds([]),
32
- * actions: [
33
- * { id: "delete", label: t("bulkDelete", { count: selectedIds.length }), variant: "danger", onClick: handleBulkDelete },
34
- * ],
35
- * },
36
- * });
37
- * ```
38
- */
39
3
  import { createContext, useCallback, useContext, useMemo, useRef, useState, } from "react";
40
4
  const EMPTY = { actions: [] };
41
5
  const BottomActionsContext = createContext(null);
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit";
2
3
  import { productRepository } from "../../../repositories";
3
4
  import { Container, Heading, Main, Section } from "../../../ui";
4
5
  import { AdSlot } from "../../homepage/components/AdSlot";
@@ -16,18 +17,18 @@ function buildLiveFilters(params) {
16
17
  const minPrice = sp(params, "minPrice");
17
18
  const maxPrice = sp(params, "maxPrice");
18
19
  if (minPrice)
19
- parts.push(`price>=${minPrice}`);
20
+ parts.push(sieveFilter("price", SIEVE_OP.GTE, minPrice));
20
21
  if (maxPrice)
21
- parts.push(`price<=${maxPrice}`);
22
+ parts.push(sieveFilter("price", SIEVE_OP.LTE, maxPrice));
22
23
  const species = sp(params, "species");
23
24
  if (species)
24
- parts.push(`liveSpecies==${species}`);
25
+ parts.push(sieveFilter("liveSpecies", SIEVE_OP.EQ, species));
25
26
  const liveSex = sp(params, "liveSex");
26
27
  if (liveSex)
27
- parts.push(`liveSex==${liveSex}`);
28
+ parts.push(sieveFilter("liveSex", SIEVE_OP.EQ, liveSex));
28
29
  const transport = sp(params, "liveTransportMethod");
29
30
  if (transport)
30
- parts.push(`liveTransportMethod==${transport}`);
31
+ parts.push(sieveFilter("liveTransportMethod", SIEVE_OP.EQ, transport));
31
32
  return parts.join(",");
32
33
  }
33
34
  export async function LiveItemsListView({ searchParams = {} }) {
@@ -1,4 +1,4 @@
1
1
  import type { LoyaltyBalance } from "../types";
2
2
  export declare function useLoyaltyBalance(uid: string | undefined, opts?: {
3
3
  endpoint?: string;
4
- }): import("@tanstack/react-query").UseQueryResult<NoInfer<LoyaltyBalance | null>, Error>;
4
+ }): import("@tanstack/react-query").UseQueryResult<LoyaltyBalance | null, Error>;
@@ -17,7 +17,7 @@ export declare function useOrder(id: string, opts?: {
17
17
  enabled?: boolean;
18
18
  endpoint?: string;
19
19
  }): {
20
- order: NoInfer<Order> | undefined;
20
+ order: Order | undefined;
21
21
  isLoading: boolean;
22
22
  error: Error | null;
23
23
  };
@@ -25,7 +25,7 @@ export declare function useTrackOrder(trackingId: string | null | undefined, opt
25
25
  enabled?: boolean;
26
26
  endpoint?: string;
27
27
  }): {
28
- trackingInfo: NonNullable<NoInfer<TrackingInfo | null>> | null;
28
+ trackingInfo: TrackingInfo | null;
29
29
  isLoading: boolean;
30
30
  error: Error | null;
31
31
  };
@@ -4,7 +4,7 @@ export declare function usePaymentSettings(opts?: {
4
4
  enabled?: boolean;
5
5
  endpoint?: string;
6
6
  }): {
7
- settings: NoInfer<PaymentSettings> | undefined;
7
+ settings: PaymentSettings | undefined;
8
8
  isLoading: boolean;
9
9
  error: Error | null;
10
10
  };
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit";
2
3
  import { productRepository } from "../../../repositories";
3
4
  import { Container, Main, Heading, Section } from "../../../ui";
4
5
  import { AdSlot } from "../../homepage/components/AdSlot";
@@ -16,15 +17,15 @@ function buildPreOrderFilters(params) {
16
17
  const minPrice = sp(params, "minPrice");
17
18
  const maxPrice = sp(params, "maxPrice");
18
19
  if (minPrice)
19
- parts.push(`price>=${minPrice}`);
20
+ parts.push(sieveFilter("price", SIEVE_OP.GTE, minPrice));
20
21
  if (maxPrice)
21
- parts.push(`price<=${maxPrice}`);
22
+ parts.push(sieveFilter("price", SIEVE_OP.LTE, maxPrice));
22
23
  const store = sp(params, "storeId");
23
24
  if (store)
24
- parts.push(`storeId==${store}`);
25
+ parts.push(sieveFilter("storeId", SIEVE_OP.EQ, store));
25
26
  const preOrderProductionStatus = sp(params, "preOrderProductionStatus");
26
27
  if (preOrderProductionStatus)
27
- parts.push(`preOrderProductionStatus==${preOrderProductionStatus}`);
28
+ parts.push(sieveFilter("preOrderProductionStatus", SIEVE_OP.EQ, preOrderProductionStatus));
28
29
  return parts.join(",");
29
30
  }
30
31
  export async function PreOrdersListView({ searchParams = {} }) {
@@ -1,7 +1,7 @@
1
1
  import type { PreorderItem } from "../types";
2
2
  export declare function usePreorders(opts?: {
3
3
  endpoint?: string;
4
- }): import("@tanstack/react-query").UseQueryResult<NoInfer<PreorderItem[]>, Error>;
4
+ }): import("@tanstack/react-query").UseQueryResult<PreorderItem[], Error>;
5
5
  export declare function usePreorder(slug: string | undefined, opts?: {
6
6
  endpoint?: string;
7
- }): import("@tanstack/react-query").UseQueryResult<NoInfer<PreorderItem | null>, Error>;
7
+ }): import("@tanstack/react-query").UseQueryResult<PreorderItem | null, Error>;
@@ -1,23 +1,25 @@
1
+ import { sieveAnd, sieveFilter, SIEVE_OP } from "@mohasinac/appkit";
2
+ import { sortBy } from "@mohasinac/appkit";
1
3
  import { productRepository } from "../repository/products.repository";
2
4
  import { ProductStatusValues } from "../schemas";
3
5
  /**
4
6
  * Reusable Sieve clauses. Single source of truth for the listing-type
5
7
  * discriminator across every action helper in this file. SB1-G (S21 2026-05-12)
6
- * routes everything through `listingType==X` — the legacy boolean flags are
8
+ * routes everything through sieveFilter("listingType", SIEVE_OP.EQ, "X") — the legacy boolean flags are
7
9
  * never emitted by code under our control any more.
8
10
  */
9
- const PUBLISHED_CLAUSE = "status==published";
10
- const AUCTIONS_PUBLISHED = `listingType==auction,${PUBLISHED_CLAUSE}`;
11
- const PREORDERS_PUBLISHED = `listingType==pre-order,${PUBLISHED_CLAUSE}`;
11
+ const PUBLISHED_CLAUSE = sieveFilter("status", SIEVE_OP.EQ, "published");
12
+ const AUCTIONS_PUBLISHED = sieveAnd(sieveFilter("listingType", SIEVE_OP.EQ, "auction"), PUBLISHED_CLAUSE);
13
+ const PREORDERS_PUBLISHED = sieveAnd(sieveFilter("listingType", SIEVE_OP.EQ, "pre-order"), PUBLISHED_CLAUSE);
12
14
  export async function listProducts(params = {}) {
13
15
  const { filters, sorts = "-createdAt", page = 1, pageSize = 20, listingType, featured, storeId, categoriesIn, } = params;
14
16
  const compoundFilters = [];
15
17
  if (listingType)
16
- compoundFilters.push(`listingType==${listingType}`);
18
+ compoundFilters.push(sieveFilter("listingType", SIEVE_OP.EQ, listingType));
17
19
  if (featured === true)
18
20
  compoundFilters.push("featured==true");
19
21
  if (storeId)
20
- compoundFilters.push(`storeId==${storeId}`);
22
+ compoundFilters.push(sieveFilter("storeId", SIEVE_OP.EQ, storeId));
21
23
  if (filters)
22
24
  compoundFilters.push(filters);
23
25
  const mergedFilters = compoundFilters.length > 0 ? compoundFilters.join(",") : undefined;
@@ -34,8 +36,8 @@ export async function getProductById(id) {
34
36
  }
35
37
  export async function getFeaturedProducts(pageSize = 8) {
36
38
  return productRepository.list({
37
- filters: `featured==true,${PUBLISHED_CLAUSE}`,
38
- sorts: "-createdAt",
39
+ filters: sieveAnd(sieveFilter("featured", SIEVE_OP.EQ, "true"), PUBLISHED_CLAUSE),
40
+ sorts: sortBy("createdAt", "DESC"),
39
41
  page: 1,
40
42
  pageSize,
41
43
  });
@@ -43,7 +45,7 @@ export async function getFeaturedProducts(pageSize = 8) {
43
45
  export async function getFeaturedAuctions(pageSize = 6) {
44
46
  return productRepository.list({
45
47
  filters: AUCTIONS_PUBLISHED,
46
- sorts: "auctionEndDate",
48
+ sorts: sortBy("auctionEndDate", "ASC"),
47
49
  page: 1,
48
50
  pageSize,
49
51
  });
@@ -51,7 +53,7 @@ export async function getFeaturedAuctions(pageSize = 6) {
51
53
  export async function getLatestProducts(pageSize = 12) {
52
54
  return productRepository.list({
53
55
  filters: PUBLISHED_CLAUSE,
54
- sorts: "-createdAt",
56
+ sorts: sortBy("createdAt", "DESC"),
55
57
  page: 1,
56
58
  pageSize,
57
59
  });
@@ -59,7 +61,7 @@ export async function getLatestProducts(pageSize = 12) {
59
61
  export async function getLatestAuctions(pageSize = 12) {
60
62
  return productRepository.list({
61
63
  filters: AUCTIONS_PUBLISHED,
62
- sorts: "-createdAt",
64
+ sorts: sortBy("createdAt", "DESC"),
63
65
  page: 1,
64
66
  pageSize,
65
67
  });
@@ -76,7 +78,7 @@ export async function listAuctions(params = {}) {
76
78
  export async function getFeaturedPreOrders(pageSize = 6) {
77
79
  return productRepository.list({
78
80
  filters: PREORDERS_PUBLISHED,
79
- sorts: "preOrderDeliveryDate",
81
+ sorts: sortBy("preOrderDeliveryDate", "ASC"),
80
82
  page: 1,
81
83
  pageSize,
82
84
  });
@@ -84,7 +86,7 @@ export async function getFeaturedPreOrders(pageSize = 6) {
84
86
  export async function getLatestPreOrders(pageSize = 12) {
85
87
  return productRepository.list({
86
88
  filters: PREORDERS_PUBLISHED,
87
- sorts: "-createdAt",
89
+ sorts: sortBy("createdAt", "DESC"),
88
90
  page: 1,
89
91
  pageSize,
90
92
  });
@@ -100,8 +102,8 @@ export async function listPreOrders(params = {}) {
100
102
  }
101
103
  export async function getRelatedProducts(categoryId, excludeId, limit = 6) {
102
104
  const result = await productRepository.list({
103
- filters: `categoryId==${categoryId},${PUBLISHED_CLAUSE}`,
104
- sorts: "-createdAt",
105
+ filters: sieveAnd(sieveFilter("categoryId", SIEVE_OP.EQ, categoryId), PUBLISHED_CLAUSE),
106
+ sorts: sortBy("createdAt", "DESC"),
105
107
  page: 1,
106
108
  pageSize: limit + 1,
107
109
  });
@@ -17,7 +17,7 @@ export type ProductSortValue = (typeof PRODUCT_SORT_VALUES)[keyof typeof PRODUCT
17
17
  * Default admin column definitions for a product table.
18
18
  * These are plain data — no React imports, no JSX.
19
19
  *
20
- * Use with `DataTable<T>` from `@mohasinac/feat-admin`.
20
+ * Use with sieveFilter("DataTable", SIEVE_OP.LT, "T>") from `@mohasinac/feat-admin`.
21
21
  *
22
22
  * @example — consumer app overrides/extends columns
23
23
  * ```ts
@@ -14,7 +14,7 @@ export const PRODUCT_SORT_VALUES = {
14
14
  * Default admin column definitions for a product table.
15
15
  * These are plain data — no React imports, no JSX.
16
16
  *
17
- * Use with `DataTable<T>` from `@mohasinac/feat-admin`.
17
+ * Use with sieveFilter("DataTable", SIEVE_OP.LT, "T>") from `@mohasinac/feat-admin`.
18
18
  *
19
19
  * @example — consumer app overrides/extends columns
20
20
  * ```ts
@@ -1,19 +1,5 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- /**
4
- * PrizeDrawCollage (SB4-B)
5
- *
6
- * Read-only display of a prize-draw's full prize pool. Each cell shows the
7
- * primary image, item-number badge, and title. Items with `isWon === true`
8
- * are dimmed under a diagonal overlay with a "Won" label so the public
9
- * collage truthfully reflects what's still up for grabs.
10
- *
11
- * Clicking any cell opens a full-screen lightbox starting at that item and
12
- * cycling circularly through all items in itemNumber order.
13
- *
14
- * Optional `highlightItemNumber` (passed by the reveal modal during animation)
15
- * adds an emphasis ring to the cell that just won.
16
- */
17
3
  import { useState } from "react";
18
4
  import { Div, Text } from "../../../ui";
19
5
  import { ImageLightbox } from "../../../ui/components/ImageLightbox";
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit";
2
3
  import { productRepository } from "../../../repositories";
3
4
  import { Container, Main, Heading, Section, Text } from "../../../ui";
4
5
  import { AdSlot } from "../../homepage/components/AdSlot";
@@ -16,15 +17,15 @@ function buildPrizeDrawFilters(params) {
16
17
  const minPrice = sp(params, "minPrice");
17
18
  const maxPrice = sp(params, "maxPrice");
18
19
  if (minPrice)
19
- parts.push(`pricePerEntry>=${minPrice}`);
20
+ parts.push(sieveFilter("pricePerEntry", SIEVE_OP.GTE, minPrice));
20
21
  if (maxPrice)
21
- parts.push(`pricePerEntry<=${maxPrice}`);
22
+ parts.push(sieveFilter("pricePerEntry", SIEVE_OP.LTE, maxPrice));
22
23
  const store = sp(params, "storeId");
23
24
  if (store)
24
- parts.push(`storeId==${store}`);
25
+ parts.push(sieveFilter("storeId", SIEVE_OP.EQ, store));
25
26
  const status = sp(params, "prizeRevealStatus");
26
27
  if (status)
27
- parts.push(`prizeRevealStatus==${status}`);
28
+ parts.push(sieveFilter("prizeRevealStatus", SIEVE_OP.EQ, status));
28
29
  return parts.join(",");
29
30
  }
30
31
  /**
@@ -1,4 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { sieveFilter, sieveAnd, SIEVE_OP } from "@mohasinac/appkit";
3
+ import { sortBy } from "@mohasinac/appkit";
2
4
  import Link from "next/link";
3
5
  import { Container, Div, Heading, Section, Stack, Text, } from "../../../ui";
4
6
  import { ROUTES } from "../../../next";
@@ -15,8 +17,8 @@ export async function PrizeDrawsSection({ config, }) {
15
17
  let draws = [];
16
18
  try {
17
19
  const result = await productRepository.list({
18
- filters: "listingType==prize-draw,status==published",
19
- sorts: "-createdAt",
20
+ filters: sieveAnd(sieveFilter("listingType", SIEVE_OP.EQ, "prize-draw"), sieveFilter("status", SIEVE_OP.EQ, "published")),
21
+ sorts: sortBy("createdAt", "DESC"),
20
22
  pageSize: limit,
21
23
  });
22
24
  draws = (result.items ?? []);
@@ -154,10 +154,10 @@ export declare const BUNDLE_SORT_OPTIONS: readonly [...({
154
154
  readonly value: string;
155
155
  readonly label: "Price: High to Low";
156
156
  }, {
157
- readonly value: "-savingsAmount";
157
+ readonly value: string;
158
158
  readonly label: "Most Savings";
159
159
  }, {
160
- readonly value: "-bundleItemCount";
160
+ readonly value: string;
161
161
  readonly label: "Most Items";
162
162
  }];
163
163
  export declare const PRIZE_DRAW_SORT_OPTIONS: readonly [{
@@ -79,8 +79,8 @@ export const PREORDER_SORT_OPTIONS = [
79
79
  export const BUNDLE_SORT_OPTIONS = [
80
80
  ...BASE_TIME_SORTS.slice(0, 1), // Newest First
81
81
  ...BASE_PRICE_SORTS,
82
- { value: "-savingsAmount", label: "Most Savings" },
83
- { value: "-bundleItemCount", label: "Most Items" },
82
+ { value: sortBy("savingsAmount", "DESC"), label: "Most Savings" },
83
+ { value: sortBy("bundleItemCount", "DESC"), label: "Most Items" },
84
84
  ];
85
85
  // ---------------------------------------------------------------------------
86
86
  // Prize Draws
@@ -10,6 +10,6 @@ export declare function useProductDetail<TProduct = ProductItem>(slug: string, o
10
10
  product: TProduct | null;
11
11
  isLoading: boolean;
12
12
  error: Error | null;
13
- refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<NoInfer<ProductItem | null>, Error>>;
13
+ refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<ProductItem | null, Error>>;
14
14
  };
15
15
  export {};
@@ -4,4 +4,4 @@ import type { ProductListResponse } from "../types";
4
4
  * boolean translates to the canonical `listingType` clause; new callers can
5
5
  * pass the union directly via the same parameter slot in a follow-up.
6
6
  */
7
- export declare function useRelatedProducts(category: string, excludeId: string, limit?: number, isAuction?: boolean): import("@tanstack/react-query").UseQueryResult<NoInfer<ProductListResponse>, Error>;
7
+ export declare function useRelatedProducts(category: string, excludeId: string, limit?: number, isAuction?: boolean): import("@tanstack/react-query").UseQueryResult<ProductListResponse, Error>;
@@ -1,3 +1,4 @@
1
+ import { sieveAnd, sieveFilter, SIEVE_OP, sortBy } from "@mohasinac/appkit";
1
2
  import { useQuery } from "@tanstack/react-query";
2
3
  import { apiClient } from "../../../http";
3
4
  import { PRODUCT_ENDPOINTS } from "../../../constants/api-endpoints";
@@ -8,11 +9,11 @@ import { PRODUCT_ENDPOINTS } from "../../../constants/api-endpoints";
8
9
  */
9
10
  export function useRelatedProducts(category, excludeId, limit = 8, isAuction = false) {
10
11
  const listingTypeClause = isAuction
11
- ? "listingType==auction"
12
- : "listingType==standard";
12
+ ? sieveFilter("listingType", SIEVE_OP.EQ, "auction")
13
+ : sieveFilter("listingType", SIEVE_OP.EQ, "standard");
13
14
  const params = new URLSearchParams({
14
- filters: `status==published,category==${encodeURIComponent(category)},${listingTypeClause}`,
15
- sorts: "-createdAt",
15
+ filters: sieveAnd(sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("category", SIEVE_OP.EQ, encodeURIComponent(category)), listingTypeClause),
16
+ sorts: sortBy("createdAt", "DESC"),
16
17
  pageSize: String(limit),
17
18
  });
18
19
  return useQuery({
@@ -9,13 +9,13 @@ export declare function usePromotions(params?: PromotionsListParams, opts?: {
9
9
  hasMore: boolean;
10
10
  isLoading: boolean;
11
11
  error: string | null;
12
- refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<NoInfer<PromotionsListResponse>, Error>>;
12
+ refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<PromotionsListResponse, Error>>;
13
13
  };
14
14
  export declare function useCoupon(code: string, opts?: {
15
15
  enabled?: boolean;
16
16
  endpoint?: string;
17
17
  }): {
18
- coupon: NonNullable<NoInfer<CouponItem | null>> | null;
18
+ coupon: CouponItem | null;
19
19
  isLoading: boolean;
20
20
  error: string | null;
21
21
  };
@@ -4,6 +4,7 @@
4
4
  * Pure business functions for review create/update/delete/vote and query flows.
5
5
  * Auth and rate-limit stay in consumer server-action wrappers.
6
6
  */
7
+ import { sortBy } from "@mohasinac/appkit";
7
8
  import { AuthorizationError, NotFoundError, ValidationError, } from "../../../errors";
8
9
  import { serverLogger } from "../../../monitoring";
9
10
  import { maskPublicReview } from "../../../security";
@@ -144,7 +145,7 @@ export async function voteReviewHelpful(reviewId, helpful) {
144
145
  }
145
146
  export async function listReviewsByProduct(productId, page = 1, pageSize = 10) {
146
147
  const result = await reviewRepository.listForProduct(productId, {
147
- sorts: "-createdAt",
148
+ sorts: sortBy("createdAt", "DESC"),
148
149
  page,
149
150
  pageSize,
150
151
  });
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit";
2
3
  import { reviewRepository } from "../../../repositories";
3
4
  import { Container, Heading, Main, Section } from "../../../ui";
4
5
  import { AdSlot } from "../../homepage/components/AdSlot";
@@ -13,22 +14,22 @@ function buildReviewFilters(params) {
13
14
  if (rating) {
14
15
  const values = rating.split("|").filter(Boolean);
15
16
  if (values.length === 1)
16
- parts.push(`rating==${values[0]}`);
17
+ parts.push(sieveFilter("rating", SIEVE_OP.EQ, values[0]));
17
18
  else if (values.length > 1)
18
- parts.push(`rating==${values.join("|")}`);
19
+ parts.push(sieveFilter("rating", SIEVE_OP.EQ, values.join("|")));
19
20
  }
20
21
  const minVotes = sp(params, "minVotes");
21
22
  if (minVotes)
22
- parts.push(`helpfulCount>=${minVotes}`);
23
+ parts.push(sieveFilter("helpfulCount", SIEVE_OP.GTE, minVotes));
23
24
  const maxVotes = sp(params, "maxVotes");
24
25
  if (maxVotes)
25
- parts.push(`helpfulCount<=${maxVotes}`);
26
+ parts.push(sieveFilter("helpfulCount", SIEVE_OP.LTE, maxVotes));
26
27
  const dateFrom = sp(params, "dateFrom");
27
28
  const dateTo = sp(params, "dateTo");
28
29
  if (dateFrom)
29
- parts.push(`createdAt>=${dateFrom}`);
30
+ parts.push(sieveFilter("createdAt", SIEVE_OP.GTE, dateFrom));
30
31
  if (dateTo)
31
- parts.push(`createdAt<=${dateTo}`);
32
+ parts.push(sieveFilter("createdAt", SIEVE_OP.LTE, dateTo));
32
33
  const q = sp(params, "q");
33
34
  if (q)
34
35
  parts.push(`productTitle@=*${q}`);
@@ -14,7 +14,7 @@ export declare function useReviews(params?: ReviewListParams, opts?: UseReviewsO
14
14
  ratingDistribution: Record<number, number> | undefined;
15
15
  isLoading: boolean;
16
16
  error: Error | null;
17
- refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<NoInfer<ReviewListResponse>, Error>>;
17
+ refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<ReviewListResponse, Error>>;
18
18
  };
19
19
  interface UseProductReviewsOptions {
20
20
  page?: number;
@@ -30,6 +30,6 @@ export declare function useProductReviews(productId: string, opts?: UseProductRe
30
30
  ratingDistribution: Record<number, number> | undefined;
31
31
  isLoading: boolean;
32
32
  error: Error | null;
33
- refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<NoInfer<ReviewListResponse>, Error>>;
33
+ refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<ReviewListResponse, Error>>;
34
34
  };
35
35
  export {};
@@ -1,4 +1,5 @@
1
1
  "use server";
2
+ import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit";
2
3
  import { scammerRepository } from "../repository/scammer.repository";
3
4
  /**
4
5
  * List verified scammer profiles for the public registry page.
@@ -12,9 +13,9 @@ export async function listVerifiedScammers(searchParams) {
12
13
  // scamType / scamPlatform filter chips — status==verified is enforced by the base query
13
14
  const filters = [];
14
15
  if (params.scamType)
15
- filters.push(`scamType==${params.scamType}`);
16
+ filters.push(sieveFilter("scamType", SIEVE_OP.EQ, String(params.scamType)));
16
17
  if (params.scamPlatform)
17
- filters.push(`scamPlatform==${params.scamPlatform}`);
18
+ filters.push(sieveFilter("scamPlatform", SIEVE_OP.EQ, String(params.scamPlatform)));
18
19
  const result = await scammerRepository.listVerified({
19
20
  filters: filters.join(",") || undefined,
20
21
  sorts: sort,
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { sortBy } from "@mohasinac/appkit";
2
3
  import Link from "next/link";
3
4
  import { ROUTES } from "../../../next/routing/route-map";
4
5
  const CLS_ICON_SM = "h-3 w-3 shrink-0";
@@ -10,10 +11,10 @@ import { listVerifiedScammers } from "../actions/scam-actions";
10
11
  import { SCAM_PLATFORM_LABELS } from "../schemas/firestore";
11
12
  import { SCAM_TYPES, SCAM_TYPE_LABELS } from "../constants/scam-types";
12
13
  const SORT_OPTIONS = [
13
- { value: "-createdAt", label: "Newest Reports" },
14
- { value: "createdAt", label: "Oldest Reports" },
15
- { value: "-incidentCount", label: "Most Victims" },
16
- { value: "-amountLost", label: "Highest Loss" },
14
+ { value: sortBy("createdAt", "DESC"), label: "Newest Reports" },
15
+ { value: sortBy("createdAt", "ASC"), label: "Oldest Reports" },
16
+ { value: sortBy("incidentCount", "DESC"), label: "Most Victims" },
17
+ { value: sortBy("amountLost", "DESC"), label: "Highest Loss" },
17
18
  ];
18
19
  function sp(params, key) {
19
20
  const v = params[key];
@@ -4,6 +4,7 @@
4
4
  * Pure business functions — auth, rate-limiting, and Next.js specifics
5
5
  * are handled by the calling server action in the consumer.
6
6
  */
7
+ import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit";
7
8
  import { productRepository } from "../../products/repository/products.repository";
8
9
  import { serverLogger } from "../../../monitoring";
9
10
  /**
@@ -14,18 +15,18 @@ export async function searchProducts(query = {}) {
14
15
  const { q = "", category, subcategory, minPrice = 0, maxPrice = 0, condition, listingType, sort = "-createdAt", page = 1, pageSize = 20, } = query;
15
16
  const filterParts = ["status==published"];
16
17
  if (category)
17
- filterParts.push(`category==${category}`);
18
+ filterParts.push(sieveFilter("category", SIEVE_OP.EQ, category));
18
19
  if (subcategory)
19
- filterParts.push(`subcategory==${subcategory}`);
20
+ filterParts.push(sieveFilter("subcategory", SIEVE_OP.EQ, subcategory));
20
21
  if (minPrice > 0)
21
- filterParts.push(`price>=${minPrice}`);
22
+ filterParts.push(sieveFilter("price", SIEVE_OP.GTE, minPrice));
22
23
  if (maxPrice > 0 && maxPrice >= minPrice)
23
- filterParts.push(`price<=${maxPrice}`);
24
+ filterParts.push(sieveFilter("price", SIEVE_OP.LTE, maxPrice));
24
25
  if (condition)
25
- filterParts.push(`condition==${condition}`);
26
+ filterParts.push(sieveFilter("condition", SIEVE_OP.EQ, condition));
26
27
  // SB1-G Phase 4 — canonical listingType discriminator.
27
28
  if (listingType)
28
- filterParts.push(`listingType==${listingType}`);
29
+ filterParts.push(sieveFilter("listingType", SIEVE_OP.EQ, listingType));
29
30
  if (q.trim())
30
31
  filterParts.push(`title_=${q.trim()}`);
31
32
  const sieveResult = await productRepository.list({
@@ -11,11 +11,11 @@ interface UseSearchOptions {
11
11
  * `options.initialCategories` — server-prefetched category list for filter facets.
12
12
  */
13
13
  export declare function useSearch(searchParams: string, options?: UseSearchOptions): {
14
- results: NoInfer<SearchResponse> | null;
14
+ results: SearchResponse | null;
15
15
  items: import("..").SearchProductItem[];
16
16
  total: number;
17
17
  totalPages: number;
18
18
  isLoading: boolean;
19
- categories: NoInfer<SearchCategoryOption[]>;
19
+ categories: SearchCategoryOption[];
20
20
  };
21
21
  export {};
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { sortBy } from "@mohasinac/appkit";
3
4
  import React from "react";
4
5
  import { PaginatedSelect } from "../../../ui/components/PaginatedSelect";
5
6
  import { apiClient } from "../../../http";
@@ -10,7 +11,7 @@ function makeLoader(scope) {
10
11
  const params = new URLSearchParams({
11
12
  page: String(page),
12
13
  pageSize: "25",
13
- sorts: "-createdAt",
14
+ sorts: sortBy("createdAt", "DESC"),
14
15
  });
15
16
  if (query.trim())
16
17
  params.set("q", query.trim());
@@ -1,5 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit";
4
+ import { sortBy } from "@mohasinac/appkit";
3
5
  import React, { useState, useCallback } from "react";
4
6
  import { useEntityDelete } from "../../../react/hooks/useEntityDelete";
5
7
  import { ConfirmDeleteModal, FilterChipGroup, ListingLayout, RowActionMenu } from "../../../ui";
@@ -36,14 +38,14 @@ export function SellerAuctionsView({ children, onEditClick, onDelete, onBulkDele
36
38
  searchPlaceholder: "Search auctions by product name",
37
39
  emptyLabel: "No auctions found",
38
40
  filterKeys: ["status"],
39
- defaultSort: "endsAt",
41
+ defaultSort: sortBy("endsAt", "ASC"),
40
42
  queryKey: ["seller", "auctions", "listing"],
41
43
  endpoint: SELLER_ENDPOINTS.AUCTIONS,
42
44
  sortOptions: [
43
45
  { value: "endsAt", label: "Ending soon" },
44
- { value: "-endsAt", label: "Ending latest" },
45
- { value: "-createdAt", label: "Newest" },
46
- { value: "createdAt", label: "Oldest" },
46
+ { value: sortBy("endsAt", "DESC"), label: "Ending latest" },
47
+ { value: sortBy("createdAt", "DESC"), label: "Newest" },
48
+ { value: sortBy("createdAt", "ASC"), label: "Oldest" },
47
49
  ],
48
50
  mapRows: (response) => toRecordArray(response.auctions).map((item, index) => ({
49
51
  id: toStringValue(item.id, `auction-${index}`),
@@ -58,7 +60,7 @@ export function SellerAuctionsView({ children, onEditClick, onDelete, onBulkDele
58
60
  getTotal: (response, mappedRows) => typeof response.meta?.total === "number"
59
61
  ? response.meta.total
60
62
  : mappedRows.length,
61
- buildFilters: (state) => state.status && state.status !== "All" ? `status==${state.status}` : undefined,
63
+ buildFilters: (state) => state.status && state.status !== "All" ? sieveFilter("status", SIEVE_OP.EQ, state.status) : undefined,
62
64
  buildBulkActions: onBulkDelete
63
65
  ? (selection) => [
64
66
  {