@mohasinac/appkit 4.2.0 → 4.3.1

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 (258) hide show
  1. package/dist/_internal/client/features/layout/navActive.d.ts +17 -0
  2. package/dist/_internal/client/features/layout/navActive.js +33 -0
  3. package/dist/_internal/server/features/auth/actions.d.ts +0 -1
  4. package/dist/_internal/server/features/auth/actions.js +0 -1
  5. package/dist/_internal/server/features/bundles/data.d.ts +22 -4
  6. package/dist/_internal/server/features/bundles/data.js +41 -4
  7. package/dist/_internal/server/features/bundles/index.d.ts +1 -1
  8. package/dist/_internal/server/features/bundles/index.js +1 -1
  9. package/dist/_internal/server/features/checkout/actions.js +7 -78
  10. package/dist/_internal/server/features/checkout/prize-bundle-gates.d.ts +5 -16
  11. package/dist/_internal/server/features/checkout/prize-bundle-gates.js +5 -30
  12. package/dist/_internal/server/features/orders/adapters.js +1 -14
  13. package/dist/_internal/server/features/products/actions.js +8 -3
  14. package/dist/_internal/server/features/products/service.d.ts +15 -0
  15. package/dist/_internal/server/features/products/service.js +41 -0
  16. package/dist/_internal/server/functions/firestore.d.ts +3 -1
  17. package/dist/_internal/server/functions/firestore.js +17 -1
  18. package/dist/_internal/server/functions/scheduled.d.ts +2 -5
  19. package/dist/_internal/server/functions/scheduled.js +6 -30
  20. package/dist/_internal/server/jobs/core/bundleStockSync.js +25 -7
  21. package/dist/_internal/server/jobs/core/countersReconcile.js +7 -1
  22. package/dist/_internal/server/jobs/core/index.d.ts +4 -4
  23. package/dist/_internal/server/jobs/core/index.js +4 -4
  24. package/dist/_internal/server/jobs/core/onPrizeDrawPaymentConfirmed.d.ts +19 -0
  25. package/dist/_internal/server/jobs/core/onPrizeDrawPaymentConfirmed.js +30 -0
  26. package/dist/_internal/server/jobs/core/paymentWindowTimeout.d.ts +2 -2
  27. package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +2 -2
  28. package/dist/_internal/server/jobs/core/prizeDrawAssignWinner.d.ts +20 -0
  29. package/dist/_internal/server/jobs/core/prizeDrawAssignWinner.js +113 -0
  30. package/dist/_internal/server/jobs/core/prizeDrawExpiryReveal.d.ts +14 -0
  31. package/dist/_internal/server/jobs/core/prizeDrawExpiryReveal.js +74 -0
  32. package/dist/_internal/server/jobs/core/prizeDrawSoldOutReveal.d.ts +22 -0
  33. package/dist/_internal/server/jobs/core/prizeDrawSoldOutReveal.js +68 -0
  34. package/dist/_internal/server/jobs/handlers/index.d.ts +3 -4
  35. package/dist/_internal/server/jobs/handlers/index.js +8 -6
  36. package/dist/_internal/server/jobs/handlers/onPrizeDrawPaymentConfirmed.d.ts +3 -0
  37. package/dist/_internal/server/jobs/handlers/onPrizeDrawPaymentConfirmed.js +11 -0
  38. package/dist/_internal/server/jobs/handlers/prizeDrawExpiryReveal.d.ts +2 -0
  39. package/dist/_internal/server/jobs/handlers/prizeDrawExpiryReveal.js +2 -0
  40. package/dist/_internal/server/jobs/handlers/prizeDrawSoldOutReveal.d.ts +3 -0
  41. package/dist/_internal/server/jobs/handlers/prizeDrawSoldOutReveal.js +4 -0
  42. package/dist/_internal/shared/actions/action-registry.js +40 -10
  43. package/dist/_internal/shared/checkout/rules/_defaults.js +1 -2
  44. package/dist/_internal/shared/checkout/rules/_limits.d.ts +3 -0
  45. package/dist/_internal/shared/checkout/rules/_limits.js +3 -0
  46. package/dist/_internal/shared/checkout/rules/_registry.d.ts +2 -1
  47. package/dist/_internal/shared/checkout/rules/_registry.js +2 -2
  48. package/dist/_internal/shared/checkout/rules/classified.rule.js +0 -1
  49. package/dist/_internal/shared/checkout/rules/index.d.ts +1 -1
  50. package/dist/_internal/shared/checkout/rules/index.js +1 -1
  51. package/dist/_internal/shared/checkout/rules/prize-draw.rule.js +20 -1
  52. package/dist/_internal/shared/checkout/rules/types.d.ts +17 -7
  53. package/dist/_internal/shared/features/categories/bundle-copy.d.ts +2 -0
  54. package/dist/_internal/shared/features/categories/bundle-copy.js +2 -0
  55. package/dist/_internal/shared/features/categories/bundle-pricing.d.ts +23 -0
  56. package/dist/_internal/shared/features/categories/bundle-pricing.js +25 -0
  57. package/dist/_internal/shared/listing-types/prize-draw/config.js +1 -1
  58. package/dist/constants/api-endpoints.d.ts +6 -9
  59. package/dist/constants/api-endpoints.js +5 -5
  60. package/dist/constants/field-names.d.ts +17 -1
  61. package/dist/constants/field-names.js +17 -1
  62. package/dist/features/account/components/UserSidebar.js +21 -9
  63. package/dist/features/account/hooks/useNotifications.js +5 -0
  64. package/dist/features/admin/actions/admin-actions.js +6 -0
  65. package/dist/features/admin/actions/notification-actions.js +1 -2
  66. package/dist/features/admin/components/AdminBlogEditorView.js +1 -1
  67. package/dist/features/admin/components/AdminGuideHubView.js +15 -1
  68. package/dist/features/admin/components/AdminPaymentsGuideView.d.ts +2 -0
  69. package/dist/features/admin/components/AdminPaymentsGuideView.js +36 -0
  70. package/dist/features/admin/components/AdminPrizeDrawsView.js +3 -3
  71. package/dist/features/admin/components/AdminSidebar.js +18 -9
  72. package/dist/features/admin/components/AdminSiteSettingsView.js +33 -6
  73. package/dist/features/admin/components/AdminTesterChecklistView.js +74 -22
  74. package/dist/features/admin/components/AdminWhatsAppGuideView.d.ts +2 -0
  75. package/dist/features/admin/components/AdminWhatsAppGuideView.js +35 -0
  76. package/dist/features/admin/hooks/useAdminListing.d.ts +4 -0
  77. package/dist/features/admin/hooks/useAdminListing.js +4 -2
  78. package/dist/features/admin/schemas/firestore.d.ts +13 -5
  79. package/dist/features/admin/schemas/firestore.js +1 -2
  80. package/dist/features/auctions/actions/bid-actions.js +3 -1
  81. package/dist/features/auctions/components/AuctionBidsTable.d.ts +6 -1
  82. package/dist/features/auctions/components/AuctionBidsTable.js +8 -4
  83. package/dist/features/auctions/components/AuctionDetailPageView.js +10 -13
  84. package/dist/features/auctions/components/CollapsibleBidHistory.d.ts +23 -2
  85. package/dist/features/auctions/components/CollapsibleBidHistory.js +22 -3
  86. package/dist/features/auctions/components/LiveBidPrice.d.ts +19 -0
  87. package/dist/features/auctions/components/LiveBidPrice.js +17 -0
  88. package/dist/features/auctions/components/PlaceBidFormClient.d.ts +1 -1
  89. package/dist/features/auctions/components/PlaceBidFormClient.js +16 -1
  90. package/dist/features/auctions/hooks/useBids.d.ts +33 -0
  91. package/dist/features/auctions/hooks/useBids.js +32 -0
  92. package/dist/features/auctions/hooks/useLiveAuctionBid.d.ts +20 -0
  93. package/dist/features/auctions/hooks/useLiveAuctionBid.js +23 -0
  94. package/dist/features/auth/checkout-value-otp.d.ts +7 -10
  95. package/dist/features/auth/checkout-value-otp.js +14 -10
  96. package/dist/features/auth/server.d.ts +0 -1
  97. package/dist/features/auth/server.js +0 -1
  98. package/dist/features/blog/api/[slug]/route.d.ts +5 -0
  99. package/dist/features/blog/api/[slug]/route.js +12 -3
  100. package/dist/features/blog/components/BlogPostView.d.ts +2 -0
  101. package/dist/features/blog/components/BlogPostView.js +5 -4
  102. package/dist/features/blog/hooks/useBlog.d.ts +2 -0
  103. package/dist/features/blog/hooks/useBlog.js +2 -0
  104. package/dist/features/blog/repository/blog.repository.d.ts +7 -0
  105. package/dist/features/blog/repository/blog.repository.js +44 -0
  106. package/dist/features/blog/schemas/firestore.d.ts +3 -0
  107. package/dist/features/blog/schemas/firestore.js +1 -0
  108. package/dist/features/blog/types/index.d.ts +2 -0
  109. package/dist/features/cart/components/index.d.ts +0 -2
  110. package/dist/features/cart/components/index.js +0 -1
  111. package/dist/features/cart/hooks/useCartCount.js +22 -5
  112. package/dist/features/cart/hooks/useGuestCart.js +11 -1
  113. package/dist/features/cart/utils/guest-cart.d.ts +4 -0
  114. package/dist/features/cart/utils/guest-cart.js +10 -0
  115. package/dist/features/cart/utils/pending-ops.d.ts +17 -0
  116. package/dist/features/cart/utils/pending-ops.js +46 -5
  117. package/dist/features/categories/components/BrandDetailPageView.js +6 -2
  118. package/dist/features/categories/components/BundleDetailView.js +4 -2
  119. package/dist/features/categories/components/CategoryDetailPageView.js +10 -2
  120. package/dist/features/categories/schemas/firestore.d.ts +7 -0
  121. package/dist/features/checkout/actions/index.d.ts +0 -1
  122. package/dist/features/checkout/actions/index.js +0 -1
  123. package/dist/features/checkout/schemas/firestore.d.ts +2 -2
  124. package/dist/features/events/actions/event-actions.d.ts +2 -0
  125. package/dist/features/events/actions/event-actions.js +5 -0
  126. package/dist/features/events/components/EventCard.js +2 -3
  127. package/dist/features/events/components/RelatedEventsCarousel.d.ts +15 -0
  128. package/dist/features/events/components/RelatedEventsCarousel.js +13 -0
  129. package/dist/features/events/components/index.d.ts +2 -0
  130. package/dist/features/events/components/index.js +1 -0
  131. package/dist/features/events/repository/events.repository.d.ts +6 -0
  132. package/dist/features/events/repository/events.repository.js +21 -0
  133. package/dist/features/history/repository/user-history.repository.d.ts +1 -1
  134. package/dist/features/history/utils/guest-history.d.ts +1 -1
  135. package/dist/features/homepage/components/FeaturedBundlesSection.js +4 -2
  136. package/dist/features/homepage/components/FeaturedProductsSection.js +2 -2
  137. package/dist/features/homepage/components/SectionCarousel.js +1 -1
  138. package/dist/features/homepage/components/WelcomeSection.js +1 -1
  139. package/dist/features/layout/AppLayoutShell.js +44 -10
  140. package/dist/features/layout/NavbarLayout.js +1 -1
  141. package/dist/features/layout/TitleBarLayout.js +2 -2
  142. package/dist/features/media/MediaVideo.d.ts +7 -0
  143. package/dist/features/media/MediaVideo.js +36 -5
  144. package/dist/features/orders/components/OrdersList.js +1 -5
  145. package/dist/features/orders/schemas/firestore.d.ts +2 -8
  146. package/dist/features/orders/schemas/index.d.ts +3 -32
  147. package/dist/features/orders/schemas/index.js +1 -4
  148. package/dist/features/orders/types/index.d.ts +6 -9
  149. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +1 -1
  150. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +2 -1
  151. package/dist/features/products/actions/product-actions.js +13 -10
  152. package/dist/features/products/components/MarketplaceBundleCard.d.ts +1 -1
  153. package/dist/features/products/components/MarketplaceBundleCard.js +7 -4
  154. package/dist/features/products/components/PrizeDrawDetailPageView.js +1 -1
  155. package/dist/features/products/components/PrizeDrawItemsEditor.js +2 -2
  156. package/dist/features/products/components/PrizeDrawWinnerMappingView.d.ts +14 -0
  157. package/dist/features/products/components/PrizeDrawWinnerMappingView.js +37 -0
  158. package/dist/features/products/components/PrizeRevealModal.d.ts +10 -23
  159. package/dist/features/products/components/PrizeRevealModal.js +18 -147
  160. package/dist/features/products/components/ProductDetailPageView.js +72 -30
  161. package/dist/features/products/components/ProductForm.js +7 -14
  162. package/dist/features/products/components/ProductGalleryClient.d.ts +10 -1
  163. package/dist/features/products/components/ProductGalleryClient.js +29 -10
  164. package/dist/features/products/components/ProductsIndexListing.js +2 -1
  165. package/dist/features/products/components/RelatedProductsCarousel.js +2 -2
  166. package/dist/features/products/components/ShowGroupSection.js +2 -2
  167. package/dist/features/products/components/SublistingCarouselSection.js +1 -1
  168. package/dist/features/products/components/index.d.ts +4 -2
  169. package/dist/features/products/components/index.js +1 -0
  170. package/dist/features/products/constants/action-defs.d.ts +1 -3
  171. package/dist/features/products/constants/action-defs.js +0 -5
  172. package/dist/features/products/repository/products.repository.d.ts +6 -0
  173. package/dist/features/products/repository/products.repository.js +20 -1
  174. package/dist/features/products/schemas/firestore.d.ts +28 -3
  175. package/dist/features/products/schemas/index.d.ts +11 -3
  176. package/dist/features/products/schemas/index.js +10 -2
  177. package/dist/features/products/types/index.d.ts +2 -1
  178. package/dist/features/reviews/actions/review-actions.js +1 -0
  179. package/dist/features/reviews/components/ReviewDetailPageView.js +8 -1
  180. package/dist/features/reviews/components/ReviewDetailShell.js +2 -1
  181. package/dist/features/reviews/components/ReviewsList.js +2 -1
  182. package/dist/features/reviews/schemas/firestore.d.ts +3 -0
  183. package/dist/features/reviews/schemas/index.d.ts +6 -0
  184. package/dist/features/reviews/schemas/index.js +2 -0
  185. package/dist/features/reviews/types/index.d.ts +3 -0
  186. package/dist/features/scams/actions/scam-actions.d.ts +3 -0
  187. package/dist/features/scams/actions/scam-actions.js +3 -2
  188. package/dist/features/scams/components/ScamProfileView.d.ts +2 -1
  189. package/dist/features/scams/components/ScamProfileView.js +2 -2
  190. package/dist/features/scams/repository/scammer.repository.d.ts +6 -0
  191. package/dist/features/scams/repository/scammer.repository.js +24 -0
  192. package/dist/features/seller/actions/seller-actions.js +8 -0
  193. package/dist/features/seller/components/SellerPrizeDrawsView.js +4 -0
  194. package/dist/features/seller/components/SellerSidebar.js +20 -9
  195. package/dist/features/stores/components/StoreDetailLayoutView.js +6 -6
  196. package/dist/features/stores/components/StoreGuideHubView.js +7 -1
  197. package/dist/features/stores/components/StoreNavTabs.d.ts +10 -1
  198. package/dist/features/stores/components/StoreNavTabs.js +22 -9
  199. package/dist/features/stores/components/StoreWhatsAppGuideView.d.ts +3 -0
  200. package/dist/features/stores/components/StoreWhatsAppGuideView.js +12 -0
  201. package/dist/features/stores/components/index.d.ts +2 -0
  202. package/dist/features/stores/components/index.js +1 -0
  203. package/dist/features/tester/actions/index.d.ts +1 -0
  204. package/dist/features/tester/actions/index.js +1 -0
  205. package/dist/features/tester/actions/leaderboard-actions.d.ts +3 -0
  206. package/dist/features/tester/actions/leaderboard-actions.js +5 -0
  207. package/dist/features/tester/components/AdminTesterFeedbackIssuesView.js +26 -4
  208. package/dist/features/tester/components/AdminTesterFeedbackListView.js +13 -0
  209. package/dist/features/tester/components/BugHunterLeaderboardView.d.ts +23 -0
  210. package/dist/features/tester/components/BugHunterLeaderboardView.js +18 -0
  211. package/dist/features/tester/components/index.d.ts +2 -0
  212. package/dist/features/tester/components/index.js +1 -0
  213. package/dist/features/tester/repository/tester-checklist-item.repository.d.ts +12 -1
  214. package/dist/features/tester/repository/tester-checklist-item.repository.js +80 -0
  215. package/dist/features/tester/repository/tester-checklist-response.repository.d.ts +4 -0
  216. package/dist/features/tester/repository/tester-checklist-response.repository.js +4 -0
  217. package/dist/features/tester/schemas/firestore.d.ts +22 -1
  218. package/dist/features/tester/schemas/firestore.js +8 -0
  219. package/dist/features/tester/seed-data/categories-tester-seed-data.js +42 -7
  220. package/dist/features/tester/seed-data/events-tester-seed-data.js +23 -0
  221. package/dist/features/tester/seed-data/orders-tester-seed-data.js +69 -31
  222. package/dist/features/tester/seed-data/products-tester-seed-data.js +154 -9
  223. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +252 -15
  224. package/dist/features/wishlist/hooks/useGuestWishlist.js +11 -1
  225. package/dist/features/wishlist/hooks/useWishlistCount.js +16 -2
  226. package/dist/features/wishlist/utils/guest-wishlist.d.ts +5 -0
  227. package/dist/features/wishlist/utils/guest-wishlist.js +11 -0
  228. package/dist/index.d.ts +23 -22
  229. package/dist/index.js +31 -58
  230. package/dist/jobs.d.ts +1 -1
  231. package/dist/jobs.js +2 -2
  232. package/dist/next/routing/route-map.d.ts +9 -2
  233. package/dist/next/routing/route-map.js +4 -1
  234. package/dist/schemas/registry.d.ts +6 -26
  235. package/dist/seed/bids-seed-data.js +14 -2
  236. package/dist/seed/blog-posts-seed-data.js +2 -1
  237. package/dist/seed/categories-seed-data.js +11 -2
  238. package/dist/seed/events-seed-data.js +11 -11
  239. package/dist/seed/faq-seed-data.js +5 -1
  240. package/dist/seed/products-auctions-seed-data.js +2 -2
  241. package/dist/seed/products-preorders-seed-data.d.ts +2 -1
  242. package/dist/seed/products-prize-draws-seed-data.js +56 -10
  243. package/dist/seed/products-standard-seed-data.js +80 -3
  244. package/dist/seed/scammers-seed-data.js +75 -2
  245. package/dist/seed/site-settings-seed-data.js +5 -2
  246. package/dist/server-entry.d.ts +0 -1
  247. package/dist/server-entry.js +0 -1
  248. package/dist/server.d.ts +4 -20
  249. package/dist/server.js +10 -57
  250. package/dist/styles.css +1 -277
  251. package/dist/tailwind-utilities.css +1 -1
  252. package/dist/ui/components/BaseListingCard.js +1 -1
  253. package/dist/ui/components/ImageLightbox.d.ts +9 -0
  254. package/dist/ui/components/ImageLightbox.js +6 -3
  255. package/dist/ui/components/ListingToolbar.d.ts +18 -1
  256. package/dist/ui/components/ListingToolbar.js +5 -2
  257. package/dist/ui/components/StickyToolbar.js +13 -8
  258. package/package.json +1 -1
@@ -0,0 +1,18 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import { Div, Row, Span, Stack, Text } from "../../../ui";
4
+ export function BugHunterLeaderboardView({ isLoading = false, isEmpty = false, renderList, renderEntry, entries = [], renderEmpty, renderSkeleton, labels = {}, className = "", }) {
5
+ if (isLoading) {
6
+ if (renderSkeleton)
7
+ return _jsx(_Fragment, { children: renderSkeleton() });
8
+ return _jsx(Row, { justify: "center", padding: "y-xl", children: "Loading\u2026" });
9
+ }
10
+ if (isEmpty) {
11
+ if (renderEmpty)
12
+ return _jsx(_Fragment, { children: renderEmpty() });
13
+ return (_jsx(Text, { paddingY: "md", variant: "secondary", size: "sm", align: "start", children: labels.noEntries ?? "No confirmed bugs yet." }));
14
+ }
15
+ if (renderList)
16
+ return _jsx(Div, { className: className, children: renderList() });
17
+ return (_jsx(Stack, { className: `${className}`, gap: "sm", children: entries.map((entry, i) => renderEntry ? (_jsx(React.Fragment, { children: renderEntry(entry, i) }, entry.hunterId)) : (_jsxs(Div, { layout: "flex", align: "center", justify: "between", rounded: "xl", padding: "sm", className: "border", "data-section": "bughunterleaderboard-div", children: [_jsxs(Span, { weight: "medium", children: ["#", entry.rank, " ", entry.hunterName] }), _jsxs(Span, { children: [entry.bugCount, " ", labels.bugs ?? "bugs"] })] }, entry.hunterId))) }));
18
+ }
@@ -9,3 +9,5 @@ export { AdminTesterFeedbackReportView } from "./AdminTesterFeedbackReportView";
9
9
  export { AdminTesterFeedbackIssuesView } from "./AdminTesterFeedbackIssuesView";
10
10
  export { AdminTesterFeedbackListView } from "./AdminTesterFeedbackListView";
11
11
  export type { AdminTesterFeedbackListViewProps } from "./AdminTesterFeedbackListView";
12
+ export { BugHunterLeaderboardView } from "./BugHunterLeaderboardView";
13
+ export type { BugHunterLeaderboardViewProps } from "./BugHunterLeaderboardView";
@@ -5,3 +5,4 @@ export { AdminTesterFeedbackView } from "./AdminTesterFeedbackView";
5
5
  export { AdminTesterFeedbackReportView } from "./AdminTesterFeedbackReportView";
6
6
  export { AdminTesterFeedbackIssuesView } from "./AdminTesterFeedbackIssuesView";
7
7
  export { AdminTesterFeedbackListView } from "./AdminTesterFeedbackListView";
8
+ export { BugHunterLeaderboardView } from "./BugHunterLeaderboardView";
@@ -1,6 +1,6 @@
1
1
  import { BaseRepository } from "../../../providers/db-firebase";
2
2
  import type { FirebaseSieveFields, FirebaseSieveResult, SieveModel } from "../../../providers/db-firebase";
3
- import { type TesterChecklistItemDocument, type TesterChecklistItemCreateInput, type TesterChecklistItemUpdateInput } from "../schemas/firestore";
3
+ import { type TesterChecklistItemDocument, type TesterChecklistItemCreateInput, type TesterChecklistItemUpdateInput, type BugHunterLeaderboardEntry } from "../schemas/firestore";
4
4
  export declare class TesterChecklistItemRepository extends BaseRepository<TesterChecklistItemDocument> {
5
5
  static readonly SIEVE_FIELDS: FirebaseSieveFields;
6
6
  constructor();
@@ -9,5 +9,16 @@ export declare class TesterChecklistItemRepository extends BaseRepository<Tester
9
9
  update(id: string, data: TesterChecklistItemUpdateInput): Promise<TesterChecklistItemDocument>;
10
10
  listActive(): Promise<TesterChecklistItemDocument[]>;
11
11
  list(model: SieveModel): Promise<FirebaseSieveResult<TesterChecklistItemDocument>>;
12
+ /** Confirms a reported "No" as a real bug: credits the reporting tester and
13
+ * disables the case for all other testers. Credit is permanent — never
14
+ * touched again by reopenAsNewVersion(). */
15
+ confirmBug(id: string, hunterId: string, hunterName: string): Promise<TesterChecklistItemDocument>;
16
+ /** Reopens a fixed, bug-confirmed case as a new, active version for retest.
17
+ * The old item stays disabled forever with its bug-hunter credit intact. */
18
+ reopenAsNewVersion(oldItemId: string): Promise<TesterChecklistItemDocument>;
19
+ /** Single-query, in-memory aggregation of bug credits per hunter — mirrors
20
+ * EventEntryRepository.getLeaderboard()'s shape. Includes old/disabled/
21
+ * superseded items, since bug credit is permanent. */
22
+ getBugHunterLeaderboard(limit?: number): Promise<BugHunterLeaderboardEntry[]>;
12
23
  }
13
24
  export declare const testerChecklistItemRepository: TesterChecklistItemRepository;
@@ -42,6 +42,85 @@ export class TesterChecklistItemRepository extends BaseRepository {
42
42
  async list(model) {
43
43
  return this.sieveQuery(model, TesterChecklistItemRepository.SIEVE_FIELDS);
44
44
  }
45
+ /** Confirms a reported "No" as a real bug: credits the reporting tester and
46
+ * disables the case for all other testers. Credit is permanent — never
47
+ * touched again by reopenAsNewVersion(). */
48
+ async confirmBug(id, hunterId, hunterName) {
49
+ const current = await this.findById(id);
50
+ if (!current) {
51
+ throw new DatabaseError(`Failed to confirm bug: missing checklist item ${id}`);
52
+ }
53
+ if (current.bugConfirmed) {
54
+ throw new DatabaseError(`Checklist item ${id} already has a confirmed bug`);
55
+ }
56
+ return this.update(id, {
57
+ isActive: false,
58
+ bugConfirmed: true,
59
+ bugHunterId: hunterId,
60
+ bugHunterName: hunterName,
61
+ bugConfirmedAt: new Date(),
62
+ });
63
+ }
64
+ /** Reopens a fixed, bug-confirmed case as a new, active version for retest.
65
+ * The old item stays disabled forever with its bug-hunter credit intact. */
66
+ async reopenAsNewVersion(oldItemId) {
67
+ const old = await this.findById(oldItemId);
68
+ if (!old) {
69
+ throw new DatabaseError(`Failed to reopen checklist item: missing document ${oldItemId}`);
70
+ }
71
+ if (!old.bugConfirmed) {
72
+ throw new DatabaseError(`Checklist item ${oldItemId} has no confirmed bug to reopen`);
73
+ }
74
+ if (old.supersededByItemId) {
75
+ throw new DatabaseError(`Checklist item ${oldItemId} has already been reopened`);
76
+ }
77
+ const nextVersion = (old.version ?? 1) + 1;
78
+ const newId = `${old.id}-v${nextVersion}`;
79
+ const newItem = await this.createWithId(newId, {
80
+ groupKey: old.groupKey,
81
+ groupLabel: old.groupLabel,
82
+ pageKey: old.pageKey,
83
+ pageLabel: old.pageLabel,
84
+ label: old.label,
85
+ description: old.description,
86
+ href: old.href,
87
+ order: old.order,
88
+ phase: old.phase,
89
+ adminOnly: old.adminOnly,
90
+ isActive: true,
91
+ version: nextVersion,
92
+ previousVersionId: old.id,
93
+ searchTokens: this.buildSearchTokens(old),
94
+ });
95
+ await this.update(old.id, { supersededByItemId: newId });
96
+ return newItem;
97
+ }
98
+ /** Single-query, in-memory aggregation of bug credits per hunter — mirrors
99
+ * EventEntryRepository.getLeaderboard()'s shape. Includes old/disabled/
100
+ * superseded items, since bug credit is permanent. */
101
+ async getBugHunterLeaderboard(limit = 50) {
102
+ const snapshot = await this.db
103
+ .collection(this.collection)
104
+ .where(TESTER_CHECKLIST_ITEM_FIELDS.BUG_CONFIRMED, "==", true)
105
+ .get();
106
+ const byHunter = new Map();
107
+ for (const doc of snapshot.docs) {
108
+ const item = this.mapDoc(doc);
109
+ if (!item.bugHunterId)
110
+ continue;
111
+ const entry = byHunter.get(item.bugHunterId) ?? {
112
+ name: item.bugHunterName ?? "Unknown tester",
113
+ count: 0,
114
+ };
115
+ entry.count += 1;
116
+ byHunter.set(item.bugHunterId, entry);
117
+ }
118
+ return Array.from(byHunter.entries())
119
+ .map(([hunterId, v]) => ({ hunterId, hunterName: v.name, bugCount: v.count }))
120
+ .sort((a, b) => b.bugCount - a.bugCount)
121
+ .slice(0, limit)
122
+ .map((entry, index) => ({ ...entry, rank: index + 1 }));
123
+ }
45
124
  }
46
125
  TesterChecklistItemRepository.SIEVE_FIELDS = {
47
126
  groupKey: { canFilter: true, canSort: true },
@@ -52,5 +131,6 @@ TesterChecklistItemRepository.SIEVE_FIELDS = {
52
131
  isActive: { canFilter: true, canSort: false },
53
132
  searchTokens: { canFilter: true, canSort: false },
54
133
  createdAt: { canFilter: true, canSort: true },
134
+ bugConfirmed: { canFilter: true, canSort: false },
55
135
  };
56
136
  export const testerChecklistItemRepository = new TesterChecklistItemRepository();
@@ -27,6 +27,10 @@ export type CoverageIssue = TesterChecklistResponseDocument & {
27
27
  groupLabel: string;
28
28
  pageLabel: string;
29
29
  label: string;
30
+ bugConfirmed?: boolean;
31
+ bugHunterId?: string;
32
+ bugHunterName?: string;
33
+ supersededByItemId?: string;
30
34
  };
31
35
  export interface CoverageReport {
32
36
  itemCoverage: ChecklistItemCoverage[];
@@ -105,6 +105,10 @@ export class TesterChecklistResponseRepository extends BaseRepository {
105
105
  groupLabel,
106
106
  pageLabel,
107
107
  label: catalogItem?.label ?? doc.checklistItemId,
108
+ bugConfirmed: catalogItem?.bugConfirmed,
109
+ bugHunterId: catalogItem?.bugHunterId,
110
+ bugHunterName: catalogItem?.bugHunterName,
111
+ supersededByItemId: catalogItem?.supersededByItemId,
108
112
  });
109
113
  }
110
114
  }
@@ -19,18 +19,32 @@ export interface TesterChecklistItemDocument extends BaseDocument {
19
19
  isActive: boolean;
20
20
  searchTokens: string[];
21
21
  adminOnly?: boolean;
22
+ bugConfirmed?: boolean;
23
+ bugHunterId?: string;
24
+ bugHunterName?: string;
25
+ bugConfirmedAt?: Date;
26
+ version?: number;
27
+ previousVersionId?: string;
28
+ supersededByItemId?: string;
22
29
  }
23
30
  export declare const TESTER_CHECKLIST_ITEM_COLLECTION: "testerChecklistItems";
24
31
  export declare const TESTER_CHECKLIST_ITEM_ID_PREFIX: "checklist-";
25
32
  export declare const TESTER_CHECKLIST_ITEM_INDEXED_FIELDS: readonly ["groupKey", "pageKey", "phase", "order", "isActive", "searchTokens", "createdAt"];
26
33
  export declare const DEFAULT_TESTER_CHECKLIST_ITEM_DATA: Partial<TesterChecklistItemDocument>;
27
34
  export type TesterChecklistItemCreateInput = Omit<TesterChecklistItemDocument, "id" | "createdAt" | "updatedAt" | "searchTokens">;
28
- export type TesterChecklistItemUpdateInput = Partial<Pick<TesterChecklistItemDocument, "groupKey" | "groupLabel" | "pageKey" | "pageLabel" | "label" | "description" | "href" | "order" | "phase" | "isActive" | "adminOnly">>;
35
+ export type TesterChecklistItemUpdateInput = Partial<Pick<TesterChecklistItemDocument, "groupKey" | "groupLabel" | "pageKey" | "pageLabel" | "label" | "description" | "href" | "order" | "phase" | "isActive" | "adminOnly" | "bugConfirmed" | "bugHunterId" | "bugHunterName" | "bugConfirmedAt" | "version" | "previousVersionId" | "supersededByItemId">>;
29
36
  export declare const testerChecklistItemQueryHelpers: {
30
37
  readonly byGroup: (groupKey: string) => readonly ["groupKey", "==", string];
31
38
  readonly byPage: (pageKey: string) => readonly ["pageKey", "==", string];
32
39
  readonly active: () => readonly ["isActive", "==", true];
40
+ readonly confirmedBugs: () => readonly ["bugConfirmed", "==", true];
33
41
  };
42
+ export interface BugHunterLeaderboardEntry {
43
+ rank: number;
44
+ hunterId: string;
45
+ hunterName: string;
46
+ bugCount: number;
47
+ }
34
48
  export declare function slugifyChecklistLabel(label: string): string;
35
49
  export declare function createChecklistItemId(groupKey: string, pageKey: string, label: string): string;
36
50
  export type TesterAnswer = "yes" | "no";
@@ -72,6 +86,13 @@ export declare const TESTER_CHECKLIST_ITEM_FIELDS: {
72
86
  readonly IS_ACTIVE: "isActive";
73
87
  readonly SEARCH_TOKENS: "searchTokens";
74
88
  readonly ADMIN_ONLY: "adminOnly";
89
+ readonly BUG_CONFIRMED: "bugConfirmed";
90
+ readonly BUG_HUNTER_ID: "bugHunterId";
91
+ readonly BUG_HUNTER_NAME: "bugHunterName";
92
+ readonly BUG_CONFIRMED_AT: "bugConfirmedAt";
93
+ readonly VERSION: "version";
94
+ readonly PREVIOUS_VERSION_ID: "previousVersionId";
95
+ readonly SUPERSEDED_BY_ITEM_ID: "supersededByItemId";
75
96
  readonly CREATED_AT: "createdAt";
76
97
  readonly UPDATED_AT: "updatedAt";
77
98
  };
@@ -28,6 +28,7 @@ export const testerChecklistItemQueryHelpers = {
28
28
  byGroup: (groupKey) => ["groupKey", "==", groupKey],
29
29
  byPage: (pageKey) => ["pageKey", "==", pageKey],
30
30
  active: () => ["isActive", "==", true],
31
+ confirmedBugs: () => ["bugConfirmed", "==", true],
31
32
  };
32
33
  export function slugifyChecklistLabel(label) {
33
34
  return label
@@ -81,6 +82,13 @@ export const TESTER_CHECKLIST_ITEM_FIELDS = {
81
82
  IS_ACTIVE: "isActive",
82
83
  SEARCH_TOKENS: "searchTokens",
83
84
  ADMIN_ONLY: "adminOnly",
85
+ BUG_CONFIRMED: "bugConfirmed",
86
+ BUG_HUNTER_ID: "bugHunterId",
87
+ BUG_HUNTER_NAME: "bugHunterName",
88
+ BUG_CONFIRMED_AT: "bugConfirmedAt",
89
+ VERSION: "version",
90
+ PREVIOUS_VERSION_ID: "previousVersionId",
91
+ SUPERSEDED_BY_ITEM_ID: "supersededByItemId",
84
92
  CREATED_AT: "createdAt",
85
93
  UPDATED_AT: "updatedAt",
86
94
  };
@@ -1,9 +1,11 @@
1
1
  /*
2
- * WHY: Shared tester sandbox — a small self-contained category tree (root + 2 leaves),
3
- * 1 brand row, and 1 bundle row so testers can exercise browsing/filtering/bundle
4
- * flows without touching real catalog data. Auto-expires after 7 days.
5
- * WHAT: Exports categoriesTesterSeedData — 3 plain categories + 1 categoryType:"brand" +
6
- * 1 categoryType:"bundle" (bundleProductIds references products-tester-seed-data.ts).
2
+ * WHY: Shared tester sandbox — a small self-contained category tree (root + 3 leaves,
3
+ * one leaf deliberately isActive:false), 1 brand row, and 1 bundle row so testers
4
+ * can exercise browsing/filtering/bundle flows without touching real catalog data.
5
+ * Auto-expires after 7 days.
6
+ * WHAT: Exports categoriesTesterSeedData — 4 plain categories + 1 categoryType:"brand" +
7
+ * 1 categoryType:"bundle" (bundleProductIds + bundleOriginalTotal reference
8
+ * products-tester-seed-data.ts).
7
9
  *
8
10
  * EXPORTS:
9
11
  * categoriesTesterSeedData — Array of Partial<CategoryDocument> for the seed runner
@@ -37,13 +39,13 @@ export const categoriesTesterSeedData = [
37
39
  description: "Disposable test category tree for the tester QA program.",
38
40
  rootId: "category-tester-sandbox",
39
41
  parentIds: [],
40
- childrenIds: ["category-tester-gadgets", "category-tester-collectibles"],
42
+ childrenIds: ["category-tester-gadgets", "category-tester-collectibles", "category-tester-inactive"],
41
43
  tier: 0,
42
44
  path: "tester-sandbox",
43
45
  order: 999,
44
46
  isLeaf: false,
45
47
  position: 0,
46
- subtreeSize: 2,
48
+ subtreeSize: 3,
47
49
  metrics: emptyMetrics,
48
50
  isFeatured: false,
49
51
  isBrand: false,
@@ -110,6 +112,36 @@ export const categoriesTesterSeedData = [
110
112
  createdAt: new Date(),
111
113
  updatedAt: new Date(),
112
114
  },
115
+ {
116
+ // Deliberately isActive:false — the entire real seed dataset (17 categories
117
+ // before this) has isActive:true on every single row, so the admin Categories
118
+ // dashboard's "isActive" toggle (backed by the categories(isActive, name ASC)
119
+ // composite index) had nothing to show when toggled to the inactive branch.
120
+ id: "category-tester-inactive",
121
+ slug: "category-tester-inactive",
122
+ name: "Test Inactive Category",
123
+ description: "Disposable test category deliberately seeded as inactive, for verifying the admin Categories isActive toggle. Auto-expires in 7 days.",
124
+ rootId: "category-tester-sandbox",
125
+ parentIds: ["category-tester-sandbox"],
126
+ childrenIds: [],
127
+ tier: 1,
128
+ path: "tester-sandbox/inactive",
129
+ order: 3,
130
+ isLeaf: true,
131
+ position: 2,
132
+ subtreeSize: 0,
133
+ metrics: emptyMetrics,
134
+ isFeatured: false,
135
+ isBrand: false,
136
+ isActive: false,
137
+ isSearchable: false,
138
+ showOnHomepage: false,
139
+ createdBy: "user-admin-letitrip",
140
+ isTestData: true,
141
+ testDataExpiresAt: testDataExpiresAt(),
142
+ createdAt: new Date(),
143
+ updatedAt: new Date(),
144
+ },
113
145
  // ── BRAND ────────────────────────────────────────────────────────────────
114
146
  {
115
147
  id: "brand-tester-sandbox",
@@ -153,6 +185,9 @@ export const categoriesTesterSeedData = [
153
185
  type: "static",
154
186
  productIds: ["product-tester-standard-1", "product-tester-standard-2"],
155
187
  },
188
+ bundleProductIds: ["product-tester-standard-1", "product-tester-standard-2"],
189
+ bundleOriginalTotal: 348, // 199 + 149
190
+ bundleStockStatus: "in_stock",
156
191
  rootId: "bundle-tester-sandbox",
157
192
  parentIds: [],
158
193
  childrenIds: [],
@@ -95,4 +95,27 @@ export const eventsTesterSeedData = [
95
95
  createdAt: new Date(),
96
96
  updatedAt: new Date(),
97
97
  },
98
+ {
99
+ id: "event-tester-sandbox-offer",
100
+ slug: "tester-sandbox-offer",
101
+ type: EVENT_FIELDS.TYPE_VALUES.OFFER,
102
+ title: "Tester Sandbox — Offer Coupon",
103
+ description: "Disposable test event for the tester QA program. Verify the Overview tab shows the coupon code and the Copy code button copies it to the clipboard.",
104
+ status: EVENT_FIELDS.STATUS_VALUES.ACTIVE,
105
+ startsAt: new Date(),
106
+ endsAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
107
+ coverImage: { type: "image", url: seedExtMedia("https://picsum.photos/seed/event-cover-tester-sandbox-offer-20260101/1200/600"), alt: TEST_EVENT_COVER_ALT },
108
+ tags: ["test"],
109
+ offerConfig: {
110
+ couponId: "coupon-rehan10",
111
+ displayCode: "REHAN10",
112
+ bannerText: "Test offer — not a real discount.",
113
+ },
114
+ stats: { totalEntries: 0, approvedEntries: 0, flaggedEntries: 0 },
115
+ createdBy: "user-admin-letitrip",
116
+ isTestData: true,
117
+ testDataExpiresAt: testDataExpiresAt(),
118
+ createdAt: new Date(),
119
+ updatedAt: new Date(),
120
+ },
98
121
  ];
@@ -5,7 +5,11 @@
5
5
  * without manually driving each one through the full checkout/shipping/return
6
6
  * flow first. Buyer is the dedicated user-tester-qa persona. Auto-expires in 7
7
7
  * days via testerSandboxCleanup (orders aren't cascade-deleted — see note below).
8
- * WHAT: Exports ordersTesterSeedData 13 Partial<OrderDocument> for the seed runner.
8
+ * Also includes one 5-item order specifically to exercise the "My Orders" /
9
+ * dashboard Recent Orders item-summary UI (thumbnails/title/qty for the first 3
10
+ * items + a "+N more" badge beyond that) — the other fixtures here are all
11
+ * single- or 2-item orders, which never trigger the "+N more" badge at all.
12
+ * WHAT: Exports ordersTesterSeedData — 14 Partial<OrderDocument> for the seed runner.
9
13
  *
10
14
  * NOTE: OrderDocument does not currently carry isTestData/testDataExpiresAt (unlike
11
15
  * categories/stores/products/blogPosts/events) — testerSandboxCleanup does not
@@ -14,7 +18,7 @@
14
18
  * orders is a follow-up, not blocking.
15
19
  *
16
20
  * EXPORTS:
17
- * ordersTesterSeedData — Array of 13 Partial<OrderDocument> for the seed runner
21
+ * ordersTesterSeedData — Array of 14 Partial<OrderDocument> for the seed runner
18
22
  *
19
23
  * @tag domain:orders,tester
20
24
  * @tag layer:seed
@@ -139,11 +143,16 @@ export const ordersTesterSeedData = [
139
143
  createdAt: daysAgo(1),
140
144
  updatedAt: NOW,
141
145
  },
142
- // ── Bundle purchase — group-tester-sandbox-bundle expands into its two children ──
146
+ // ── Bundle purchase — a real checkout produces ONE order item for the whole
147
+ // bundle (see addBundleToCartAction / checkout/actions.ts bundle-expansion),
148
+ // not one item per member product. Previously mis-modeled against
149
+ // "group-tester-sandbox-bundle" (a real standalone product that separately
150
+ // demonstrates the Tier-GP product-group "Set" feature, not a bundle at
151
+ // all) — the actual bundle is the categories row "bundle-tester-sandbox".
143
152
  {
144
153
  id: "order-tester-sandbox-bundle",
145
- productId: "group-tester-sandbox-bundle",
146
- productTitle: "Test Bundle — Standard #1 + Standard #2",
154
+ productId: "bundle-tester-sandbox",
155
+ productTitle: "Test Bundle",
147
156
  userId: BUYER_ID,
148
157
  userName: BUYER_NAME,
149
158
  userEmail: BUYER_EMAIL,
@@ -151,32 +160,22 @@ export const ordersTesterSeedData = [
151
160
  storeName: STORE_NAME,
152
161
  items: [
153
162
  {
154
- productId: "product-tester-standard-1",
155
- productTitle: "Test Gadget — Standard Listing #1",
163
+ productId: "bundle-tester-sandbox",
164
+ productTitle: "Test Bundle",
156
165
  listingType: "standard",
157
166
  quantity: 1,
158
167
  unitPrice: 199,
159
168
  totalPrice: 199,
160
- bundleCategorySlug: "group-tester-sandbox-bundle",
161
- bundleProductIds: ["product-tester-standard-1", "product-tester-standard-2"],
162
- },
163
- {
164
- productId: "product-tester-standard-2",
165
- productTitle: "Test Collectible — Standard Listing #2",
166
- listingType: "standard",
167
- quantity: 1,
168
- unitPrice: 149,
169
- totalPrice: 149,
170
- bundleCategorySlug: "group-tester-sandbox-bundle",
169
+ bundleCategorySlug: "bundle-tester-sandbox",
171
170
  bundleProductIds: ["product-tester-standard-1", "product-tester-standard-2"],
172
171
  },
173
172
  ],
174
173
  orderType: "standard",
175
- bundleId: "group-tester-sandbox-bundle",
174
+ bundleId: "bundle-tester-sandbox",
176
175
  isNonRefundable: true,
177
- quantity: 2,
178
- unitPrice: 164,
179
- totalPrice: 329,
176
+ quantity: 1,
177
+ unitPrice: 199,
178
+ totalPrice: 199,
180
179
  currency: "INR",
181
180
  status: "processing",
182
181
  paymentStatus: "paid",
@@ -206,13 +205,12 @@ export const ordersTesterSeedData = [
206
205
  unitPrice: 50,
207
206
  totalPrice: 50,
208
207
  prizeRevealStatus: "revealed",
209
- revealedItemNumber: 1,
210
208
  },
211
209
  ],
212
210
  orderType: "prize-draw",
213
211
  prizeDrawProductId: PRIZEDRAW_PRODUCT_ID,
212
+ prizeRevealMode: "scheduled",
214
213
  prizeWon: { itemNumber: 1, title: "Test Prize — Grand", images: [], wonAt: daysAgo(1) },
215
- prizeRevealDeadline: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
216
214
  isNonRefundable: true,
217
215
  quantity: 1,
218
216
  unitPrice: 50,
@@ -225,7 +223,11 @@ export const ordersTesterSeedData = [
225
223
  createdAt: daysAgo(1),
226
224
  updatedAt: daysAgo(1),
227
225
  },
228
- // ── Prize draw — non-winning entry, auto-refunded ────────────────────────────
226
+ // ── Prize draw — a second entry on the same closed draw, revealed to a
227
+ // different item. Every paid entry on a prize draw is eventually
228
+ // assigned some item (prizeMaxEntries === item count) — there's no
229
+ // "losing" outcome under the automatic-reveal model, unlike a lottery
230
+ // with fewer prizes than tickets. ─────────────────────────────────────
229
231
  {
230
232
  id: "order-tester-sandbox-prizedraw-lose",
231
233
  productId: PRIZEDRAW_PRODUCT_ID,
@@ -243,23 +245,59 @@ export const ordersTesterSeedData = [
243
245
  quantity: 1,
244
246
  unitPrice: 50,
245
247
  totalPrice: 50,
246
- prizeRevealStatus: "closed",
248
+ prizeRevealStatus: "revealed",
247
249
  },
248
250
  ],
249
251
  orderType: "prize-draw",
250
252
  prizeDrawProductId: PRIZEDRAW_PRODUCT_ID,
253
+ prizeRevealMode: "scheduled",
254
+ prizeWon: { itemNumber: 2, title: "Test Prize — Runner-up", images: [], wonAt: daysAgo(1) },
255
+ isNonRefundable: true,
251
256
  quantity: 1,
252
257
  unitPrice: 50,
253
258
  totalPrice: 50,
254
259
  currency: "INR",
255
- status: "refunded",
256
- paymentStatus: "refunded",
260
+ status: "delivered",
261
+ paymentStatus: "paid",
257
262
  paymentMethod: "upi_manual",
258
- refundAmount: 50,
259
- refundStatus: "completed",
260
- refundNote: "Disposable test — non-winning prize-draw entry auto-refunded after reveal.",
261
263
  orderDate: daysAgo(1),
262
264
  createdAt: daysAgo(1),
263
265
  updatedAt: NOW,
264
266
  },
267
+ // ── Multi-item order — 5 line items so the "My Orders" list / dashboard Recent
268
+ // Orders widget shows real thumbnails+title+qty for the first 3 and a genuine
269
+ // "+2 more" badge for the rest (every other fixture above tops out at 2 items).
270
+ {
271
+ id: "order-tester-sandbox-multi-item",
272
+ productId: STANDARD_PRODUCT_ID,
273
+ productTitle: STANDARD_PRODUCT_TITLE,
274
+ userId: BUYER_ID,
275
+ userName: BUYER_NAME,
276
+ userEmail: BUYER_EMAIL,
277
+ storeId: STORE_ID,
278
+ storeName: STORE_NAME,
279
+ items: [
280
+ { productId: "product-tester-standard-1", productTitle: "Test Gadget — Standard Listing #1", listingType: "standard", quantity: 1, unitPrice: 199, totalPrice: 199 },
281
+ { productId: "product-tester-standard-2", productTitle: "Test Collectible — Standard Listing #2", listingType: "standard", quantity: 1, unitPrice: 149, totalPrice: 149 },
282
+ { productId: "product-tester-standard-accessory-case", productTitle: "Test Accessory — Carry Case", listingType: "standard", quantity: 1, unitPrice: 99, totalPrice: 99 },
283
+ { productId: "product-tester-standard-accessory-stand", productTitle: "Test Accessory — Display Stand", listingType: "standard", quantity: 2, unitPrice: 49, totalPrice: 98 },
284
+ { productId: "product-tester-standard-accessory-stickers", productTitle: "Test Accessory — Sticker Set", listingType: "standard", quantity: 3, unitPrice: 19, totalPrice: 57 },
285
+ ],
286
+ orderType: "standard",
287
+ quantity: 8,
288
+ unitPrice: 199,
289
+ totalPrice: 602,
290
+ currency: "INR",
291
+ status: "delivered",
292
+ paymentStatus: "paid",
293
+ paymentMethod: "upi_manual",
294
+ shippingAddress: "addr-tester-qa-home",
295
+ trackingNumber: "TEST-TRACK-MULTI-001",
296
+ shippingCarrier: "Test Carrier",
297
+ shippingDate: daysAgo(2),
298
+ deliveryDate: daysAgo(1),
299
+ orderDate: daysAgo(3),
300
+ createdAt: daysAgo(3),
301
+ updatedAt: daysAgo(1),
302
+ },
265
303
  ];