@mohasinac/appkit 2.7.11 → 2.7.13

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 (152) hide show
  1. package/dist/_internal/server/jobs/core/assignSpinPrize.js +8 -7
  2. package/dist/_internal/server/jobs/core/bundleStockSync.js +17 -20
  3. package/dist/_internal/server/jobs/core/countersReconcile.js +3 -2
  4. package/dist/_internal/server/jobs/core/onProductStockChange.js +18 -20
  5. package/dist/_internal/server/jobs/core/onProductWrite.js +3 -2
  6. package/dist/_internal/server/jobs/core/prizeRevealClose.js +7 -5
  7. package/dist/_internal/server/jobs/core/prizeRevealExpiry.js +11 -6
  8. package/dist/_internal/server/jobs/core/prizeRevealOpen.js +13 -7
  9. package/dist/_internal/server/jobs/core/prizeRevealReminder.js +9 -4
  10. package/dist/_internal/server/jobs/core/triggerEventRaffle.js +3 -2
  11. package/dist/_internal/shared/features/blog/schema.d.ts +4 -4
  12. package/dist/_internal/shared/features/categories/bundle-copy.d.ts +3 -6
  13. package/dist/_internal/shared/features/categories/bundle-copy.js +3 -6
  14. package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +32 -32
  15. package/dist/_internal/shared/features/events/schema.d.ts +4 -4
  16. package/dist/_internal/shared/features/products/schema.d.ts +20 -20
  17. package/dist/_internal/shared/features/promotions/schema.d.ts +2 -2
  18. package/dist/_internal/shared/features/reviews/schema.d.ts +1 -1
  19. package/dist/constants/field-names.d.ts +824 -0
  20. package/dist/constants/field-names.js +929 -0
  21. package/dist/constants/sort.d.ts +7 -0
  22. package/dist/constants/sort.js +5 -0
  23. package/dist/constants/table-keys.d.ts +48 -0
  24. package/dist/constants/table-keys.js +46 -0
  25. package/dist/features/account/components/AddressesIndexListing.js +9 -6
  26. package/dist/features/admin/components/AdminAllEventEntriesView.js +4 -1
  27. package/dist/features/admin/components/AdminBidsView.js +4 -1
  28. package/dist/features/admin/components/AdminBlogView.js +9 -2
  29. package/dist/features/admin/components/AdminBrandsView.js +9 -2
  30. package/dist/features/admin/components/AdminBundlesView.js +0 -1
  31. package/dist/features/admin/components/AdminCarouselView.js +4 -1
  32. package/dist/features/admin/components/AdminCartsView.js +4 -1
  33. package/dist/features/admin/components/AdminCategoriesView.js +9 -2
  34. package/dist/features/admin/components/AdminContactView.js +4 -1
  35. package/dist/features/admin/components/AdminCouponsView.js +4 -1
  36. package/dist/features/admin/components/AdminFaqsView.js +5 -1
  37. package/dist/features/admin/components/AdminFeaturesView.js +5 -2
  38. package/dist/features/admin/components/AdminHistoryView.js +5 -1
  39. package/dist/features/admin/components/AdminNewsletterView.js +4 -1
  40. package/dist/features/admin/components/AdminNotificationsView.js +4 -1
  41. package/dist/features/admin/components/AdminOrdersView.js +14 -12
  42. package/dist/features/admin/components/AdminPayoutsView.js +4 -1
  43. package/dist/features/admin/components/AdminPrizeDrawsView.js +4 -1
  44. package/dist/features/admin/components/AdminProductsView.js +14 -3
  45. package/dist/features/admin/components/AdminReturnRequestsView.js +4 -1
  46. package/dist/features/admin/components/AdminReviewsView.js +4 -1
  47. package/dist/features/admin/components/AdminScammersView.js +4 -1
  48. package/dist/features/admin/components/AdminSessionsView.js +4 -1
  49. package/dist/features/admin/components/AdminStoreAddressesView.js +5 -1
  50. package/dist/features/admin/components/AdminStoresView.js +10 -3
  51. package/dist/features/admin/components/AdminSublistingCategoriesView.js +4 -1
  52. package/dist/features/admin/components/AdminSupportTicketsView.js +4 -1
  53. package/dist/features/admin/components/AdminTeamView.js +4 -1
  54. package/dist/features/admin/components/AdminUsersView.js +9 -12
  55. package/dist/features/admin/components/AdminViewCards.d.ts +12 -0
  56. package/dist/features/admin/components/AdminViewCards.js +53 -0
  57. package/dist/features/admin/components/AdminWishlistsView.js +4 -1
  58. package/dist/features/auctions/repository/bid.repository.js +1 -6
  59. package/dist/features/auctions/schemas/index.d.ts +4 -4
  60. package/dist/features/blog/actions/blog-actions.d.ts +16 -16
  61. package/dist/features/blog/components/BlogFilters.d.ts +28 -28
  62. package/dist/features/blog/components/BlogFilters.js +18 -15
  63. package/dist/features/blog/components/BlogIndexListing.js +20 -16
  64. package/dist/features/blog/schemas/index.d.ts +10 -10
  65. package/dist/features/categories/components/BundleDetailView.js +0 -1
  66. package/dist/features/categories/components/CategoriesIndexListing.js +25 -21
  67. package/dist/features/categories/components/CategoryBundlesListing.js +2 -4
  68. package/dist/features/categories/schemas/firestore.d.ts +1 -1
  69. package/dist/features/categories/schemas/index.d.ts +2 -2
  70. package/dist/features/events/components/AdminEventsView.js +5 -1
  71. package/dist/features/events/components/EventFilters.d.ts +24 -24
  72. package/dist/features/events/components/EventFilters.js +16 -13
  73. package/dist/features/events/components/EventStatusBadge.js +1 -0
  74. package/dist/features/events/components/EventsIndexListing.js +31 -26
  75. package/dist/features/events/components/EventsListPageView.js +13 -10
  76. package/dist/features/events/schemas/firestore.d.ts +1 -0
  77. package/dist/features/events/schemas/firestore.js +1 -0
  78. package/dist/features/events/schemas/index.d.ts +1 -1
  79. package/dist/features/events/types/index.d.ts +1 -1
  80. package/dist/features/faq/actions/faq-actions.d.ts +10 -10
  81. package/dist/features/faq/schemas/index.d.ts +4 -4
  82. package/dist/features/homepage/components/FeaturedBundlesSection.js +1 -3
  83. package/dist/features/orders/components/OrderFilters.d.ts +20 -20
  84. package/dist/features/orders/components/OrderFilters.js +33 -30
  85. package/dist/features/orders/repository/orders.repository.js +1 -15
  86. package/dist/features/orders/schemas/index.d.ts +2 -2
  87. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +35 -31
  88. package/dist/features/pre-orders/repository/preorders.repository.js +8 -4
  89. package/dist/features/pre-orders/schemas/index.d.ts +3 -3
  90. package/dist/features/products/components/AuctionsIndexListing.js +34 -30
  91. package/dist/features/products/components/BidHistory.d.ts +0 -1
  92. package/dist/features/products/components/BidHistory.js +1 -1
  93. package/dist/features/products/components/PrizeDrawsIndexListing.js +44 -40
  94. package/dist/features/products/components/ProductDetailPageView.js +1 -1
  95. package/dist/features/products/components/ProductFilters.d.ts +20 -20
  96. package/dist/features/products/components/ProductFilters.js +62 -59
  97. package/dist/features/products/components/ProductsIndexListing.js +28 -24
  98. package/dist/features/products/components/ProductsIndexPageView.js +18 -10
  99. package/dist/features/products/hooks/useProducts.js +2 -0
  100. package/dist/features/products/repository/products.repository.js +2 -22
  101. package/dist/features/products/schemas/index.d.ts +28 -28
  102. package/dist/features/products/schemas/product-features.validators.d.ts +12 -12
  103. package/dist/features/products/types/index.d.ts +2 -0
  104. package/dist/features/promotions/components/CouponsIndexListing.js +57 -32
  105. package/dist/features/promotions/schemas/index.d.ts +4 -4
  106. package/dist/features/reviews/components/ReviewDetailShell.js +6 -5
  107. package/dist/features/reviews/components/ReviewFilters.d.ts +16 -16
  108. package/dist/features/reviews/components/ReviewFilters.js +10 -7
  109. package/dist/features/reviews/components/ReviewsIndexListing.js +21 -17
  110. package/dist/features/reviews/components/ReviewsList.d.ts +5 -2
  111. package/dist/features/reviews/components/ReviewsList.js +11 -5
  112. package/dist/features/reviews/schemas/firestore.d.ts +1 -0
  113. package/dist/features/reviews/schemas/index.d.ts +8 -8
  114. package/dist/features/reviews/types/index.d.ts +1 -0
  115. package/dist/features/search/schemas/index.d.ts +2 -2
  116. package/dist/features/seller/components/SellerAuctionsView.js +5 -1
  117. package/dist/features/seller/components/SellerBidsView.js +4 -1
  118. package/dist/features/seller/components/SellerCouponsView.js +4 -1
  119. package/dist/features/seller/components/SellerOffersView.js +5 -1
  120. package/dist/features/seller/components/SellerOrdersView.js +4 -1
  121. package/dist/features/seller/components/SellerPayoutsView.js +5 -1
  122. package/dist/features/seller/components/SellerPreOrdersView.js +4 -1
  123. package/dist/features/seller/components/SellerPrizeDrawsView.js +4 -1
  124. package/dist/features/seller/components/SellerProductsView.js +4 -1
  125. package/dist/features/seller/schemas/index.d.ts +12 -12
  126. package/dist/features/stores/api/route.js +10 -1
  127. package/dist/features/stores/components/StoreReviewsListing.js +1 -1
  128. package/dist/features/stores/components/StoresIndexListing.js +24 -20
  129. package/dist/features/stores/repository/stores.repository.js +8 -5
  130. package/dist/features/stores/schemas/firestore.d.ts +1 -0
  131. package/dist/features/stores/schemas/index.d.ts +4 -4
  132. package/dist/index.d.ts +8 -1
  133. package/dist/index.js +12 -1
  134. package/dist/providers/firebase-client/auth.d.ts +7 -0
  135. package/dist/providers/firebase-client/auth.js +15 -8
  136. package/dist/react/hooks/useUrlTable.js +2 -1
  137. package/dist/seed/bids-seed-data.js +45 -44
  138. package/dist/seed/categories-seed-data.js +41 -40
  139. package/dist/seed/coupons-seed-data.js +41 -40
  140. package/dist/seed/products-auctions-seed-data.js +54 -53
  141. package/dist/seed/products-preorders-seed-data.js +25 -24
  142. package/dist/seed/products-prize-draws-seed-data.js +24 -23
  143. package/dist/seed/products-standard-seed-data.js +294 -293
  144. package/dist/seed/reviews-seed-data.js +61 -60
  145. package/dist/seed/scammers-seed-data.js +3 -2
  146. package/dist/seed/stores-seed-data.js +9 -8
  147. package/dist/seed/support-tickets-seed-data.js +13 -12
  148. package/dist/seed/users-seed-data.js +28 -27
  149. package/dist/tailwind-utilities.css +1 -1
  150. package/dist/utils/sieve-builder.d.ts +41 -0
  151. package/dist/utils/sieve-builder.js +66 -0
  152. package/package.json +2 -2
@@ -3,6 +3,7 @@
3
3
  * `crypto.randomInt`. Enforces one spin per user.
4
4
  */
5
5
  import crypto from "node:crypto";
6
+ import { EVENT_ENTRY_FIELDS, COMMON_FIELDS } from "../../../../constants/field-names";
6
7
  const EVENTS_COLLECTION = "events";
7
8
  const EVENT_ENTRIES_COLLECTION = "eventEntries";
8
9
  const COUPONS_COLLECTION = "coupons";
@@ -20,8 +21,8 @@ export async function runAssignSpinPrize(input, ctx) {
20
21
  }
21
22
  const entriesSnap = await ctx.db
22
23
  .collection(EVENT_ENTRIES_COLLECTION)
23
- .where("eventId", "==", eventId)
24
- .where("userId", "==", userId)
24
+ .where(EVENT_ENTRY_FIELDS.EVENT_ID, "==", eventId)
25
+ .where(EVENT_ENTRY_FIELDS.USER_ID, "==", userId)
25
26
  .limit(1)
26
27
  .get();
27
28
  if (entriesSnap.empty) {
@@ -60,11 +61,11 @@ export async function runAssignSpinPrize(input, ctx) {
60
61
  }
61
62
  }
62
63
  await entryDoc.ref.update({
63
- spinUsed: true,
64
- spinPrizeId: pick.id,
65
- spinWonAt: ctx.now,
66
- spinPrizeCouponCode: spinPrizeCouponCode ?? null,
67
- updatedAt: ctx.now,
64
+ [EVENT_ENTRY_FIELDS.SPIN_USED]: true,
65
+ [EVENT_ENTRY_FIELDS.SPIN_PRIZE_ID]: pick.id,
66
+ [EVENT_ENTRY_FIELDS.SPIN_WON_AT]: ctx.now,
67
+ [EVENT_ENTRY_FIELDS.SPIN_PRIZE_COUPON_CODE]: spinPrizeCouponCode ?? null,
68
+ [COMMON_FIELDS.UPDATED_AT]: ctx.now,
68
69
  });
69
70
  ctx.logger.info("Spin prize assigned", {
70
71
  eventId,
@@ -6,41 +6,39 @@
6
6
  * `bundleStockStatus`. This sweep recomputes `bundleStockStatus` for
7
7
  * every active bundle by inspecting its members' product status.
8
8
  */
9
+ import { CATEGORY_FIELDS, PRODUCT_FIELDS, COMMON_FIELDS } from "../../../../constants/field-names";
9
10
  const CATEGORIES_COLLECTION = "categories";
10
11
  const PRODUCT_COLLECTION = "products";
11
- const UNAVAILABLE = new Set(["sold", "out_of_stock", "discontinued"]);
12
- const MIN_ACTIVE_DEFAULT = 1;
13
- async function computeBundleStockStatus(productIds, minActive, ctx) {
12
+ const UNAVAILABLE = new Set([
13
+ PRODUCT_FIELDS.STATUS_VALUES.SOLD,
14
+ PRODUCT_FIELDS.STATUS_VALUES.OUT_OF_STOCK,
15
+ PRODUCT_FIELDS.STATUS_VALUES.DISCONTINUED,
16
+ ]);
17
+ async function computeBundleStockStatus(productIds, ctx) {
14
18
  if (productIds.length === 0)
15
19
  return "out_of_stock";
16
- let unavailable = 0;
17
20
  for (let i = 0; i < productIds.length; i += 30) {
18
21
  const chunk = productIds.slice(i, i + 30);
19
22
  const snap = await ctx.db
20
23
  .collection(PRODUCT_COLLECTION)
21
24
  .where("__name__", "in", chunk)
22
25
  .get();
26
+ if (snap.size < chunk.length)
27
+ return "out_of_stock";
23
28
  for (const doc of snap.docs) {
24
29
  const status = doc.data().status;
25
30
  if (!status || UNAVAILABLE.has(status))
26
- unavailable++;
31
+ return "out_of_stock";
27
32
  }
28
- if (snap.size < chunk.length)
29
- unavailable += chunk.length - snap.size;
30
33
  }
31
- const active = productIds.length - unavailable;
32
- if (unavailable === 0)
33
- return "in_stock";
34
- if (active < minActive)
35
- return "out_of_stock";
36
- return "partial";
34
+ return "in_stock";
37
35
  }
38
36
  export async function runBundleStockSync(ctx) {
39
37
  ctx.logger.info("Bundle stock sync starting (SB-UNI-V categories)");
40
38
  const snap = await ctx.db
41
39
  .collection(CATEGORIES_COLLECTION)
42
- .where("categoryType", "==", "bundle")
43
- .where("isActive", "==", true)
40
+ .where(CATEGORY_FIELDS.CATEGORY_TYPE, "==", CATEGORY_FIELDS.CATEGORY_TYPE_VALUES.BUNDLE)
41
+ .where(CATEGORY_FIELDS.IS_ACTIVE, "==", true)
44
42
  .limit(500)
45
43
  .get();
46
44
  if (snap.empty) {
@@ -53,13 +51,12 @@ export async function runBundleStockSync(ctx) {
53
51
  const productIds = data.bundleProductIds ?? [];
54
52
  if (productIds.length === 0)
55
53
  continue;
56
- const minActive = data.minActiveMembers ?? MIN_ACTIVE_DEFAULT;
57
- const nextStatus = await computeBundleStockStatus(productIds, minActive, ctx);
54
+ const nextStatus = await computeBundleStockStatus(productIds, ctx);
58
55
  if (nextStatus !== data.bundleStockStatus) {
59
56
  await bundleDoc.ref.update({
60
- bundleStockStatus: nextStatus,
61
- bundleQueryResolvedAt: ctx.now,
62
- updatedAt: ctx.now,
57
+ [CATEGORY_FIELDS.BUNDLE_STOCK_STATUS]: nextStatus,
58
+ [CATEGORY_FIELDS.BUNDLE_QUERY_RESOLVED_AT]: ctx.now,
59
+ [COMMON_FIELDS.UPDATED_AT]: ctx.now,
63
60
  });
64
61
  updated++;
65
62
  }
@@ -1,5 +1,6 @@
1
1
  import { categoriesRepository, reviewRepository, storeRepository, } from "../../../../repositories";
2
2
  import { ProductStatusValues, PRODUCT_COLLECTION } from "../../../../features/products/schemas/firestore";
3
+ import { ORDER_FIELDS, PRODUCT_FIELDS } from "../../../../constants/field-names";
3
4
  import { QUERY_LIMIT } from "../handlers/messages";
4
5
  const STORES_COLLECTION = "stores";
5
6
  const ORDERS_COLLECTION = "orders";
@@ -18,7 +19,7 @@ async function reconcileCategories(ctx) {
18
19
  continue;
19
20
  if (!leafCounts[catId])
20
21
  leafCounts[catId] = { productIds: [], auctionIds: [] };
21
- if (data.listingType === "auction")
22
+ if (data.listingType === PRODUCT_FIELDS.LISTING_TYPE_VALUES.AUCTION)
22
23
  leafCounts[catId].auctionIds.push(doc.id);
23
24
  else
24
25
  leafCounts[catId].productIds.push(doc.id);
@@ -69,7 +70,7 @@ async function reconcileStores(ctx) {
69
70
  ctx.db
70
71
  .collection(ORDERS_COLLECTION)
71
72
  .where("sellerId", "==", sellerId)
72
- .where("status", "==", "delivered")
73
+ .where(ORDER_FIELDS.STATUS, "==", ORDER_FIELDS.STATUS_VALUES.DELIVERED)
73
74
  .limit(QUERY_LIMIT)
74
75
  .get(),
75
76
  reviewRepository.getApprovedRatingAggregateByStore(storeId),
@@ -10,58 +10,56 @@
10
10
  * member products (≤16 typically). Caller should skip when the product's
11
11
  * status didn't transition between "available" and "unavailable".
12
12
  */
13
+ import { CATEGORY_FIELDS, PRODUCT_FIELDS, COMMON_FIELDS } from "../../../../constants/field-names";
13
14
  const CATEGORIES_COLLECTION = "categories";
14
15
  const GROUPED_LISTINGS_COLLECTION = "groupedListings";
15
16
  const PRODUCT_COLLECTION = "products";
16
- const UNAVAILABLE_STATUSES = new Set(["sold", "out_of_stock", "discontinued"]);
17
+ const UNAVAILABLE_STATUSES = new Set([
18
+ PRODUCT_FIELDS.STATUS_VALUES.SOLD,
19
+ PRODUCT_FIELDS.STATUS_VALUES.OUT_OF_STOCK,
20
+ PRODUCT_FIELDS.STATUS_VALUES.DISCONTINUED,
21
+ ]);
17
22
  const MIN_ACTIVE_DEFAULT = 2;
18
23
  export function isAvailable(status) {
19
24
  if (!status)
20
25
  return false;
21
26
  return !UNAVAILABLE_STATUSES.has(status);
22
27
  }
23
- async function recomputeBundleStatus(productIds, minActive, ctx) {
28
+ async function recomputeBundleStatus(productIds, ctx) {
24
29
  if (productIds.length === 0)
25
30
  return "out_of_stock";
26
- let unavailable = 0;
27
31
  for (let i = 0; i < productIds.length; i += 30) {
28
32
  const chunk = productIds.slice(i, i + 30);
29
33
  const snap = await ctx.db
30
34
  .collection(PRODUCT_COLLECTION)
31
35
  .where("__name__", "in", chunk)
32
36
  .get();
37
+ if (snap.size < chunk.length)
38
+ return "out_of_stock";
33
39
  for (const doc of snap.docs) {
34
40
  const status = doc.data().status;
35
41
  if (!isAvailable(status))
36
- unavailable++;
42
+ return "out_of_stock";
37
43
  }
38
- if (snap.size < chunk.length)
39
- unavailable += chunk.length - snap.size;
40
44
  }
41
- const active = productIds.length - unavailable;
42
- if (unavailable === 0)
43
- return "in_stock";
44
- if (active < minActive)
45
- return "out_of_stock";
46
- return "partial";
45
+ return "in_stock";
47
46
  }
48
47
  export async function syncBundlesForProduct(productId, ctx) {
49
48
  const snap = await ctx.db
50
49
  .collection(CATEGORIES_COLLECTION)
51
- .where("categoryType", "==", "bundle")
52
- .where("bundleProductIds", "array-contains", productId)
50
+ .where(CATEGORY_FIELDS.CATEGORY_TYPE, "==", CATEGORY_FIELDS.CATEGORY_TYPE_VALUES.BUNDLE)
51
+ .where(CATEGORY_FIELDS.BUNDLE_PRODUCT_IDS, "array-contains", productId)
53
52
  .get();
54
53
  let updated = 0;
55
54
  for (const bundleDoc of snap.docs) {
56
55
  const data = bundleDoc.data();
57
56
  const ids = data.bundleProductIds ?? [];
58
- const minActive = data.minActiveMembers ?? 1;
59
- const next = await recomputeBundleStatus(ids, minActive, ctx);
57
+ const next = await recomputeBundleStatus(ids, ctx);
60
58
  if (next !== data.bundleStockStatus) {
61
59
  await bundleDoc.ref.update({
62
- bundleStockStatus: next,
63
- bundleQueryResolvedAt: ctx.now,
64
- updatedAt: ctx.now,
60
+ [CATEGORY_FIELDS.BUNDLE_STOCK_STATUS]: next,
61
+ [CATEGORY_FIELDS.BUNDLE_QUERY_RESOLVED_AT]: ctx.now,
62
+ [COMMON_FIELDS.UPDATED_AT]: ctx.now,
65
63
  });
66
64
  updated++;
67
65
  }
@@ -99,7 +97,7 @@ export async function syncGroupedListingsForProduct(productId, ctx) {
99
97
  await groupDoc.ref.update({
100
98
  activeMemberCount: activeCount,
101
99
  visibilityStatus: nextVisibility,
102
- updatedAt: ctx.now,
100
+ [COMMON_FIELDS.UPDATED_AT]: ctx.now,
103
101
  });
104
102
  updated++;
105
103
  }
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { categoriesRepository, storeRepository, } from "../../../../repositories";
6
6
  import { ProductStatusValues } from "../../../../features/products/schemas/firestore";
7
+ import { PRODUCT_FIELDS } from "../../../../constants/field-names";
7
8
  const UNAVAILABLE_PRODUCT_STATUSES = new Set([
8
9
  ProductStatusValues.SOLD,
9
10
  ProductStatusValues.OUT_OF_STOCK,
@@ -23,8 +24,8 @@ export async function handleProductWrite(input, ctx) {
23
24
  const afterCategory = after?.category ?? null;
24
25
  const beforeStoreId = (before?.storeId || before?.sellerId) ?? null;
25
26
  const afterStoreId = (after?.storeId || after?.sellerId) ?? null;
26
- const isAuction = after?.listingType === "auction";
27
- const beforeIsAuction = before?.listingType === "auction";
27
+ const isAuction = after?.listingType === PRODUCT_FIELDS.LISTING_TYPE_VALUES.AUCTION;
28
+ const beforeIsAuction = before?.listingType === PRODUCT_FIELDS.LISTING_TYPE_VALUES.AUCTION;
28
29
  const wasPublished = beforeStatus === ProductStatusValues.PUBLISHED;
29
30
  const isPublished = afterStatus === ProductStatusValues.PUBLISHED;
30
31
  const isDelete = !after;
@@ -1,11 +1,13 @@
1
+ import { PRODUCT_FIELDS, COMMON_FIELDS } from "../../../../constants/field-names";
1
2
  const PRODUCT_COLLECTION = "products";
3
+ const PRIZE_DRAW_LISTING_TYPE = "prize-draw";
2
4
  export async function runPrizeRevealClose(ctx) {
3
5
  ctx.logger.info("Prize reveal close sweep starting");
4
6
  const snap = await ctx.db
5
7
  .collection(PRODUCT_COLLECTION)
6
- .where("listingType", "==", "prize-draw")
7
- .where("prizeRevealStatus", "==", "open")
8
- .where("prizeRevealWindowEnd", "<=", ctx.now)
8
+ .where(PRODUCT_FIELDS.LISTING_TYPE, "==", PRIZE_DRAW_LISTING_TYPE)
9
+ .where(PRODUCT_FIELDS.PRIZE_REVEAL_STATUS, "==", PRODUCT_FIELDS.PRIZE_REVEAL_STATUS_VALUES.OPEN)
10
+ .where(PRODUCT_FIELDS.PRIZE_REVEAL_WINDOW_END, "<=", ctx.now)
9
11
  .limit(100)
10
12
  .get();
11
13
  if (snap.empty) {
@@ -14,8 +16,8 @@ export async function runPrizeRevealClose(ctx) {
14
16
  }
15
17
  const batch = ctx.db.batch();
16
18
  snap.docs.forEach((doc) => batch.update(doc.ref, {
17
- prizeRevealStatus: "closed",
18
- updatedAt: ctx.now,
19
+ [PRODUCT_FIELDS.PRIZE_REVEAL_STATUS]: PRODUCT_FIELDS.PRIZE_REVEAL_STATUS_VALUES.CLOSED,
20
+ [COMMON_FIELDS.UPDATED_AT]: ctx.now,
19
21
  }));
20
22
  await batch.commit();
21
23
  ctx.logger.info("Closed prize draws", { count: snap.size });
@@ -1,12 +1,17 @@
1
1
  import { notificationRepository } from "../../../../repositories";
2
+ import { ORDER_FIELDS, PRODUCT_FIELDS, COMMON_FIELDS } from "../../../../constants/field-names";
2
3
  const ORDER_COLLECTION = "orders";
3
4
  export async function runPrizeRevealExpiry(ctx) {
4
5
  ctx.logger.info("Prize reveal expiry sweep starting");
5
6
  const snap = await ctx.db
6
7
  .collection(ORDER_COLLECTION)
7
- .where("paymentStatus", "==", "paid")
8
- .where("status", "in", ["pending", "confirmed", "processing"])
9
- .where("prizeRevealDeadline", "<", ctx.now)
8
+ .where(ORDER_FIELDS.PAYMENT_STATUS, "==", ORDER_FIELDS.PAYMENT_STATUS_VALUES.PAID)
9
+ .where(ORDER_FIELDS.STATUS, "in", [
10
+ ORDER_FIELDS.STATUS_VALUES.PENDING,
11
+ ORDER_FIELDS.STATUS_VALUES.CONFIRMED,
12
+ ORDER_FIELDS.STATUS_VALUES.PROCESSING,
13
+ ])
14
+ .where(PRODUCT_FIELDS.PRIZE_REVEAL_DEADLINE, "<", ctx.now)
10
15
  .limit(200)
11
16
  .get();
12
17
  if (snap.empty) {
@@ -21,11 +26,11 @@ export async function runPrizeRevealExpiry(ctx) {
21
26
  if (!order.prizeDrawProductId)
22
27
  continue;
23
28
  await doc.ref.update({
24
- status: "refunded",
25
- paymentStatus: "refunded",
29
+ [ORDER_FIELDS.STATUS]: ORDER_FIELDS.STATUS_VALUES.REFUNDED,
30
+ [ORDER_FIELDS.PAYMENT_STATUS]: ORDER_FIELDS.PAYMENT_STATUS_VALUES.REFUNDED,
26
31
  isNonRefundable: false,
27
32
  prizeRevealExpired: true,
28
- updatedAt: ctx.now,
33
+ [COMMON_FIELDS.UPDATED_AT]: ctx.now,
29
34
  });
30
35
  if (order.userId) {
31
36
  try {
@@ -1,13 +1,15 @@
1
1
  import { notificationRepository } from "../../../../repositories";
2
+ import { PRODUCT_FIELDS, ORDER_FIELDS, COMMON_FIELDS } from "../../../../constants/field-names";
2
3
  const PRODUCT_COLLECTION = "products";
3
4
  const ORDER_COLLECTION = "orders";
5
+ const PRIZE_DRAW_LISTING_TYPE = "prize-draw";
4
6
  export async function runPrizeRevealOpen(ctx) {
5
7
  ctx.logger.info("Prize reveal open sweep starting");
6
8
  const snap = await ctx.db
7
9
  .collection(PRODUCT_COLLECTION)
8
- .where("listingType", "==", "prize-draw")
9
- .where("prizeRevealStatus", "==", "pending")
10
- .where("prizeRevealWindowStart", "<=", ctx.now)
10
+ .where(PRODUCT_FIELDS.LISTING_TYPE, "==", PRIZE_DRAW_LISTING_TYPE)
11
+ .where(PRODUCT_FIELDS.PRIZE_REVEAL_STATUS, "==", PRODUCT_FIELDS.PRIZE_REVEAL_STATUS_VALUES.PENDING)
12
+ .where(PRODUCT_FIELDS.PRIZE_REVEAL_WINDOW_START, "<=", ctx.now)
11
13
  .limit(100)
12
14
  .get();
13
15
  if (snap.empty) {
@@ -17,14 +19,18 @@ export async function runPrizeRevealOpen(ctx) {
17
19
  for (const doc of snap.docs) {
18
20
  const product = doc.data();
19
21
  await doc.ref.update({
20
- prizeRevealStatus: "open",
21
- updatedAt: ctx.now,
22
+ [PRODUCT_FIELDS.PRIZE_REVEAL_STATUS]: PRODUCT_FIELDS.PRIZE_REVEAL_STATUS_VALUES.OPEN,
23
+ [COMMON_FIELDS.UPDATED_AT]: ctx.now,
22
24
  });
23
25
  const orders = await ctx.db
24
26
  .collection(ORDER_COLLECTION)
25
27
  .where("prizeDrawProductId", "==", doc.id)
26
- .where("paymentStatus", "==", "paid")
27
- .where("status", "in", ["pending", "confirmed", "processing"])
28
+ .where(ORDER_FIELDS.PAYMENT_STATUS, "==", ORDER_FIELDS.PAYMENT_STATUS_VALUES.PAID)
29
+ .where(ORDER_FIELDS.STATUS, "in", [
30
+ ORDER_FIELDS.STATUS_VALUES.PENDING,
31
+ ORDER_FIELDS.STATUS_VALUES.CONFIRMED,
32
+ ORDER_FIELDS.STATUS_VALUES.PROCESSING,
33
+ ])
28
34
  .get();
29
35
  let notified = 0;
30
36
  for (const orderDoc of orders.docs) {
@@ -1,4 +1,5 @@
1
1
  import { notificationRepository } from "../../../../repositories";
2
+ import { ORDER_FIELDS, PRODUCT_FIELDS } from "../../../../constants/field-names";
2
3
  const ORDER_COLLECTION = "orders";
3
4
  const ONE_DAY_MS = 86400000;
4
5
  export async function runPrizeRevealReminder(ctx) {
@@ -6,10 +7,14 @@ export async function runPrizeRevealReminder(ctx) {
6
7
  const cutoff = new Date(ctx.now.getTime() + ONE_DAY_MS);
7
8
  const snap = await ctx.db
8
9
  .collection(ORDER_COLLECTION)
9
- .where("paymentStatus", "==", "paid")
10
- .where("status", "in", ["pending", "confirmed", "processing"])
11
- .where("prizeRevealDeadline", "<=", cutoff)
12
- .where("prizeRevealDeadline", ">", ctx.now)
10
+ .where(ORDER_FIELDS.PAYMENT_STATUS, "==", ORDER_FIELDS.PAYMENT_STATUS_VALUES.PAID)
11
+ .where(ORDER_FIELDS.STATUS, "in", [
12
+ ORDER_FIELDS.STATUS_VALUES.PENDING,
13
+ ORDER_FIELDS.STATUS_VALUES.CONFIRMED,
14
+ ORDER_FIELDS.STATUS_VALUES.PROCESSING,
15
+ ])
16
+ .where(PRODUCT_FIELDS.PRIZE_REVEAL_DEADLINE, "<=", cutoff)
17
+ .where(PRODUCT_FIELDS.PRIZE_REVEAL_DEADLINE, ">", ctx.now)
13
18
  .limit(500)
14
19
  .get();
15
20
  let notified = 0;
@@ -3,6 +3,7 @@
3
3
  * logic keys off the event's `raffleType`.
4
4
  */
5
5
  import crypto from "node:crypto";
6
+ import { EVENT_ENTRY_FIELDS } from "../../../../constants/field-names";
6
7
  const EVENTS_COLLECTION = "events";
7
8
  const EVENT_ENTRIES_COLLECTION = "eventEntries";
8
9
  export async function runTriggerEventRaffle(input, ctx) {
@@ -28,8 +29,8 @@ export async function runTriggerEventRaffle(input, ctx) {
28
29
  const topN = input.topN ?? event.raffleTopN ?? 0;
29
30
  const entriesSnap = await ctx.db
30
31
  .collection(EVENT_ENTRIES_COLLECTION)
31
- .where("eventId", "==", input.eventId)
32
- .where("status", "==", "CONFIRMED")
32
+ .where(EVENT_ENTRY_FIELDS.EVENT_ID, "==", input.eventId)
33
+ .where(EVENT_ENTRY_FIELDS.STATUS, "==", EVENT_ENTRY_FIELDS.STATUS_VALUES.CONFIRMED)
33
34
  .get();
34
35
  let pool = entriesSnap.docs.map((d) => ({
35
36
  id: d.id,
@@ -17,9 +17,9 @@ export declare const blogPostInputSchema: z.ZodObject<{
17
17
  title: string;
18
18
  content: string;
19
19
  category: string;
20
- slug: string;
21
20
  tags: string[];
22
21
  isFeatured: boolean;
22
+ slug: string;
23
23
  youtubeId?: string | undefined;
24
24
  coverImage?: string | undefined;
25
25
  excerpt?: string | undefined;
@@ -31,9 +31,9 @@ export declare const blogPostInputSchema: z.ZodObject<{
31
31
  category: string;
32
32
  slug: string;
33
33
  status?: "draft" | "published" | undefined;
34
- youtubeId?: string | undefined;
35
34
  tags?: string[] | undefined;
36
35
  isFeatured?: boolean | undefined;
36
+ youtubeId?: string | undefined;
37
37
  coverImage?: string | undefined;
38
38
  excerpt?: string | undefined;
39
39
  metaTitle?: string | undefined;
@@ -57,9 +57,9 @@ export declare const blogPostUpdateSchema: z.ZodObject<Omit<{
57
57
  title?: string | undefined;
58
58
  content?: string | undefined;
59
59
  category?: string | undefined;
60
- youtubeId?: string | undefined;
61
60
  tags?: string[] | undefined;
62
61
  isFeatured?: boolean | undefined;
62
+ youtubeId?: string | undefined;
63
63
  coverImage?: string | undefined;
64
64
  excerpt?: string | undefined;
65
65
  metaTitle?: string | undefined;
@@ -69,9 +69,9 @@ export declare const blogPostUpdateSchema: z.ZodObject<Omit<{
69
69
  title?: string | undefined;
70
70
  content?: string | undefined;
71
71
  category?: string | undefined;
72
- youtubeId?: string | undefined;
73
72
  tags?: string[] | undefined;
74
73
  isFeatured?: boolean | undefined;
74
+ youtubeId?: string | undefined;
75
75
  coverImage?: string | undefined;
76
76
  excerpt?: string | undefined;
77
77
  metaTitle?: string | undefined;
@@ -108,16 +108,13 @@ export declare const BUNDLE_COPY: {
108
108
  };
109
109
  readonly stockBadge: {
110
110
  readonly in_stock: "In stock";
111
- readonly partial: "Some items unavailable";
112
- readonly out_of_stock: "Currently out of stock";
111
+ readonly out_of_stock: "Not active";
113
112
  readonly listVariantInStock: "In stock";
114
- readonly listVariantPartial: "Partial";
115
- readonly listVariantOutOfStock: "Out of stock";
113
+ readonly listVariantOutOfStock: "Not active";
116
114
  };
117
115
  };
118
116
  /** Stock-status variant mapping (kept here so consumers can drive Badge variant prop). */
119
117
  export declare const BUNDLE_STOCK_VARIANT: {
120
118
  readonly in_stock: "success";
121
- readonly partial: "warning";
122
- readonly out_of_stock: "danger";
119
+ readonly out_of_stock: "warning";
123
120
  };
@@ -119,16 +119,13 @@ export const BUNDLE_COPY = {
119
119
  // Stock badges (shared between list + featured + detail)
120
120
  stockBadge: {
121
121
  in_stock: "In stock",
122
- partial: "Some items unavailable",
123
- out_of_stock: "Currently out of stock",
122
+ out_of_stock: "Not active",
124
123
  listVariantInStock: "In stock",
125
- listVariantPartial: "Partial",
126
- listVariantOutOfStock: "Out of stock",
124
+ listVariantOutOfStock: "Not active",
127
125
  },
128
126
  };
129
127
  /** Stock-status variant mapping (kept here so consumers can drive Badge variant prop). */
130
128
  export const BUNDLE_STOCK_VARIANT = {
131
129
  in_stock: "success",
132
- partial: "warning",
133
- out_of_stock: "danger",
130
+ out_of_stock: "warning",
134
131
  };
@@ -25,34 +25,34 @@ export declare const bundleQueryRuleSchema: z.ZodDiscriminatedUnion<"type", [z.Z
25
25
  tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
26
26
  listingType: z.ZodOptional<z.ZodEnum<["standard", "pre-order"]>>;
27
27
  }, "strip", z.ZodTypeAny, {
28
- listingType?: "standard" | "pre-order" | undefined;
29
- brandSlug?: string | undefined;
30
28
  tags?: string[] | undefined;
31
- categorySlug?: string | undefined;
32
- }, {
33
29
  listingType?: "standard" | "pre-order" | undefined;
30
+ categorySlug?: string | undefined;
34
31
  brandSlug?: string | undefined;
32
+ }, {
35
33
  tags?: string[] | undefined;
34
+ listingType?: "standard" | "pre-order" | undefined;
36
35
  categorySlug?: string | undefined;
36
+ brandSlug?: string | undefined;
37
37
  }>;
38
38
  orderBy: z.ZodOptional<z.ZodEnum<["price-asc", "price-desc", "createdAt-desc"]>>;
39
39
  limit: z.ZodNumber;
40
40
  }, "strip", z.ZodTypeAny, {
41
41
  filter: {
42
- listingType?: "standard" | "pre-order" | undefined;
43
- brandSlug?: string | undefined;
44
42
  tags?: string[] | undefined;
43
+ listingType?: "standard" | "pre-order" | undefined;
45
44
  categorySlug?: string | undefined;
45
+ brandSlug?: string | undefined;
46
46
  };
47
47
  type: "dynamic";
48
48
  limit: number;
49
49
  orderBy?: "price-asc" | "price-desc" | "createdAt-desc" | undefined;
50
50
  }, {
51
51
  filter: {
52
- listingType?: "standard" | "pre-order" | undefined;
53
- brandSlug?: string | undefined;
54
52
  tags?: string[] | undefined;
53
+ listingType?: "standard" | "pre-order" | undefined;
55
54
  categorySlug?: string | undefined;
55
+ brandSlug?: string | undefined;
56
56
  };
57
57
  type: "dynamic";
58
58
  limit: number;
@@ -93,34 +93,34 @@ export declare const bundleCreateSchema: z.ZodObject<{
93
93
  tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
94
94
  listingType: z.ZodOptional<z.ZodEnum<["standard", "pre-order"]>>;
95
95
  }, "strip", z.ZodTypeAny, {
96
- listingType?: "standard" | "pre-order" | undefined;
97
- brandSlug?: string | undefined;
98
96
  tags?: string[] | undefined;
99
- categorySlug?: string | undefined;
100
- }, {
101
97
  listingType?: "standard" | "pre-order" | undefined;
98
+ categorySlug?: string | undefined;
102
99
  brandSlug?: string | undefined;
100
+ }, {
103
101
  tags?: string[] | undefined;
102
+ listingType?: "standard" | "pre-order" | undefined;
104
103
  categorySlug?: string | undefined;
104
+ brandSlug?: string | undefined;
105
105
  }>;
106
106
  orderBy: z.ZodOptional<z.ZodEnum<["price-asc", "price-desc", "createdAt-desc"]>>;
107
107
  limit: z.ZodNumber;
108
108
  }, "strip", z.ZodTypeAny, {
109
109
  filter: {
110
- listingType?: "standard" | "pre-order" | undefined;
111
- brandSlug?: string | undefined;
112
110
  tags?: string[] | undefined;
111
+ listingType?: "standard" | "pre-order" | undefined;
113
112
  categorySlug?: string | undefined;
113
+ brandSlug?: string | undefined;
114
114
  };
115
115
  type: "dynamic";
116
116
  limit: number;
117
117
  orderBy?: "price-asc" | "price-desc" | "createdAt-desc" | undefined;
118
118
  }, {
119
119
  filter: {
120
- listingType?: "standard" | "pre-order" | undefined;
121
- brandSlug?: string | undefined;
122
120
  tags?: string[] | undefined;
121
+ listingType?: "standard" | "pre-order" | undefined;
123
122
  categorySlug?: string | undefined;
123
+ brandSlug?: string | undefined;
124
124
  };
125
125
  type: "dynamic";
126
126
  limit: number;
@@ -150,10 +150,10 @@ export declare const bundleCreateSchema: z.ZodObject<{
150
150
  productIds: string[];
151
151
  } | {
152
152
  filter: {
153
- listingType?: "standard" | "pre-order" | undefined;
154
- brandSlug?: string | undefined;
155
153
  tags?: string[] | undefined;
154
+ listingType?: "standard" | "pre-order" | undefined;
156
155
  categorySlug?: string | undefined;
156
+ brandSlug?: string | undefined;
157
157
  };
158
158
  type: "dynamic";
159
159
  limit: number;
@@ -176,10 +176,10 @@ export declare const bundleCreateSchema: z.ZodObject<{
176
176
  productIds: string[];
177
177
  } | {
178
178
  filter: {
179
- listingType?: "standard" | "pre-order" | undefined;
180
- brandSlug?: string | undefined;
181
179
  tags?: string[] | undefined;
180
+ listingType?: "standard" | "pre-order" | undefined;
182
181
  categorySlug?: string | undefined;
182
+ brandSlug?: string | undefined;
183
183
  };
184
184
  type: "dynamic";
185
185
  limit: number;
@@ -215,34 +215,34 @@ export declare const bundleUpdateSchema: z.ZodObject<{
215
215
  tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
216
216
  listingType: z.ZodOptional<z.ZodEnum<["standard", "pre-order"]>>;
217
217
  }, "strip", z.ZodTypeAny, {
218
- listingType?: "standard" | "pre-order" | undefined;
219
- brandSlug?: string | undefined;
220
218
  tags?: string[] | undefined;
221
- categorySlug?: string | undefined;
222
- }, {
223
219
  listingType?: "standard" | "pre-order" | undefined;
220
+ categorySlug?: string | undefined;
224
221
  brandSlug?: string | undefined;
222
+ }, {
225
223
  tags?: string[] | undefined;
224
+ listingType?: "standard" | "pre-order" | undefined;
226
225
  categorySlug?: string | undefined;
226
+ brandSlug?: string | undefined;
227
227
  }>;
228
228
  orderBy: z.ZodOptional<z.ZodEnum<["price-asc", "price-desc", "createdAt-desc"]>>;
229
229
  limit: z.ZodNumber;
230
230
  }, "strip", z.ZodTypeAny, {
231
231
  filter: {
232
- listingType?: "standard" | "pre-order" | undefined;
233
- brandSlug?: string | undefined;
234
232
  tags?: string[] | undefined;
233
+ listingType?: "standard" | "pre-order" | undefined;
235
234
  categorySlug?: string | undefined;
235
+ brandSlug?: string | undefined;
236
236
  };
237
237
  type: "dynamic";
238
238
  limit: number;
239
239
  orderBy?: "price-asc" | "price-desc" | "createdAt-desc" | undefined;
240
240
  }, {
241
241
  filter: {
242
- listingType?: "standard" | "pre-order" | undefined;
243
- brandSlug?: string | undefined;
244
242
  tags?: string[] | undefined;
243
+ listingType?: "standard" | "pre-order" | undefined;
245
244
  categorySlug?: string | undefined;
245
+ brandSlug?: string | undefined;
246
246
  };
247
247
  type: "dynamic";
248
248
  limit: number;
@@ -279,10 +279,10 @@ export declare const bundleUpdateSchema: z.ZodObject<{
279
279
  productIds: string[];
280
280
  } | {
281
281
  filter: {
282
- listingType?: "standard" | "pre-order" | undefined;
283
- brandSlug?: string | undefined;
284
282
  tags?: string[] | undefined;
283
+ listingType?: "standard" | "pre-order" | undefined;
285
284
  categorySlug?: string | undefined;
285
+ brandSlug?: string | undefined;
286
286
  };
287
287
  type: "dynamic";
288
288
  limit: number;
@@ -304,10 +304,10 @@ export declare const bundleUpdateSchema: z.ZodObject<{
304
304
  productIds: string[];
305
305
  } | {
306
306
  filter: {
307
- listingType?: "standard" | "pre-order" | undefined;
308
- brandSlug?: string | undefined;
309
307
  tags?: string[] | undefined;
308
+ listingType?: "standard" | "pre-order" | undefined;
310
309
  categorySlug?: string | undefined;
310
+ brandSlug?: string | undefined;
311
311
  };
312
312
  type: "dynamic";
313
313
  limit: number;