@mohasinac/appkit 4.41.0 → 4.41.2

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 (169) hide show
  1. package/dist/features/seller/schemas/coupon-form.d.ts +37 -37
  2. package/dist/features/seller/schemas/coupon-form.js +36 -8
  3. package/dist/features/shell/SectionForm.js +44 -5
  4. package/dist/schemas/registry.d.ts +10 -10
  5. package/package.json +2 -2
  6. package/dist/_internal/server/features/classified/actions.d.ts +0 -12
  7. package/dist/_internal/server/features/classified/actions.js +0 -33
  8. package/dist/_internal/server/features/digital-code/actions.d.ts +0 -12
  9. package/dist/_internal/server/features/digital-code/actions.js +0 -33
  10. package/dist/_internal/server/features/homepage/data.d.ts +0 -18
  11. package/dist/_internal/server/features/homepage/data.js +0 -70
  12. package/dist/_internal/server/features/live/actions.d.ts +0 -6
  13. package/dist/_internal/server/features/live/actions.js +0 -27
  14. package/dist/_internal/server/features/messages/actions.d.ts +0 -6
  15. package/dist/_internal/server/features/messages/actions.js +0 -6
  16. package/dist/_internal/server/features/messages/data.d.ts +0 -10
  17. package/dist/_internal/server/features/messages/data.js +0 -24
  18. package/dist/_internal/server/features/messages/index.d.ts +0 -2
  19. package/dist/_internal/server/features/messages/index.js +0 -2
  20. package/dist/_internal/server/jobs/core/testerSandboxRefresh.d.ts +0 -12
  21. package/dist/_internal/server/jobs/core/testerSandboxRefresh.js +0 -112
  22. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.d.ts +0 -2
  23. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.js +0 -2
  24. package/dist/_internal/shared/features/homepage/section-gate.d.ts +0 -14
  25. package/dist/_internal/shared/features/homepage/section-gate.js +0 -51
  26. package/dist/_internal/shared/features/lottery/config-form.d.ts +0 -58
  27. package/dist/_internal/shared/features/lottery/config-form.js +0 -71
  28. package/dist/client/api/useFeatureFlags.d.ts +0 -22
  29. package/dist/client/api/useFeatureFlags.js +0 -27
  30. package/dist/features/account/address-validation.d.ts +0 -20
  31. package/dist/features/account/address-validation.js +0 -35
  32. package/dist/features/account/components/ChatList.d.ts +0 -14
  33. package/dist/features/account/components/ChatList.js +0 -9
  34. package/dist/features/account/components/ChatWindow.d.ts +0 -17
  35. package/dist/features/account/components/ChatWindow.js +0 -6
  36. package/dist/features/account/components/MessagesView.d.ts +0 -16
  37. package/dist/features/account/components/MessagesView.js +0 -5
  38. package/dist/features/account/components/UserOffersView.d.ts +0 -10
  39. package/dist/features/account/components/UserOffersView.js +0 -5
  40. package/dist/features/account/constants/addresses.d.ts +0 -13
  41. package/dist/features/account/constants/addresses.js +0 -43
  42. package/dist/features/account/hooks/useAddressForm.d.ts +0 -24
  43. package/dist/features/account/hooks/useAddressForm.js +0 -58
  44. package/dist/features/admin/actions/chat-actions.d.ts +0 -29
  45. package/dist/features/admin/actions/chat-actions.js +0 -101
  46. package/dist/features/admin/components/AdminFeatureFlagsView.d.ts +0 -9
  47. package/dist/features/admin/components/AdminFeatureFlagsView.js +0 -109
  48. package/dist/features/admin/components/AdminSiteView.d.ts +0 -10
  49. package/dist/features/admin/components/AdminSiteView.js +0 -52
  50. package/dist/features/admin/hooks/useChat.d.ts +0 -24
  51. package/dist/features/admin/hooks/useChat.js +0 -100
  52. package/dist/features/admin/permission-map.d.ts +0 -3
  53. package/dist/features/admin/permission-map.js +0 -26
  54. package/dist/features/admin/repository/chat.repository.d.ts +0 -50
  55. package/dist/features/admin/repository/chat.repository.js +0 -223
  56. package/dist/features/auth/actions/password-change-otp-actions.d.ts +0 -18
  57. package/dist/features/auth/actions/password-change-otp-actions.js +0 -88
  58. package/dist/features/auth/actions/realtime-token-actions.d.ts +0 -11
  59. package/dist/features/auth/actions/realtime-token-actions.js +0 -38
  60. package/dist/features/auth/password-change-otp.d.ts +0 -34
  61. package/dist/features/auth/password-change-otp.js +0 -56
  62. package/dist/features/classified/components/ClassifiedContactSellerPanel.d.ts +0 -12
  63. package/dist/features/classified/components/ClassifiedContactSellerPanel.js +0 -49
  64. package/dist/features/events/api/route.d.ts +0 -12
  65. package/dist/features/events/api/route.js +0 -90
  66. package/dist/features/faq/api/route.d.ts +0 -11
  67. package/dist/features/faq/api/route.js +0 -52
  68. package/dist/features/faq/hooks/useFAQs.d.ts +0 -22
  69. package/dist/features/faq/hooks/useFAQs.js +0 -41
  70. package/dist/features/media/upload/video-poster.test.d.ts +0 -1
  71. package/dist/features/media/upload/video-poster.test.js +0 -42
  72. package/dist/features/messages/actions/index.d.ts +0 -2
  73. package/dist/features/messages/actions/index.js +0 -2
  74. package/dist/features/messages/actions/messages-actions.d.ts +0 -15
  75. package/dist/features/messages/actions/messages-actions.js +0 -33
  76. package/dist/features/messages/actions/ping-rtdb.d.ts +0 -2
  77. package/dist/features/messages/actions/ping-rtdb.js +0 -26
  78. package/dist/features/messages/hooks/useConversation.d.ts +0 -22
  79. package/dist/features/messages/hooks/useConversation.js +0 -155
  80. package/dist/features/messages/hooks/useConversations.d.ts +0 -15
  81. package/dist/features/messages/hooks/useConversations.js +0 -104
  82. package/dist/features/messages/index.d.ts +0 -6
  83. package/dist/features/messages/index.js +0 -4
  84. package/dist/features/messages/realtime.d.ts +0 -32
  85. package/dist/features/messages/realtime.js +0 -39
  86. package/dist/features/messages/repository/conversations.repository.d.ts +0 -71
  87. package/dist/features/messages/repository/conversations.repository.js +0 -284
  88. package/dist/features/messages/schemas/firestore.d.ts +0 -34
  89. package/dist/features/messages/schemas/firestore.js +0 -16
  90. package/dist/features/messages/schemas/index.d.ts +0 -177
  91. package/dist/features/messages/schemas/index.js +0 -35
  92. package/dist/features/messages/server.d.ts +0 -6
  93. package/dist/features/messages/server.js +0 -6
  94. package/dist/features/products/components/MakeOfferForm.d.ts +0 -20
  95. package/dist/features/products/components/MakeOfferForm.js +0 -9
  96. package/dist/features/reviews/api/route.d.ts +0 -21
  97. package/dist/features/reviews/api/route.js +0 -174
  98. package/dist/features/seller/api/offers/route.d.ts +0 -17
  99. package/dist/features/seller/api/offers/route.js +0 -63
  100. package/dist/features/seller/components/SellerAuctionsView.d.ts +0 -9
  101. package/dist/features/seller/components/SellerAuctionsView.js +0 -113
  102. package/dist/features/seller/components/SellerOffersPanel.d.ts +0 -21
  103. package/dist/features/seller/components/SellerOffersPanel.js +0 -160
  104. package/dist/features/seller/components/SellerPreOrdersView.d.ts +0 -6
  105. package/dist/features/seller/components/SellerPreOrdersView.js +0 -148
  106. package/dist/features/seller/components/SellerPrizeDrawsView.d.ts +0 -6
  107. package/dist/features/seller/components/SellerPrizeDrawsView.js +0 -152
  108. package/dist/features/seller/permission-map.d.ts +0 -5
  109. package/dist/features/seller/permission-map.js +0 -17
  110. package/dist/features/shell/StepForm.d.ts +0 -80
  111. package/dist/features/shell/StepForm.js +0 -136
  112. package/dist/features/stores/api/route.d.ts +0 -12
  113. package/dist/features/stores/api/route.js +0 -110
  114. package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.d.ts +0 -2
  115. package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.js +0 -33
  116. package/dist/features/tester/seed-data/authored/account-auth__testing-program.d.ts +0 -2
  117. package/dist/features/tester/seed-data/authored/account-auth__testing-program.js +0 -138
  118. package/dist/features/tester/seed-data/bids-tester-seed-data.d.ts +0 -2
  119. package/dist/features/tester/seed-data/bids-tester-seed-data.js +0 -37
  120. package/dist/features/tester/seed-data/blog-tester-seed-data.d.ts +0 -2
  121. package/dist/features/tester/seed-data/blog-tester-seed-data.js +0 -40
  122. package/dist/features/tester/seed-data/carts-tester-seed-data.d.ts +0 -3
  123. package/dist/features/tester/seed-data/carts-tester-seed-data.js +0 -70
  124. package/dist/features/tester/seed-data/categories-tester-seed-data.d.ts +0 -2
  125. package/dist/features/tester/seed-data/categories-tester-seed-data.js +0 -218
  126. package/dist/features/tester/seed-data/coupons-tester-seed-data.d.ts +0 -2
  127. package/dist/features/tester/seed-data/coupons-tester-seed-data.js +0 -76
  128. package/dist/features/tester/seed-data/events-tester-seed-data.d.ts +0 -2
  129. package/dist/features/tester/seed-data/events-tester-seed-data.js +0 -193
  130. package/dist/features/tester/seed-data/offers-tester-seed-data.d.ts +0 -2
  131. package/dist/features/tester/seed-data/offers-tester-seed-data.js +0 -191
  132. package/dist/features/tester/seed-data/orders-tester-seed-data.d.ts +0 -2
  133. package/dist/features/tester/seed-data/orders-tester-seed-data.js +0 -329
  134. package/dist/features/tester/seed-data/products-tester-seed-data.d.ts +0 -2
  135. package/dist/features/tester/seed-data/products-tester-seed-data.js +0 -815
  136. package/dist/features/tester/seed-data/stores-tester-seed-data.d.ts +0 -2
  137. package/dist/features/tester/seed-data/stores-tester-seed-data.js +0 -79
  138. package/dist/features/wishlist/components/WishlistToggleButton.d.ts +0 -12
  139. package/dist/features/wishlist/components/WishlistToggleButton.js +0 -36
  140. package/dist/monitoring/analytics.d.ts +0 -80
  141. package/dist/monitoring/analytics.js +0 -176
  142. package/dist/next/middleware/pii-redactor.d.ts +0 -32
  143. package/dist/next/middleware/pii-redactor.js +0 -84
  144. package/dist/providers/db-firebase/realtime.d.ts +0 -42
  145. package/dist/providers/db-firebase/realtime.js +0 -138
  146. package/dist/security/rbac/Can.d.ts +0 -31
  147. package/dist/security/rbac/Can.js +0 -22
  148. package/dist/security/rbac/default-roles.d.ts +0 -2
  149. package/dist/security/rbac/default-roles.js +0 -83
  150. package/dist/security/rbac/hook.d.ts +0 -20
  151. package/dist/security/rbac/hook.js +0 -30
  152. package/dist/security/rbac/index.d.ts +0 -8
  153. package/dist/security/rbac/index.js +0 -6
  154. package/dist/security/rbac/middleware.d.ts +0 -51
  155. package/dist/security/rbac/middleware.js +0 -51
  156. package/dist/security/rbac/resolver.d.ts +0 -5
  157. package/dist/security/rbac/resolver.js +0 -38
  158. package/dist/security/rbac/server.d.ts +0 -24
  159. package/dist/security/rbac/server.js +0 -42
  160. package/dist/security/rbac/types.d.ts +0 -22
  161. package/dist/security/rbac/types.js +0 -2
  162. package/dist/seed/conversations-seed-data.d.ts +0 -2
  163. package/dist/seed/conversations-seed-data.js +0 -292
  164. package/dist/utils/filter.helper.d.ts +0 -18
  165. package/dist/utils/filter.helper.js +0 -21
  166. package/dist/utils/pagination.helper.d.ts +0 -23
  167. package/dist/utils/pagination.helper.js +0 -24
  168. package/dist/utils/search-tokens.d.ts +0 -2
  169. package/dist/utils/search-tokens.js +0 -21
@@ -1,815 +0,0 @@
1
- /*
2
- * WHY: Shared tester sandbox — a handful of disposable test products spanning every listing
3
- * type (standard, auction, pre-order, prize-draw, classified, digital-code, live, art,
4
- * stickers), all owned by store-tester-sandbox, so testers can exercise buying/bidding/
5
- * pre-ordering against real code paths — including navigating every entry of the store
6
- * detail page's listing-type dropdown (see StoreNavTabs). Auto-expires after 7 days
7
- * (testerSandboxCleanup cascades into any bids on the auction).
8
- * WHAT: Exports productsTesterSeedData — 2 standard + 4 auction (3 staggered "still open"
9
- * cycling fixtures + 1 already-ended "won" fixture) + 1 pre-order + 1 prize-draw +
10
- * 1 classified + 1 digital-code + 1 live + 1 art + 1 stickers product + 1 product-group
11
- * ("Set") parent (product-tester-standard-1/2 are its children, linked via groupId).
12
- *
13
- * Every auction end date is recomputed on each seed run from tester-window.ts, as a
14
- * FRACTION of the testing window rather than a fixed duration. At the default
15
- * 180-minute window the staggered three land on the historical 1h/2h/3h; a shorter
16
- * TESTER_WINDOW_MINUTES pulls all of them in together, which is what lets a run
17
- * actually watch an auction cross its end time.
18
- *
19
- * EXPORTS:
20
- * productsTesterSeedData — Array of Partial<ProductDocument> for the seed runner
21
- *
22
- * @tag domain:products,tester
23
- * @tag layer:seed
24
- * @tag pattern:none
25
- * @tag access:server-only
26
- * @tag consumers:seed/index.ts,seed-cli.mjs
27
- * @tag sideEffects:none
28
- */
29
- import { PRODUCT_FIELDS } from "../../../constants/field-names";
30
- import { buildSearchTxt } from "../../../utils/search-txt";
31
- import { seedPhoto } from "../../../seed/_helpers/media";
32
- import { testDataExpiresAt } from "./tester-ttl";
33
- import { windowOffset } from "./tester-window";
34
- const TESTER_STORE_ID = "store-tester-sandbox";
35
- const TESTER_STORE_NAME = "Tester Sandbox Store";
36
- const TESTER_GROUP_TITLE = "Tester Sandbox Bundle";
37
- const GADGETS_CATEGORY_SLUGS = ["category-tester-gadgets", "category-tester-sandbox"];
38
- const GADGETS_CATEGORY_NAMES = ["Test Gadgets", "Tester Sandbox"];
39
- const COLLECTIBLES_CATEGORY_SLUGS = ["category-tester-collectibles", "category-tester-sandbox"];
40
- const COLLECTIBLES_CATEGORY_NAMES = ["Test Collectibles", "Tester Sandbox"];
41
- function withTokens(p) {
42
- return {
43
- tags: [],
44
- featured: false,
45
- isTestData: true,
46
- testDataExpiresAt: testDataExpiresAt(),
47
- storeId: TESTER_STORE_ID,
48
- storeName: TESTER_STORE_NAME,
49
- ...p,
50
- searchTxt: buildSearchTxt([p.title, p.description, p.brand, p.brandSlug, p.categoryNames, p.tags]),
51
- };
52
- }
53
- // Staggered, incrementing-id auction fixtures so a tester can watch a live auction
54
- // actually cross its end time inside one session, instead of the old single fixture
55
- // that always sat 5 days out. A loop (not hand-typed ids) avoids id collisions if
56
- // the stagger list is ever extended.
57
- //
58
- // Expressed as FRACTIONS of the testing window rather than fixed hours: with the
59
- // default 180-minute window these resolve to the same 1h/2h/3h this fixture has
60
- // always used, and an automated run shortens all three together by setting
61
- // TESTER_WINDOW_MINUTES. Hard-coded hours cannot be shortened, which is what made
62
- // "watch an auction end" untestable in any run shorter than three hours.
63
- const AUCTION_CYCLE_STAGGER_FRACTIONS = [1 / 3, 2 / 3, 1];
64
- /** Deliberately past the end of the run — "plenty of clock left" fixtures must NOT expire mid-test. */
65
- const OUTLASTS_RUN = 2;
66
- /** ~1/9 of the window: 20 minutes at the default 180, 10 at a 90-minute run. Scales with the window instead of pinning 20 minutes that a short run can never reach. */
67
- const EXPIRES_MID_RUN = 1 / 9;
68
- const stagedAuctions = AUCTION_CYCLE_STAGGER_FRACTIONS.map((fraction, i) => {
69
- const endsAt = windowOffset(fraction);
70
- const endsInMinutes = Math.max(1, Math.round((endsAt.getTime() - Date.now()) / 60000));
71
- return withTokens({
72
- id: `auction-tester-sandbox-cycle-${i + 1}`,
73
- slug: `auction-tester-sandbox-cycle-${i + 1}`,
74
- title: `Test Auction — Ends in ~${endsInMinutes}m`,
75
- description: `Disposable test auction for the tester QA program, staggered to end roughly ${endsInMinutes} minute(s) after seeding so testers can watch the end-of-auction flow live. Place a bid — it auto-expires in 7 days, cascading to any bids.`,
76
- categorySlugs: COLLECTIBLES_CATEGORY_SLUGS,
77
- categoryNames: COLLECTIBLES_CATEGORY_NAMES,
78
- brandSlug: "brand-tester-sandbox",
79
- brand: "TestBrand",
80
- startingBid: 15000,
81
- currentBid: 15000,
82
- currency: "INR",
83
- price: 150,
84
- stockQuantity: 1,
85
- availableQuantity: 1,
86
- auctionEndDate: endsAt,
87
- bidCount: 0,
88
- bidsHaveStarted: false,
89
- isSold: false,
90
- mainImage: seedPhoto(`auction-image-tester-sandbox-cycle-${i + 1}-20260101`, 900, 900),
91
- images: [seedPhoto(`auction-image-tester-sandbox-cycle-${i + 1}-20260101`, 900, 900)],
92
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
93
- condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
94
- listingType: "auction",
95
- customFields: [],
96
- customSections: [],
97
- isPromoted: false,
98
- isOnSale: false,
99
- createdAt: new Date(),
100
- updatedAt: new Date(),
101
- });
102
- });
103
- /**
104
- * Buy-Now (buyout) fixtures. Four states, because the 2026-08-24 rework made
105
- * buyout availability depend on `buyNowPrice > currentBid` rather than on
106
- * "nobody has bid yet" — so the interesting cases are now about PRICE, and
107
- * three of them were previously unreachable as test data.
108
- *
109
- * Every date is Date.now()-relative at module import, per CLAUDE.md's tester
110
- * fixture standard, so each seed run re-arms them; durations come from tester-window.ts.
111
- */
112
- const buyoutAuctions = [
113
- {
114
- key: "buyout",
115
- title: "Test Auction — Buy It Now available",
116
- desc: "The clean buyout case. Buy Now is offered, there is plenty of clock, and completing checkout within the hour should close the auction as sold with your bid recorded at the buyout price.",
117
- currentBid: 8000,
118
- buyNowPrice: 12000,
119
- bidCount: 0,
120
- bidsHaveStarted: false,
121
- endsAtFraction: OUTLASTS_RUN,
122
- },
123
- {
124
- key: "buyout-contested",
125
- title: "Test Auction — Buy It Now with live bidding",
126
- desc: "Buy Now is STILL offered even though bidding has started, because the buyout price is above the current bid. Buying it out should mark the other bidders lost. This case did not exist before the bidsHaveStarted gate was dropped.",
127
- currentBid: 9500,
128
- buyNowPrice: 12000,
129
- bidCount: 2,
130
- bidsHaveStarted: true,
131
- endsAtFraction: OUTLASTS_RUN,
132
- },
133
- {
134
- key: "buyout-passed",
135
- title: "Test Auction — bidding passed Buy It Now",
136
- desc: "Negative control. Bidding has overtaken the buyout price, so Buy Now must appear NOWHERE — no button, no advertised price on the detail page, no Buyout chip on the card.",
137
- currentBid: 9500,
138
- buyNowPrice: 9000,
139
- bidCount: 5,
140
- bidsHaveStarted: true,
141
- endsAtFraction: OUTLASTS_RUN,
142
- },
143
- {
144
- key: "buyout-expiring",
145
- title: "Test Auction — Buy It Now, ends in ~20 minutes",
146
- desc: "The buyout hold is clamped to the auction's own end time rather than the full hour. Start a buyout here and DON'T finish checkout: when the clock runs out the buyout must fail and the item must go to the bidding, not to you.",
147
- currentBid: 3000,
148
- buyNowPrice: 5000,
149
- bidCount: 1,
150
- bidsHaveStarted: true,
151
- endsAtFraction: EXPIRES_MID_RUN,
152
- },
153
- ].map((f) => withTokens({
154
- id: `auction-tester-sandbox-${f.key}`,
155
- slug: `auction-tester-sandbox-${f.key}`,
156
- title: f.title,
157
- description: f.desc,
158
- categorySlugs: COLLECTIBLES_CATEGORY_SLUGS,
159
- categoryNames: COLLECTIBLES_CATEGORY_NAMES,
160
- brandSlug: "brand-tester-sandbox",
161
- brand: "TestBrand",
162
- startingBid: 8000,
163
- currentBid: f.currentBid,
164
- buyNowPrice: f.buyNowPrice,
165
- currency: "INR",
166
- price: f.currentBid,
167
- stockQuantity: 1,
168
- availableQuantity: 1,
169
- auctionEndDate: windowOffset(f.endsAtFraction),
170
- bidCount: f.bidCount,
171
- bidsHaveStarted: f.bidsHaveStarted,
172
- isSold: false,
173
- mainImage: seedPhoto(`auction-image-tester-sandbox-${f.key}-20260101`, 900, 900),
174
- images: [seedPhoto(`auction-image-tester-sandbox-${f.key}-20260101`, 900, 900)],
175
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
176
- condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
177
- listingType: "auction",
178
- customFields: [],
179
- customSections: [],
180
- isPromoted: false,
181
- isOnSale: false,
182
- createdAt: new Date(),
183
- updatedAt: new Date(),
184
- }));
185
- /**
186
- * An offerable standard listing, owned by the tester's OWN sandbox store
187
- * (`withTokens` supplies `storeId: TESTER_STORE_ID`).
188
- *
189
- * That ownership is the point: one tester can drive the whole negotiation
190
- * solo — make the offer at /products/product-tester-offerable as the buyer,
191
- * then accept/counter/decline it at /store/offers as the seller. The
192
- * complementary fixture `offer-tester-sandbox-accepted` covers the other half
193
- * (an already-accepted offer on somebody ELSE's store, so the checkout lane can
194
- * be exercised without the tester having accepted it themselves).
195
- */
196
- const offerableProduct = withTokens({
197
- id: "product-tester-offerable",
198
- slug: "product-tester-offerable",
199
- title: "Test Gadget — Accepts Offers",
200
- description: "Disposable test product with buyer offers enabled. Make an offer below the listed price and watch it appear under My Offers. Minimum accepted offer is 70% of the listed price.",
201
- categorySlugs: COLLECTIBLES_CATEGORY_SLUGS,
202
- categoryNames: COLLECTIBLES_CATEGORY_NAMES,
203
- brandSlug: "brand-tester-sandbox",
204
- brand: "TestBrand",
205
- price: 2000,
206
- currency: "INR",
207
- allowOffers: true,
208
- minOfferPercent: 70,
209
- stockQuantity: 5,
210
- availableQuantity: 5,
211
- isSold: false,
212
- mainImage: seedPhoto("product-image-tester-offerable-20260101", 900, 900),
213
- images: [seedPhoto("product-image-tester-offerable-20260101", 900, 900)],
214
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
215
- condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
216
- listingType: "standard",
217
- customFields: [],
218
- customSections: [],
219
- isPromoted: false,
220
- isOnSale: false,
221
- createdAt: new Date(),
222
- updatedAt: new Date(),
223
- });
224
- export const productsTesterSeedData = [
225
- ...stagedAuctions,
226
- ...buyoutAuctions,
227
- offerableProduct,
228
- withTokens({
229
- id: "product-tester-standard-1",
230
- slug: "product-tester-standard-1",
231
- title: "Test Gadget — Standard Listing #1",
232
- description: "Disposable test product for the tester QA program. Buy it, review it, wishlist it — it auto-expires in 7 days.",
233
- categorySlugs: GADGETS_CATEGORY_SLUGS,
234
- categoryNames: GADGETS_CATEGORY_NAMES,
235
- brandSlug: "brand-tester-sandbox",
236
- brand: "TestBrand",
237
- price: 199,
238
- currency: "INR",
239
- stockQuantity: 10,
240
- availableQuantity: 10,
241
- isSold: false,
242
- mainImage: seedPhoto("product-image-tester-standard-1-20260101", 900, 900),
243
- images: [seedPhoto("product-image-tester-standard-1-20260101", 900, 900)],
244
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
245
- condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
246
- listingType: "standard",
247
- customFields: [],
248
- customSections: [],
249
- isPromoted: false,
250
- isOnSale: false,
251
- // 18% — contrasts with member #3's 12% so one grouped line spans two rates.
252
- gstRate: 18,
253
- hsnCode: "95030090",
254
- // Child of the "group-tester-sandbox-bundle" product-group ("Set") parent
255
- // below — findByGroupId() queries products by this field directly, so
256
- // without it the parent's groupChildSlugs[] mirror is never actually
257
- // resolvable and ShowGroupSection renders nothing (members.length <= 1).
258
- groupId: "group-tester-sandbox-bundle",
259
- groupParentSlug: "group-tester-sandbox-bundle",
260
- groupTitle: TESTER_GROUP_TITLE,
261
- createdAt: new Date(),
262
- updatedAt: new Date(),
263
- }),
264
- withTokens({
265
- id: "product-tester-standard-2",
266
- slug: "product-tester-standard-2",
267
- title: "Test Collectible — Standard Listing #2",
268
- description: "Second disposable test product, referenced by the test bundle. Auto-expires in 7 days.",
269
- categorySlugs: COLLECTIBLES_CATEGORY_SLUGS,
270
- categoryNames: COLLECTIBLES_CATEGORY_NAMES,
271
- brandSlug: "brand-tester-sandbox",
272
- brand: "TestBrand",
273
- price: 149,
274
- currency: "INR",
275
- stockQuantity: 10,
276
- availableQuantity: 10,
277
- isSold: false,
278
- mainImage: seedPhoto("product-image-tester-standard-2-20260101", 900, 900),
279
- images: [seedPhoto("product-image-tester-standard-2-20260101", 900, 900)],
280
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
281
- condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
282
- listingType: "standard",
283
- customFields: [],
284
- customSections: [],
285
- isPromoted: false,
286
- isOnSale: false,
287
- gstRate: 18,
288
- hsnCode: "95030090",
289
- groupId: "group-tester-sandbox-bundle",
290
- groupParentSlug: "group-tester-sandbox-bundle",
291
- groupTitle: TESTER_GROUP_TITLE,
292
- createdAt: new Date(),
293
- updatedAt: new Date(),
294
- }),
295
- withTokens({
296
- id: "product-tester-standard-3",
297
- slug: "product-tester-standard-3",
298
- title: "Test Sticker Pack — Standard Listing #3",
299
- description: "Third member of the test product group. Carries a DIFFERENT gstRate from its siblings on purpose: it is the only fixture that exercises per-member GST proration on a grouped/bundled cart line, where taxing the whole line at one product's rate would be wrong in both directions. Auto-expires in 7 days.",
300
- categorySlugs: COLLECTIBLES_CATEGORY_SLUGS,
301
- categoryNames: COLLECTIBLES_CATEGORY_NAMES,
302
- brandSlug: "brand-tester-sandbox",
303
- brand: "TestBrand",
304
- price: 99,
305
- currency: "INR",
306
- stockQuantity: 10,
307
- availableQuantity: 10,
308
- isSold: false,
309
- mainImage: seedPhoto("product-image-tester-standard-3-20260101", 900, 900),
310
- images: [seedPhoto("product-image-tester-standard-3-20260101", 900, 900)],
311
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
312
- condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
313
- listingType: "standard",
314
- customFields: [],
315
- customSections: [],
316
- isPromoted: false,
317
- isOnSale: false,
318
- // 12% against the siblings' 18% — the whole point of this fixture.
319
- gstRate: 12,
320
- hsnCode: "49081000",
321
- groupId: "group-tester-sandbox-bundle",
322
- groupParentSlug: "group-tester-sandbox-bundle",
323
- groupTitle: TESTER_GROUP_TITLE,
324
- createdAt: new Date(),
325
- updatedAt: new Date(),
326
- }),
327
- // ── Grouped-cart-line fixtures ───────────────────────────────────────────
328
- // Each of the three below exists to make ONE picker branch testable by hand.
329
- // Without them the branch can only be reached by editing data live, which a
330
- // reseed silently wipes out.
331
- withTokens({
332
- id: "product-tester-group-soldout",
333
- slug: "product-tester-group-soldout",
334
- title: "Test Part — Sold Out (Group Member)",
335
- description: "A member of the tester product group that is deliberately out of stock. Exists so the group picker's blocked-member branch has real data: it must render a reason chip instead of a +/- stepper, and must not be selectable. Auto-expires in 7 days.",
336
- categorySlugs: COLLECTIBLES_CATEGORY_SLUGS,
337
- categoryNames: COLLECTIBLES_CATEGORY_NAMES,
338
- brandSlug: "brand-tester-sandbox",
339
- brand: "TestBrand",
340
- price: 129,
341
- currency: "INR",
342
- stockQuantity: 0,
343
- availableQuantity: 0,
344
- isSold: true,
345
- mainImage: seedPhoto("product-image-tester-group-soldout-20260101", 900, 900),
346
- images: [seedPhoto("product-image-tester-group-soldout-20260101", 900, 900)],
347
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
348
- condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
349
- listingType: "standard",
350
- customFields: [],
351
- customSections: [],
352
- isPromoted: false,
353
- isOnSale: false,
354
- gstRate: 18,
355
- hsnCode: "95030090",
356
- groupId: "group-tester-sandbox-bundle",
357
- groupParentSlug: "group-tester-sandbox-bundle",
358
- groupTitle: TESTER_GROUP_TITLE,
359
- createdAt: new Date(),
360
- updatedAt: new Date(),
361
- }),
362
- // A group whose members span TWO stores. `storeId` is the order-splitting key
363
- // and the key per-store add-ons/coupons/shipping/payout hang off, so such a
364
- // group can never become one cart line — the picker must stand down to a
365
- // read-only table rather than offer a button that always fails.
366
- // `withTokens` spreads `...p` last, so the storeId below overrides the
367
- // sandbox default on purpose.
368
- withTokens({
369
- id: "product-tester-crossstore-a",
370
- slug: "product-tester-crossstore-a",
371
- title: "Test Cross-Store Set — Seller A",
372
- description: "Parent of a deliberately CROSS-STORE tester group. Its sibling belongs to a different seller, so the group picker must render read-only with no quantity column and no \"Add selected\" button. Auto-expires in 7 days.",
373
- categorySlugs: COLLECTIBLES_CATEGORY_SLUGS,
374
- categoryNames: COLLECTIBLES_CATEGORY_NAMES,
375
- brandSlug: "brand-tester-sandbox",
376
- brand: "TestBrand",
377
- price: 259,
378
- currency: "INR",
379
- stockQuantity: 6,
380
- availableQuantity: 6,
381
- isSold: false,
382
- mainImage: seedPhoto("product-image-tester-crossstore-a-20260101", 900, 900),
383
- images: [seedPhoto("product-image-tester-crossstore-a-20260101", 900, 900)],
384
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
385
- condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
386
- listingType: "standard",
387
- customFields: [],
388
- customSections: [],
389
- isPromoted: false,
390
- isOnSale: false,
391
- gstRate: 18,
392
- isGroupParent: true,
393
- groupId: "group-tester-cross-store",
394
- groupTitle: "Tester Cross-Store Set",
395
- groupChildSlugs: ["product-tester-crossstore-b"],
396
- createdAt: new Date(),
397
- updatedAt: new Date(),
398
- }),
399
- withTokens({
400
- id: "product-tester-crossstore-b",
401
- slug: "product-tester-crossstore-b",
402
- title: "Test Cross-Store Set — Seller B",
403
- description: "Sibling of product-tester-crossstore-a, deliberately owned by a DIFFERENT store so the group spans two sellers. Still isTestData, so filterTestDataForViewer keeps it off that store's public listings for non-testers. Auto-expires in 7 days.",
404
- categorySlugs: COLLECTIBLES_CATEGORY_SLUGS,
405
- categoryNames: COLLECTIBLES_CATEGORY_NAMES,
406
- brandSlug: "brand-tester-sandbox",
407
- brand: "TestBrand",
408
- price: 189,
409
- currency: "INR",
410
- stockQuantity: 6,
411
- availableQuantity: 6,
412
- isSold: false,
413
- mainImage: seedPhoto("product-image-tester-crossstore-b-20260101", 900, 900),
414
- images: [seedPhoto("product-image-tester-crossstore-b-20260101", 900, 900)],
415
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
416
- condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
417
- listingType: "standard",
418
- customFields: [],
419
- customSections: [],
420
- isPromoted: false,
421
- isOnSale: false,
422
- gstRate: 12,
423
- // The whole point of this fixture — a different seller from its sibling.
424
- storeId: "store-beyblade-arena",
425
- storeName: "Beyblade Arena",
426
- groupId: "group-tester-cross-store",
427
- groupParentSlug: "product-tester-crossstore-a",
428
- groupTitle: "Tester Cross-Store Set",
429
- createdAt: new Date(),
430
- updatedAt: new Date(),
431
- }),
432
- withTokens({
433
- id: "product-tester-standard-sold",
434
- slug: "product-tester-standard-sold",
435
- title: "Test Collectible — Sold Out (Hidden by Default)",
436
- description: "Disposable test product deliberately seeded as sold out — exists to verify the public/admin/seller \"Show sold\" toggle actually hides it by default and reveals it when toggled on. Auto-expires in 7 days.",
437
- categorySlugs: COLLECTIBLES_CATEGORY_SLUGS,
438
- categoryNames: COLLECTIBLES_CATEGORY_NAMES,
439
- brandSlug: "brand-tester-sandbox",
440
- brand: "TestBrand",
441
- price: 179,
442
- currency: "INR",
443
- stockQuantity: 0,
444
- availableQuantity: 0,
445
- isSold: true,
446
- mainImage: seedPhoto("product-image-tester-standard-sold-20260101", 900, 900),
447
- images: [seedPhoto("product-image-tester-standard-sold-20260101", 900, 900)],
448
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
449
- condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
450
- listingType: "standard",
451
- customFields: [],
452
- customSections: [],
453
- isPromoted: false,
454
- isOnSale: false,
455
- createdAt: new Date(),
456
- updatedAt: new Date(),
457
- }),
458
- withTokens({
459
- id: "auction-tester-sandbox-won",
460
- slug: "auction-tester-sandbox-won",
461
- title: "Test Auction — Already Won",
462
- description: "Disposable test auction, already ended and won, paired with a \"won auction\" test order. Auto-expires in 7 days, cascading to its bid.",
463
- categorySlugs: COLLECTIBLES_CATEGORY_SLUGS,
464
- categoryNames: COLLECTIBLES_CATEGORY_NAMES,
465
- brandSlug: "brand-tester-sandbox",
466
- brand: "TestBrand",
467
- startingBid: 8000,
468
- currentBid: 15000,
469
- currency: "INR",
470
- price: 150,
471
- stockQuantity: 1,
472
- availableQuantity: 0,
473
- auctionEndDate: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000),
474
- bidCount: 1,
475
- bidsHaveStarted: true,
476
- leadingBidderId: "user-tester-qa",
477
- isSold: true,
478
- mainImage: seedPhoto("auction-image-tester-sandbox-won-20260101", 900, 900),
479
- images: [seedPhoto("auction-image-tester-sandbox-won-20260101", 900, 900)],
480
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
481
- condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
482
- listingType: "auction",
483
- customFields: [],
484
- customSections: [],
485
- isPromoted: false,
486
- isOnSale: false,
487
- createdAt: new Date(),
488
- updatedAt: new Date(),
489
- }),
490
- withTokens({
491
- id: "preorder-tester-sandbox-1",
492
- slug: "preorder-tester-sandbox-1",
493
- title: "Test Pre-order — Reserve Me!",
494
- description: "Disposable test pre-order for the tester QA program. Auto-expires in 7 days.",
495
- categorySlugs: GADGETS_CATEGORY_SLUGS,
496
- categoryNames: GADGETS_CATEGORY_NAMES,
497
- brandSlug: "brand-tester-sandbox",
498
- brand: "TestBrand",
499
- price: 299,
500
- currency: "INR",
501
- condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
502
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
503
- listingType: "pre-order",
504
- images: [seedPhoto("preorder-image-tester-sandbox-1-20260101", 900, 900)],
505
- mainImage: seedPhoto("preorder-image-tester-sandbox-1-20260101", 900, 900),
506
- isSold: false,
507
- // stockQuantity must be set (not just availableQuantity) — the public
508
- // listing route's default "hide sold" filter is a Firestore inequality
509
- // on stockQuantity, and Firestore excludes documents missing that field
510
- // entirely from an inequality query, not just ones where it's 0. Without
511
- // this the pre-order would be permanently invisible on the default
512
- // /pre-orders listing (2026-08-19 index-sweep session).
513
- stockQuantity: 5,
514
- availableQuantity: 5,
515
- customFields: [],
516
- customSections: [],
517
- isPromoted: false,
518
- isOnSale: false,
519
- preOrderDeliveryDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
520
- preOrderProductionStatus: "in_production",
521
- preOrderDepositPercent: 25,
522
- preOrderMaxQuantity: 50,
523
- preOrderCurrentCount: 0,
524
- preOrderCancellable: true,
525
- createdAt: new Date(),
526
- updatedAt: new Date(),
527
- }),
528
- withTokens({
529
- id: "prizedraw-tester-sandbox-1",
530
- slug: "prizedraw-tester-sandbox-1",
531
- title: "Test Prize Draw — Reveal Me!",
532
- description: "Disposable test prize-draw for the tester QA program. Buy an entry, then reveal — auto-expires in 7 days.",
533
- categorySlugs: COLLECTIBLES_CATEGORY_SLUGS,
534
- categoryNames: COLLECTIBLES_CATEGORY_NAMES,
535
- brandSlug: "brand-tester-sandbox",
536
- brand: "TestBrand",
537
- price: 50,
538
- currency: "INR",
539
- condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
540
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
541
- listingType: "prize-draw",
542
- images: [seedPhoto("prizedraw-image-tester-sandbox-1-20260101", 900, 900)],
543
- mainImage: seedPhoto("prizedraw-image-tester-sandbox-1-20260101", 900, 900),
544
- isSold: false,
545
- stockQuantity: 3,
546
- availableQuantity: 3,
547
- customFields: [],
548
- customSections: [],
549
- isPromoted: false,
550
- isOnSale: false,
551
- prizeDrawMode: "reveal",
552
- prizeRevealMode: "instant",
553
- pricePerEntry: 50,
554
- prizeMaxEntries: 3,
555
- prizeCurrentEntries: 0,
556
- prizeDrawDurationDays: 7,
557
- prizeRevealWindowStart: new Date(),
558
- prizeRevealWindowEnd: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
559
- prizeRevealStatus: "open",
560
- prizeDrawItems: [
561
- { itemNumber: 1, title: "Test Prize — Grand", description: "Disposable test grand prize.", images: [seedPhoto("prizedraw-item-1-20260101", 600, 600)], condition: "new", estimatedValue: 500, isWon: false },
562
- { itemNumber: 2, title: "Test Prize — Runner-up", description: "Disposable test runner-up prize.", images: [seedPhoto("prizedraw-item-2-20260101", 600, 600)], condition: "new", estimatedValue: 150, isWon: false },
563
- { itemNumber: 3, title: "Test Prize — Consolation", description: "Disposable test consolation prize.", images: [seedPhoto("prizedraw-item-3-20260101", 600, 600)], condition: "new", estimatedValue: 20, isWon: false },
564
- ],
565
- createdAt: new Date(),
566
- updatedAt: new Date(),
567
- }),
568
- withTokens({
569
- id: "prizedraw-tester-sandbox-closed",
570
- slug: "prizedraw-tester-sandbox-closed",
571
- title: "Test Prize Draw — Already Closed",
572
- description: "Disposable test prize-draw, window already closed — exists to verify the admin/seller \"Show closed\" toggle actually hides it by default and reveals it when toggled on. Auto-expires in 7 days.",
573
- categorySlugs: COLLECTIBLES_CATEGORY_SLUGS,
574
- categoryNames: COLLECTIBLES_CATEGORY_NAMES,
575
- brandSlug: "brand-tester-sandbox",
576
- brand: "TestBrand",
577
- price: 50,
578
- currency: "INR",
579
- condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
580
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
581
- listingType: "prize-draw",
582
- images: [seedPhoto("prizedraw-image-tester-sandbox-closed-20260101", 900, 900)],
583
- mainImage: seedPhoto("prizedraw-image-tester-sandbox-closed-20260101", 900, 900),
584
- isSold: true,
585
- stockQuantity: 0,
586
- availableQuantity: 0,
587
- customFields: [],
588
- customSections: [],
589
- isPromoted: false,
590
- isOnSale: false,
591
- prizeDrawMode: "reveal",
592
- prizeRevealMode: "scheduled",
593
- pricePerEntry: 50,
594
- prizeMaxEntries: 3,
595
- prizeCurrentEntries: 3,
596
- prizeDrawDurationDays: 13,
597
- prizeRevealWindowStart: new Date(Date.now() - 14 * 24 * 60 * 60 * 1000),
598
- prizeRevealWindowEnd: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000),
599
- prizeRevealStatus: "closed",
600
- prizeDrawItems: [
601
- { itemNumber: 1, title: "Test Prize — Grand", description: "Disposable test grand prize.", images: [seedPhoto("prizedraw-item-closed-1-20260101", 600, 600)], condition: "new", estimatedValue: 500, isWon: true },
602
- { itemNumber: 2, title: "Test Prize — Runner-up", description: "Disposable test runner-up prize.", images: [seedPhoto("prizedraw-item-closed-2-20260101", 600, 600)], condition: "new", estimatedValue: 150, isWon: true },
603
- { itemNumber: 3, title: "Test Prize — Consolation", description: "Disposable test consolation prize.", images: [seedPhoto("prizedraw-item-closed-3-20260101", 600, 600)], condition: "new", estimatedValue: 20, isWon: true },
604
- ],
605
- createdAt: new Date(),
606
- updatedAt: new Date(),
607
- }),
608
- withTokens({
609
- id: "classified-tester-sandbox-1",
610
- slug: "classified-tester-sandbox-1",
611
- title: "Test Classified — Contact Me!",
612
- description: "Disposable test classified listing for the tester QA program. No checkout — make an offer or contact the seller. Auto-expires in 7 days.",
613
- categorySlugs: COLLECTIBLES_CATEGORY_SLUGS,
614
- categoryNames: COLLECTIBLES_CATEGORY_NAMES,
615
- brandSlug: "brand-tester-sandbox",
616
- brand: "TestBrand",
617
- price: 250,
618
- currency: "INR",
619
- // Classifieds are the one non-standard type with `canMakeOffer: true`.
620
- // Until 2026-08-24 the sticky "Make an Offer" CTA on this page only
621
- // scrolled to the chat box and created no offer at all — this flag is what
622
- // makes the real form render there.
623
- allowOffers: true,
624
- minOfferPercent: 70,
625
- condition: PRODUCT_FIELDS.CONDITION_VALUES.GOOD,
626
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
627
- listingType: "classified",
628
- images: [seedPhoto("classified-image-tester-sandbox-1-20260101", 900, 900)],
629
- mainImage: seedPhoto("classified-image-tester-sandbox-1-20260101", 900, 900),
630
- isSold: false,
631
- stockQuantity: 1,
632
- availableQuantity: 1,
633
- customFields: [],
634
- customSections: [],
635
- isPromoted: false,
636
- isOnSale: false,
637
- classified: {
638
- meetupArea: { city: "Bengaluru", locality: "Test Locality", pincode: "560001" },
639
- acceptsShipping: false,
640
- negotiable: true,
641
- },
642
- createdAt: new Date(),
643
- updatedAt: new Date(),
644
- }),
645
- withTokens({
646
- id: "digitalcode-tester-sandbox-1",
647
- slug: "digitalcode-tester-sandbox-1",
648
- title: "Test Digital Code — Auto-Claim!",
649
- description: "Disposable test digital-code listing for the tester QA program. Auto-expires in 7 days.",
650
- categorySlugs: GADGETS_CATEGORY_SLUGS,
651
- categoryNames: GADGETS_CATEGORY_NAMES,
652
- brandSlug: "brand-tester-sandbox",
653
- brand: "TestBrand",
654
- price: 99,
655
- currency: "INR",
656
- condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
657
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
658
- listingType: "digital-code",
659
- images: [seedPhoto("digitalcode-image-tester-sandbox-1-20260101", 900, 900)],
660
- mainImage: seedPhoto("digitalcode-image-tester-sandbox-1-20260101", 900, 900),
661
- isSold: false,
662
- stockQuantity: 10,
663
- availableQuantity: 10,
664
- customFields: [],
665
- customSections: [],
666
- isPromoted: false,
667
- isOnSale: false,
668
- digitalCode: {
669
- codeDeliveryMethod: "auto-claim",
670
- codePoolSize: 10,
671
- codesAvailable: 10,
672
- redemptionInstructions: "Disposable test code — redeem at test-redeem.example for tester QA purposes only.",
673
- },
674
- createdAt: new Date(),
675
- updatedAt: new Date(),
676
- }),
677
- withTokens({
678
- id: "live-tester-sandbox-1",
679
- slug: "live-tester-sandbox-1",
680
- title: "Test Live Item — Golden Retriever Puppy",
681
- description: "Disposable test live-item listing for the tester QA program (verifies the mandatory-video rule, gallery video slide, and watermark on a real animal listing). Auto-expires in 7 days.",
682
- categorySlugs: COLLECTIBLES_CATEGORY_SLUGS,
683
- categoryNames: COLLECTIBLES_CATEGORY_NAMES,
684
- brandSlug: "brand-tester-sandbox",
685
- brand: "TestBrand",
686
- price: 1500,
687
- currency: "INR",
688
- condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
689
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
690
- listingType: "live",
691
- images: [seedPhoto("live-image-tester-sandbox-1-20260101", 900, 900)],
692
- mainImage: seedPhoto("live-image-tester-sandbox-1-20260101", 900, 900),
693
- // Real, directly-playable dog video (a raw <video> element, not routed through
694
- // /api/media/ext which is image-only — Root Cause #27) — Wikimedia Commons,
695
- // CC-BY-SA 4.0, https://commons.wikimedia.org/wiki/File:Slow_motion_of_running_greyhound.webm.
696
- // Exercises the mandatory-video-for-live rule + gallery video slide + watermark
697
- // on a genuine "animal actually moving" clip instead of a broken YouTube watch-page URL.
698
- video: {
699
- url: "https://upload.wikimedia.org/wikipedia/commons/4/42/Slow_motion_of_running_greyhound.webm", // audit-seed-external-url-ok: raw <video> src, CC-BY-SA 4.0 (Wikimedia Commons)
700
- thumbnailUrl: seedPhoto("live-video-thumb-tester-sandbox-1-20260101", 800, 450),
701
- duration: 14,
702
- },
703
- isSold: false,
704
- stockQuantity: 1,
705
- availableQuantity: 1,
706
- customFields: [],
707
- customSections: [],
708
- isPromoted: false,
709
- isOnSale: false,
710
- liveItem: {
711
- species: "Dog (Golden Retriever)",
712
- ageMonths: 6,
713
- sex: "male",
714
- careInfo: "Disposable test care info for the tester QA program.",
715
- transport: { method: "courier", handlingFee: 100, insuranceIncluded: true },
716
- jurisdictionAllowed: ["IN-KA", "IN-MH"],
717
- vendorVerified: true,
718
- },
719
- createdAt: new Date(),
720
- updatedAt: new Date(),
721
- }),
722
- withTokens({
723
- id: "art-tester-sandbox-1",
724
- slug: "art-tester-sandbox-1",
725
- title: "Test Art Print — Frame Me!",
726
- description: "Disposable test art listing for the tester QA program. Auto-expires in 7 days.",
727
- categorySlugs: COLLECTIBLES_CATEGORY_SLUGS,
728
- categoryNames: COLLECTIBLES_CATEGORY_NAMES,
729
- brandSlug: "brand-tester-sandbox",
730
- brand: "TestBrand",
731
- price: 349,
732
- currency: "INR",
733
- stockQuantity: 5,
734
- availableQuantity: 5,
735
- isSold: false,
736
- mainImage: seedPhoto("art-image-tester-sandbox-1-20260101", 900, 900),
737
- images: [seedPhoto("art-image-tester-sandbox-1-20260101", 900, 900)],
738
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
739
- condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
740
- listingType: "art",
741
- customFields: [],
742
- customSections: [],
743
- isPromoted: false,
744
- isOnSale: false,
745
- createdAt: new Date(),
746
- updatedAt: new Date(),
747
- }),
748
- withTokens({
749
- id: "stickers-tester-sandbox-1",
750
- slug: "stickers-tester-sandbox-1",
751
- title: "Test Sticker Pack — Peel Me!",
752
- description: "Disposable test stickers listing for the tester QA program. Auto-expires in 7 days.",
753
- categorySlugs: GADGETS_CATEGORY_SLUGS,
754
- categoryNames: GADGETS_CATEGORY_NAMES,
755
- brandSlug: "brand-tester-sandbox",
756
- brand: "TestBrand",
757
- price: 79,
758
- currency: "INR",
759
- stockQuantity: 25,
760
- availableQuantity: 25,
761
- isSold: false,
762
- mainImage: seedPhoto("stickers-image-tester-sandbox-1-20260101", 900, 900),
763
- images: [seedPhoto("stickers-image-tester-sandbox-1-20260101", 900, 900)],
764
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
765
- condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
766
- listingType: "stickers",
767
- customFields: [],
768
- customSections: [],
769
- isPromoted: false,
770
- isOnSale: false,
771
- createdAt: new Date(),
772
- updatedAt: new Date(),
773
- }),
774
- withTokens({
775
- id: "group-tester-sandbox-bundle",
776
- slug: "group-tester-sandbox-bundle",
777
- // Product-group ("Set") parent — Tier GP, unrelated to the Bundles
778
- // feature (categoryType:"bundle") despite the legacy "bundle" id/slug.
779
- // Kept stable rather than renamed since nothing outside this file's
780
- // internal group wiring depends on the "bundle" name.
781
- title: "Test Product Set — Standard #1 + Standard #2",
782
- description: "Disposable test product-group parent linking the two tester-sandbox standard products as a \"Set\". Auto-expires in 7 days.",
783
- categorySlugs: GADGETS_CATEGORY_SLUGS,
784
- categoryNames: GADGETS_CATEGORY_NAMES,
785
- brandSlug: "brand-tester-sandbox",
786
- brand: "TestBrand",
787
- price: 329,
788
- currency: "INR",
789
- condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
790
- status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
791
- listingType: "standard",
792
- images: [seedPhoto("product-image-tester-standard-1-20260101", 900, 900)],
793
- mainImage: seedPhoto("product-image-tester-standard-1-20260101", 900, 900),
794
- isSold: false,
795
- stockQuantity: 5,
796
- availableQuantity: 5,
797
- customFields: [],
798
- customSections: [],
799
- isPromoted: false,
800
- isOnSale: false,
801
- isGroupParent: true,
802
- groupId: "group-tester-sandbox-bundle",
803
- groupTitle: TESTER_GROUP_TITLE,
804
- // Parent↔child mirror: every id here must also carry `groupId` on its own
805
- // document. The pair drifting is Root Cause #42's second instance.
806
- groupChildSlugs: [
807
- "product-tester-standard-1",
808
- "product-tester-standard-2",
809
- "product-tester-standard-3",
810
- "product-tester-group-soldout",
811
- ],
812
- createdAt: new Date(),
813
- updatedAt: new Date(),
814
- }),
815
- ];