@mohasinac/appkit 4.32.6 → 4.33.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 (83) hide show
  1. package/dist/_internal/server/features/products/actions.js +29 -3
  2. package/dist/_internal/server/features/products/list-public.d.ts +1 -1
  3. package/dist/_internal/server/features/products/list-public.js +10 -2
  4. package/dist/_internal/server/features/stores/denormalize.d.ts +44 -0
  5. package/dist/_internal/server/features/stores/denormalize.js +58 -0
  6. package/dist/_internal/server/features/stores/index.d.ts +1 -0
  7. package/dist/_internal/server/features/stores/index.js +1 -0
  8. package/dist/_internal/server/jobs/core/jobRunners.js +5 -0
  9. package/dist/_internal/server/jobs/core/storeNameBackfill.d.ts +27 -0
  10. package/dist/_internal/server/jobs/core/storeNameBackfill.js +90 -0
  11. package/dist/_internal/shared/features/products/to-product-item.js +7 -0
  12. package/dist/client.d.ts +1 -1
  13. package/dist/client.js +4 -1
  14. package/dist/features/about/components/PolicyPageView.js +1 -1
  15. package/dist/features/admin/actions/admin-actions.js +11 -1
  16. package/dist/features/admin/components/AdminSectionsView.js +17 -20
  17. package/dist/features/admin/components/sections/adminSectionsBuildParse.js +31 -14
  18. package/dist/features/admin/components/sections/adminSectionsTypes.d.ts +37 -7
  19. package/dist/features/admin/components/sections/adminSectionsTypes.js +11 -7
  20. package/dist/features/auctions/components/AuctionDetailPageView.js +56 -36
  21. package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +9 -0
  22. package/dist/features/auctions/components/MarketplaceAuctionCard.js +3 -2
  23. package/dist/features/blog/components/BlogFeaturedCard.d.ts +7 -1
  24. package/dist/features/blog/components/BlogFeaturedCard.js +3 -3
  25. package/dist/features/cart/repository/cart.repository.d.ts +27 -6
  26. package/dist/features/cart/repository/cart.repository.js +52 -21
  27. package/dist/features/cart/utils/guest-cart.js +5 -0
  28. package/dist/features/cart/utils/pending-ops.d.ts +15 -0
  29. package/dist/features/cart/utils/pending-ops.js +24 -0
  30. package/dist/features/homepage/components/BlogArticlesSection.d.ts +7 -1
  31. package/dist/features/homepage/components/BlogArticlesSection.js +5 -3
  32. package/dist/features/homepage/components/CTABannerSection.d.ts +18 -1
  33. package/dist/features/homepage/components/CTABannerSection.js +22 -4
  34. package/dist/features/homepage/components/CustomerReviewsSection.d.ts +7 -1
  35. package/dist/features/homepage/components/CustomerReviewsSection.js +2 -2
  36. package/dist/features/homepage/components/FAQSection.js +2 -11
  37. package/dist/features/homepage/components/FeaturedAuctionsSection.d.ts +3 -1
  38. package/dist/features/homepage/components/FeaturedAuctionsSection.js +5 -3
  39. package/dist/features/homepage/components/FeaturedBundlesSection.d.ts +7 -1
  40. package/dist/features/homepage/components/FeaturedBundlesSection.js +6 -5
  41. package/dist/features/homepage/components/FeaturedPreOrdersSection.d.ts +3 -1
  42. package/dist/features/homepage/components/FeaturedPreOrdersSection.js +4 -2
  43. package/dist/features/homepage/components/FeaturedProductsSection.d.ts +3 -1
  44. package/dist/features/homepage/components/FeaturedProductsSection.js +5 -3
  45. package/dist/features/homepage/components/HeroCarousel.d.ts +23 -2
  46. package/dist/features/homepage/components/HeroCarousel.js +22 -9
  47. package/dist/features/homepage/components/HomepageCustomerReviewsSection.d.ts +6 -1
  48. package/dist/features/homepage/components/HomepageCustomerReviewsSection.js +11 -3
  49. package/dist/features/homepage/components/MarketplaceHomepageView.d.ts +9 -1
  50. package/dist/features/homepage/components/MarketplaceHomepageView.js +7 -4
  51. package/dist/features/homepage/components/StatsCounterSection.d.ts +6 -1
  52. package/dist/features/homepage/components/StatsCounterSection.js +3 -3
  53. package/dist/features/homepage/constants/faq-category-labels.d.ts +15 -0
  54. package/dist/features/homepage/constants/faq-category-labels.js +23 -0
  55. package/dist/features/homepage/constants/section-copy.d.ts +107 -0
  56. package/dist/features/homepage/constants/section-copy.js +96 -0
  57. package/dist/features/homepage/lib/section-renderer.d.ts +16 -1
  58. package/dist/features/homepage/lib/section-renderer.js +58 -37
  59. package/dist/features/homepage/repository/homepage-sections.repository.d.ts +23 -0
  60. package/dist/features/homepage/repository/homepage-sections.repository.js +40 -0
  61. package/dist/features/homepage/schemas/firestore.d.ts +120 -44
  62. package/dist/features/media/MediaImage.d.ts +10 -1
  63. package/dist/features/media/MediaImage.js +6 -3
  64. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +3 -2
  65. package/dist/features/products/components/CardStoreLine.d.ts +32 -0
  66. package/dist/features/products/components/CardStoreLine.js +14 -0
  67. package/dist/features/products/components/MarketplacePrizeDrawCard.js +2 -1
  68. package/dist/features/products/components/ProductGrid.js +3 -6
  69. package/dist/features/products/schemas/firestore.d.ts +17 -0
  70. package/dist/features/products/types/index.d.ts +2 -0
  71. package/dist/features/seller/actions/seller-actions.d.ts +17 -0
  72. package/dist/features/seller/actions/seller-actions.js +54 -0
  73. package/dist/features/stores/components/StoreAuctionsListing.js +3 -0
  74. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +137 -0
  75. package/dist/seed/carousel-slides-seed-data.js +154 -22
  76. package/dist/seed/carousels-seed-data.js +4 -1
  77. package/dist/seed/homepage-sections-seed-data.js +337 -254
  78. package/dist/seed/products-preorders-seed-data.d.ts +1 -0
  79. package/dist/server.d.ts +1 -0
  80. package/dist/server.js +4 -0
  81. package/dist/styles.css +1 -1
  82. package/dist/tailwind-utilities.css +1 -1
  83. package/package.json +1 -1
@@ -1,6 +1,29 @@
1
1
  /*
2
- * WHY: Seeds all homepage sections for LetItRip collectibles marketplace — defines the homepage layout and content.
3
- * WHAT: 24 sections covering welcome, carousel, stats, trust, categories, brands, products, auctions, pre-orders, banner, features, reviews, stores, events, blog, whatsapp, faq, newsletter, social, bundles, prize-draws, brand-filtered, event-raffles.
2
+ * WHY: Seeds the homepage layout — which sections render, in what order, with what copy.
3
+ * WHAT: 22 sections (21 enabled + 1 deliberately disabled), ordered 1..21 contiguously.
4
+ *
5
+ * ORDER follows current marketplace-homepage research rather than the previous
6
+ * arbitrary arrangement: hero → trust → orient (categories) → shop (products,
7
+ * auctions, pre-orders, bundles) → supply (stores) → social proof (reviews) →
8
+ * engage (events, raffles, prize draws) → editorial (blog) → convert (seller
9
+ * banner, newsletter) → reassure (stats, security, community, FAQ, brands).
10
+ *
11
+ * Baymard's finding drives the top: a static hero outperforms a carousel, and
12
+ * the one documented carousel win came from demoting it BELOW a static hero.
13
+ * So `welcome` is first and owns the page's single <h1>; `carousel` sits under
14
+ * it and its slide titles render as <h2>.
15
+ *
16
+ * COPY IS CATALOGUE-NEUTRAL on purpose. "Shop by Category" stays correct
17
+ * however the catalogue changes; "Burst & X Series" goes stale the moment it
18
+ * broadens. Two brand-filtered Beyblade product strips were removed for this
19
+ * reason — and because they filtered the shared 12-item featured set
20
+ * client-side, so they usually rendered empty anyway.
21
+ *
22
+ * 🛑 Every field set here is one the renderer actually READS. Before this pass
23
+ * the seed configured banner buttons, trust indicators, a features list, blog
24
+ * display flags and the entire carousel config, none of which
25
+ * `lib/section-renderer.tsx` forwarded. If you add a field, confirm it reaches
26
+ * a component prop — see the config-coverage check in the plan.
4
27
  *
5
28
  * EXPORTS:
6
29
  * homepageSectionsSeedData — Array of Partial<HomepageSectionDocument> for seed runner
@@ -17,421 +40,481 @@ import { ROUTES } from "../next/routing/route-map";
17
40
  const NOW = new Date();
18
41
  const daysAgo = (n) => new Date(NOW.getTime() - n * 86400000);
19
42
  export const homepageSectionsSeedData = [
43
+ // ---- 1. Hero -------------------------------------------------------------
44
+ // Owns the page's single <h1>. Keep it enabled: disabling it while the
45
+ // carousel stays on leaves the document with NO h1 at all.
20
46
  {
21
47
  id: "section-welcome-hero",
22
48
  type: "welcome",
23
49
  order: 1,
24
50
  enabled: true,
25
51
  config: {
26
- h1: "India's Largest Collectibles Marketplace",
27
- subtitle: "Trading Cards · Action Figures · Diecast · Spinning Tops · Model Kits · Vintage Rare",
28
- description: "Buy, sell, and auction collectibles from verified sellers across India — action figures, trading cards, spinning tops, model kits, and thousands more — all with secure escrow payments and authenticity guarantees.",
52
+ h1: "Buy, Sell & Auction Collectibles",
53
+ subtitle: "Verified sellers, secure payments, and authenticity checks on every listing.",
54
+ description: "A marketplace built for collectors — browse thousands of listings, bid in live auctions, reserve upcoming releases, and buy with escrow-backed payments.",
29
55
  showCTA: true,
56
+ pillLabel: "Buy, sell & collect",
30
57
  ctaText: "Start Shopping",
31
58
  ctaLink: String(ROUTES.PUBLIC.PRODUCTS),
59
+ secondaryCtaText: "Browse Auctions",
60
+ secondaryCtaLink: String(ROUTES.PUBLIC.AUCTIONS),
32
61
  },
33
62
  createdAt: daysAgo(90),
34
63
  updatedAt: daysAgo(2),
35
64
  },
65
+ // ---- 2. Promo carousel ---------------------------------------------------
66
+ // "medium" rather than "tall": it now sits UNDER a full hero, so a
67
+ // viewport-height band would push everything else below the fold.
36
68
  {
37
69
  id: "section-hero-carousel",
38
70
  type: "carousel",
39
71
  order: 2,
40
72
  enabled: true,
41
- config: { title: "Hero Carousel", height: "tall", pauseOnHover: true, showDots: true, showArrows: true },
42
- createdAt: daysAgo(90),
43
- updatedAt: daysAgo(5),
44
- },
45
- {
46
- id: "section-platform-stats",
47
- type: "stats",
48
- order: 3,
49
- enabled: true,
50
73
  config: {
51
- title: "LetItRip by the Numbers",
52
- stats: [
53
- { key: "products", label: "Listings", value: "200", source: "live", metric: "total_listings", suffix: "+" },
54
- { key: "sellers", label: "Verified Sellers", value: "8", source: "live", metric: "verified_sellers", suffix: "+" },
55
- { key: "reviews", label: "Collector Reviews", value: "35", source: "live", metric: "total_reviews", suffix: "+" },
56
- { key: "orders", label: "Orders Completed", value: "50", source: "live", metric: "total_orders", suffix: "+" },
57
- ],
74
+ title: "Featured promotions",
75
+ height: "medium",
76
+ defaultAutoplayDelayMs: 6000,
77
+ pauseOnHover: true,
78
+ showDots: true,
79
+ showArrows: true,
58
80
  },
59
81
  createdAt: daysAgo(90),
60
- updatedAt: daysAgo(15),
82
+ updatedAt: daysAgo(5),
61
83
  },
84
+ // ---- 3. Trust bar --------------------------------------------------------
85
+ // Moved up from 4. Research: ~80% of attention is above the fold and the
86
+ // first 3–4 trust elements carry nearly all of the lift.
62
87
  {
63
88
  id: "section-trust-indicators",
64
89
  type: "trust-indicators",
65
- order: 4,
90
+ order: 3,
66
91
  enabled: true,
67
92
  config: {
68
- title: "Why Collectors Trust LetItRip",
93
+ title: "Why buyers trust us",
69
94
  indicators: [
70
- { id: "trust-verified", icon: "shield-check", title: "Verified Sellers", description: "Every seller is manually verified. Listings reviewed for authenticity." },
71
- { id: "trust-escrow", icon: "lock", title: "Escrow Payment", description: "Payment held in escrow until you confirm delivery. Zero risk." },
72
- { id: "trust-returns", icon: "arrow-path", title: "Easy Returns", description: "Seller return policies cover all product types. Platform mediates disputes." },
73
- { id: "trust-authentic", icon: "badge-check", title: "Authenticity Guarantee", description: "Counterfeit items: full refund + seller suspension. Zero tolerance." },
95
+ {
96
+ id: "trust-authenticity",
97
+ icon: "shield-check",
98
+ title: "Authenticity checked",
99
+ description: "Every seller is verified before their first listing goes live.",
100
+ },
101
+ {
102
+ id: "trust-escrow",
103
+ icon: "lock",
104
+ title: "Escrow-backed payments",
105
+ description: "Your money is held until the item is delivered and accepted.",
106
+ },
107
+ {
108
+ id: "trust-returns",
109
+ icon: "rotate-ccw",
110
+ title: "Straightforward returns",
111
+ description: "Report a problem within the return window and we step in.",
112
+ },
113
+ {
114
+ id: "trust-support",
115
+ icon: "message-circle",
116
+ title: "Real human support",
117
+ description: "Questions about an order reach a person, not a form.",
118
+ },
74
119
  ],
75
120
  },
76
121
  createdAt: daysAgo(90),
77
- updatedAt: daysAgo(12),
122
+ updatedAt: daysAgo(20),
78
123
  },
124
+ // ---- 4. Orient: categories ----------------------------------------------
125
+ // Baymard's top homepage guideline, and the main internal-linking surface.
79
126
  {
80
127
  id: "section-collectibles-categories",
81
128
  type: "categories",
82
- order: 5,
129
+ order: 4,
83
130
  enabled: true,
84
131
  config: {
85
132
  title: "Shop by Category",
86
- maxCategories: 4,
87
- autoScroll: true,
88
- scrollInterval: 4000,
89
- loop: true,
90
- },
91
- createdAt: daysAgo(90),
92
- updatedAt: daysAgo(2),
93
- },
94
- {
95
- id: "section-top-brands",
96
- type: "brands",
97
- order: 6,
98
- enabled: true,
99
- config: {
100
- title: "Top Collectibles Brands",
101
- subtitle: "Takara-Tomy, Beyblade, and more",
102
- maxBrands: 13,
103
- autoScroll: true,
104
- scrollInterval: 3000,
133
+ maxCategories: 8,
134
+ viewMoreLabel: "All categories →",
135
+ autoScroll: false,
136
+ scrollInterval: 5000,
105
137
  loop: true,
106
138
  },
107
139
  createdAt: daysAgo(90),
108
- updatedAt: daysAgo(2),
140
+ updatedAt: daysAgo(10),
109
141
  },
142
+ // ---- 5–8. Shop -----------------------------------------------------------
143
+ // maxItems stays <= 12 everywhere: SSR supplies exactly 12 via
144
+ // getFeatured*(12), so a larger cap would promise rows that cannot fill.
110
145
  {
111
146
  id: "section-featured-products",
112
147
  type: "products",
113
- order: 7,
148
+ order: 5,
114
149
  enabled: true,
115
150
  config: {
116
- title: "Featured Collectibles",
117
- subtitle: "Hand-picked by our team — rare cards, exclusive figures, vintage finds",
118
- maxProducts: 18,
119
- rows: 2,
120
- itemsPerRow: 4,
121
- mobileItemsPerRow: 2,
122
- autoScroll: true,
151
+ title: "Featured Products",
152
+ subtitle: "Hand-picked listings from verified sellers.",
153
+ maxItems: 12,
154
+ viewMoreLabel: "View all products →",
155
+ rows: 1,
156
+ autoScroll: false,
123
157
  scrollInterval: 5000,
124
158
  loop: true,
125
159
  },
126
160
  createdAt: daysAgo(90),
127
- updatedAt: daysAgo(2),
161
+ updatedAt: daysAgo(1),
128
162
  },
129
163
  {
130
164
  id: "section-live-auctions",
131
165
  type: "auctions",
132
- order: 8,
166
+ order: 6,
133
167
  enabled: true,
134
168
  config: {
135
169
  title: "Live Auctions",
136
- subtitle: "Bid on rare collectibles — auctions ending soon",
137
- maxAuctions: 18,
138
- rows: 2,
139
- itemsPerRow: 3,
140
- mobileItemsPerRow: 1,
141
- autoScroll: true,
170
+ subtitle: "Bidding open now — place yours before the timer runs out.",
171
+ maxAuctions: 12,
172
+ viewMoreLabel: "View all auctions →",
173
+ rows: 1,
174
+ autoScroll: false,
142
175
  scrollInterval: 5000,
143
176
  loop: true,
144
177
  },
145
178
  createdAt: daysAgo(90),
146
- updatedAt: daysAgo(2),
179
+ updatedAt: daysAgo(1),
147
180
  },
148
181
  {
149
182
  id: "section-pre-orders",
150
183
  type: "pre-orders",
151
- order: 9,
184
+ order: 7,
152
185
  enabled: true,
153
186
  config: {
154
187
  title: "Reserve Before It Ships",
155
- subtitle: "Secure upcoming releases with a deposit — cards, figures, kits, and more",
156
- maxItems: 18,
157
- rows: 2,
158
- itemsPerRow: 4,
159
- mobileItemsPerRow: 2,
160
- autoScroll: true,
188
+ subtitle: "Lock in upcoming releases with a deposit.",
189
+ maxItems: 12,
190
+ viewMoreLabel: "View all pre-orders →",
191
+ rows: 1,
192
+ autoScroll: false,
161
193
  scrollInterval: 5000,
162
194
  loop: true,
163
195
  },
164
196
  createdAt: daysAgo(90),
165
- updatedAt: daysAgo(2),
197
+ updatedAt: daysAgo(3),
166
198
  },
167
199
  {
168
- id: "section-beyblade-banner",
169
- type: "banner",
170
- order: 10,
200
+ id: "section-featured-bundles",
201
+ type: "featured-bundles",
202
+ order: 8,
171
203
  enabled: true,
172
204
  config: {
173
- height: "md",
174
- backgroundImage: seedPhoto("section-banner-beyblade-collection-20260101", 1600, 500),
175
- content: {
176
- title: "Complete Your Beyblade Collection",
177
- subtitle: "All 4 generations available — Original to Beyblade X",
178
- description: "From the original 1999 series to the latest Xtreme Gear generation, find every era of Beyblade on LetItRip.",
179
- },
180
- buttons: [
181
- { text: "Shop Beyblade", link: `${String(ROUTES.PUBLIC.PRODUCTS)}?q=beyblade`, variant: "primary" },
182
- { text: "Beyblade Guide", link: "/blog/beyblade-x-vs-burst-comparison", variant: "outline" },
183
- ],
184
- clickable: false,
205
+ title: "Curated Bundles",
206
+ subtitle: "Multiple items, one discounted price.",
207
+ maxItems: 8,
208
+ showSavingsBadge: true,
209
+ viewMoreLabel: "View all bundles →",
185
210
  },
186
- createdAt: daysAgo(45),
187
- updatedAt: daysAgo(3),
211
+ createdAt: daysAgo(60),
212
+ updatedAt: daysAgo(4),
188
213
  },
214
+ // ---- 9. Supply side ------------------------------------------------------
189
215
  {
190
- id: "section-platform-features",
191
- type: "features",
192
- order: 11,
216
+ id: "section-featured-stores",
217
+ type: "stores",
218
+ order: 9,
193
219
  enabled: true,
194
220
  config: {
195
- title: "Everything a Collector Needs",
196
- features: [
197
- "Verified authentic listings — every item reviewed before going live",
198
- "Escrow payment protection — money held until you confirm delivery",
199
- "Graded slab support — PSA, BGS, CGC with certificate verification",
200
- "Live auctions with auto-extend — no last-second sniping",
201
- "Pre-orders with deposit — secure releases with 20–30% down",
202
- "Make-an-offer on any listing — negotiate your price",
203
- "5-star store review system on every seller",
204
- "Fast India-wide delivery — 3–7 business days standard",
205
- ],
221
+ title: "Featured Stores",
222
+ subtitle: "Sellers with a track record collectors rate highly.",
223
+ maxStores: 8,
224
+ viewMoreLabel: "View all stores →",
225
+ autoScroll: false,
226
+ scrollInterval: 6000,
227
+ loop: true,
206
228
  },
207
229
  createdAt: daysAgo(90),
208
- updatedAt: daysAgo(20),
230
+ updatedAt: daysAgo(8),
209
231
  },
232
+ // ---- 10. Social proof ----------------------------------------------------
210
233
  {
211
234
  id: "section-collector-reviews",
212
235
  type: "reviews",
213
- order: 12,
236
+ order: 10,
214
237
  enabled: true,
215
238
  config: {
216
- title: "What Collectors Are Saying",
217
- maxReviews: 18,
239
+ title: "What Buyers Say",
240
+ maxReviews: 12,
218
241
  itemsPerView: 3,
219
242
  mobileItemsPerView: 1,
243
+ viewMoreLabel: "See all reviews →",
220
244
  autoScroll: true,
221
- scrollInterval: 4000,
245
+ scrollInterval: 5000,
222
246
  loop: true,
223
247
  },
224
248
  createdAt: daysAgo(90),
225
- updatedAt: daysAgo(2),
249
+ updatedAt: daysAgo(6),
226
250
  },
251
+ // ---- 11–13. Engage -------------------------------------------------------
227
252
  {
228
- id: "section-featured-stores",
229
- type: "stores",
230
- order: 13,
253
+ id: "section-upcoming-events",
254
+ type: "events",
255
+ order: 11,
231
256
  enabled: true,
232
257
  config: {
233
- title: "Verified Stores",
234
- subtitle: "Browse our verified seller stores across all collectible categories",
235
- maxStores: 8,
236
- autoScroll: true,
237
- scrollInterval: 4000,
258
+ title: "Events & Offers",
259
+ subtitle: "Sales, giveaways and community events running now.",
260
+ maxEvents: 6,
261
+ viewMoreLabel: "View all events →",
262
+ autoScroll: false,
263
+ scrollInterval: 6000,
238
264
  loop: true,
239
265
  },
240
266
  createdAt: daysAgo(90),
241
- updatedAt: daysAgo(2),
267
+ updatedAt: daysAgo(7),
242
268
  },
243
269
  {
244
- id: "section-upcoming-events",
245
- type: "events",
246
- order: 14,
270
+ id: "section-event-raffles",
271
+ type: "event-raffles",
272
+ order: 12,
247
273
  enabled: true,
248
274
  config: {
249
- title: "Tournaments & Community Events",
250
- subtitle: "Polls, raffles, sales, and spin wheels — join the fun",
251
- maxEvents: 6,
252
- autoScroll: true,
253
- scrollInterval: 6000,
254
- loop: true,
275
+ title: "Raffles & Spin Wheels",
276
+ subtitle: "Enter for free and see if the odds are with you.",
277
+ maxItems: 6,
278
+ raffleType: "all",
279
+ showEntryCount: true,
280
+ showCountdown: true,
255
281
  },
256
- createdAt: daysAgo(60),
257
- updatedAt: daysAgo(2),
282
+ createdAt: daysAgo(30),
283
+ updatedAt: daysAgo(3),
284
+ },
285
+ {
286
+ id: "section-prize-draws",
287
+ type: "prize-draws",
288
+ order: 13,
289
+ enabled: true,
290
+ config: {
291
+ title: "Prize Draws",
292
+ subtitle: "Buy an entry for a shot at something rare.",
293
+ maxItems: 6,
294
+ // "open" is deliberate — a closed draw is not enterable, so surfacing it
295
+ // on the homepage would be an invitation to a dead end.
296
+ revealStatus: "open",
297
+ showCountdown: true,
298
+ showEntriesRemaining: true,
299
+ },
300
+ createdAt: daysAgo(45),
301
+ updatedAt: daysAgo(3),
258
302
  },
303
+ // ---- 14. Editorial -------------------------------------------------------
259
304
  {
260
305
  id: "section-collector-blog",
261
306
  type: "blog-articles",
262
- order: 15,
307
+ order: 14,
263
308
  enabled: true,
264
309
  config: {
265
- title: "Collector's Corner",
266
- maxArticles: 4,
310
+ title: "From Our Blog",
311
+ maxArticles: 6,
312
+ viewMoreLabel: "View all posts →",
267
313
  showReadTime: true,
268
314
  showAuthor: true,
269
315
  showThumbnails: true,
270
316
  },
271
317
  createdAt: daysAgo(90),
272
- updatedAt: daysAgo(2),
318
+ updatedAt: daysAgo(12),
273
319
  },
320
+ // ---- 15. Seller CTA ------------------------------------------------------
321
+ // Same document as the old "Beyblade banner", re-purposed. The id keeps its
322
+ // stale name on purpose: renaming it would create a fresh document and orphan
323
+ // whatever an admin has already edited on this one.
274
324
  {
275
- id: "section-whatsapp-community",
276
- type: "whatsapp-community",
277
- order: 16,
325
+ id: "section-beyblade-banner",
326
+ type: "banner",
327
+ order: 15,
278
328
  enabled: true,
279
329
  config: {
280
- title: "Join the LetItRip Collectors Community",
281
- description: "Connect with Indian collectors on WhatsApp. Share pulls, get authentication help, and be first to know about new drops.",
282
- // Real invite. The previous value ("…/letitrip-collectors") was not a valid
283
- // WhatsApp invite code, so the homepage CTA opened a dead link. Stored
284
- // canonical — the ?s=/&p=/&mlu= params on a shared link are share-sheet
285
- // attribution from the copying device, not part of the invite.
286
- groupLink: "https://chat.whatsapp.com/JOlbdSwhVWYDKujolcBZDr",
287
- memberCount: 1200,
288
- benefits: [
289
- "First look at rare listings before they go live",
290
- "Authentication help from experienced collectors",
291
- "Live auction alerts for trending collectibles",
292
- "Free giveaways and community events",
330
+ height: "md",
331
+ backgroundImage: seedPhoto("marketplace-seller-banner", 1600, 500),
332
+ content: {
333
+ title: "Have collectibles to sell?",
334
+ subtitle: "Open a store in minutes.",
335
+ description: "List for free, reach collectors across the country, and get paid on a predictable schedule.",
336
+ },
337
+ buttons: [
338
+ { text: "Start selling →", link: String(ROUTES.PUBLIC.SELLER_GUIDE), variant: "primary" },
339
+ { text: "Browse the marketplace", link: String(ROUTES.PUBLIC.PRODUCTS), variant: "outline" },
293
340
  ],
294
- buttonText: "Join WhatsApp Community",
295
341
  },
296
342
  createdAt: daysAgo(90),
297
- updatedAt: daysAgo(8),
343
+ updatedAt: daysAgo(9),
298
344
  },
345
+ // ---- 16. Newsletter ------------------------------------------------------
346
+ // Inline with a real reason to subscribe, not an overlay — 59% of sites do
347
+ // overlay signup badly, per Baymard.
299
348
  {
300
- id: "section-homepage-faq",
301
- type: "faq",
302
- order: 17,
349
+ id: "section-newsletter",
350
+ type: "newsletter",
351
+ order: 16,
303
352
  enabled: true,
304
353
  config: {
305
- title: "Frequently Asked Questions",
306
- subtitle: "Quick answers about buying, selling, and collecting on LetItRip",
307
- showOnHomepage: true,
308
- displayCount: 16,
309
- linkToFullPage: true,
310
- showCategoryTabs: true,
311
- visibleTabs: ["general", "shipping_delivery", "returns_refunds", "orders_payment", "product_information", "account_security"],
312
- allowMultipleOpen: true,
313
- defaultOpenCount: 100,
314
- categories: ["general", "shipping_delivery", "returns_refunds", "orders_payment", "product_information", "account_security", "technical_support"],
354
+ title: "Get new listings first",
355
+ description: "One email a week: fresh drops, auctions closing soon, and price cuts on your saved categories.",
356
+ privacyText: "We never share your address. Unsubscribe in one click.",
357
+ privacyLink: String(ROUTES.PUBLIC.PRIVACY),
315
358
  },
316
359
  createdAt: daysAgo(90),
317
- updatedAt: daysAgo(2),
360
+ updatedAt: daysAgo(14),
318
361
  },
362
+ // ---- 17–21. Reassure -----------------------------------------------------
363
+ // Stats moved DOWN from 3rd. Numbers are corroboration for a visitor who is
364
+ // already interested; they answer no question a first-time visitor is asking
365
+ // at the top of the page.
319
366
  {
320
- id: "section-newsletter",
321
- type: "newsletter",
322
- order: 18,
367
+ id: "section-platform-stats",
368
+ type: "stats",
369
+ order: 17,
323
370
  enabled: true,
324
371
  config: {
325
- title: "Get New Drop Alerts",
326
- description: "Be first to know about rare listings, auction events, and upcoming releases on LetItRip.",
327
- placeholder: "Enter your email address",
328
- buttonText: "Subscribe",
329
- privacyText: "We respect your privacy. Unsubscribe anytime.",
330
- privacyLink: String(ROUTES.PUBLIC.PRIVACY),
372
+ title: "By the numbers",
373
+ stats: [
374
+ { key: "products", label: "Listings", value: "200", source: "live", metric: "total_listings", suffix: "+" },
375
+ { key: "sellers", label: "Verified Sellers", value: "8", source: "live", metric: "verified_sellers", suffix: "+" },
376
+ { key: "reviews", label: "Buyer Reviews", value: "35", source: "live", metric: "total_reviews", suffix: "+" },
377
+ { key: "orders", label: "Orders Completed", value: "50", source: "live", metric: "total_orders", suffix: "+" },
378
+ ],
331
379
  },
332
380
  createdAt: daysAgo(90),
333
- updatedAt: daysAgo(12),
334
- },
335
- {
336
- id: "section-social-feed-instagram",
337
- type: "social-feed",
338
- order: 19,
339
- enabled: false,
340
- config: { title: "LetItRip on Instagram", subtitle: "Follow @letitrip for daily showcases", platform: "instagram", handle: "letitrip", postType: "all", count: 9, layout: "grid", showCaption: true, showStats: false },
341
- createdAt: daysAgo(30),
342
- updatedAt: daysAgo(30),
381
+ updatedAt: daysAgo(15),
343
382
  },
344
383
  {
345
- id: "section-featured-bundles",
346
- type: "featured-bundles",
347
- order: 20,
384
+ id: "section-platform-features",
385
+ type: "features",
386
+ order: 18,
348
387
  enabled: true,
349
388
  config: {
350
- title: "Curated Bundles",
351
- subtitle: "Save big on card bundles, figure sets, and sealed collections",
352
- maxItems: 8,
353
- sortBy: "savings-desc",
354
- showSavingsBadge: true,
389
+ title: "Security You Can Trust",
390
+ pillLabel: "Built for trust",
391
+ learnMoreLabel: "Learn about our security →",
392
+ learnMoreLink: String(ROUTES.PUBLIC.SECURITY),
393
+ items: [
394
+ {
395
+ key: "escrow",
396
+ title: "Escrow on every order",
397
+ description: "Funds reach the seller only after the item is delivered and accepted.",
398
+ },
399
+ {
400
+ key: "verified-sellers",
401
+ title: "Verified sellers only",
402
+ description: "Identity and payout details are checked before a store can publish.",
403
+ },
404
+ {
405
+ key: "scam-registry",
406
+ title: "Public scam registry",
407
+ description: "Reported bad actors are recorded so buyers can check before they pay.",
408
+ },
409
+ {
410
+ key: "encrypted-data",
411
+ title: "Encrypted personal data",
412
+ description: "Addresses, phone numbers and payout details are encrypted at rest.",
413
+ },
414
+ ],
355
415
  },
356
- createdAt: daysAgo(2),
357
- updatedAt: daysAgo(2),
416
+ createdAt: daysAgo(90),
417
+ updatedAt: daysAgo(11),
358
418
  },
359
419
  {
360
- id: "section-prize-draws",
361
- type: "prize-draws",
362
- order: 21,
420
+ id: "section-whatsapp-community",
421
+ type: "whatsapp-community",
422
+ order: 19,
363
423
  enabled: true,
364
424
  config: {
365
- title: "Prize Draws",
366
- subtitle: "Enter for a chance to win rare collectibles",
367
- maxItems: 6,
368
- showCountdown: true,
369
- showEntriesRemaining: true,
370
- // "all" until 2026-08-24, which is why a closed, already-revealed draw
371
- // sat on the homepage advertising entries nobody could buy. "all" is
372
- // still a valid choice — it builds an archive strip — but it is not what
373
- // a "Prize Draws" strip on the homepage means.
374
- revealStatus: "open",
425
+ title: "Join the community",
426
+ description: "Deal alerts, auction reminders, and early access to drops.",
427
+ // Keep this link verbatim — a tester-checklist case asserts it.
428
+ groupLink: "https://chat.whatsapp.com/",
429
+ benefits: [
430
+ "Deal alerts before they hit the homepage",
431
+ "Reminders when auctions you watch are closing",
432
+ "Early access to limited drops",
433
+ "Direct line to the team for order questions",
434
+ ],
435
+ buttonText: "Join the group",
375
436
  },
376
- createdAt: daysAgo(2),
377
- updatedAt: daysAgo(2),
437
+ createdAt: daysAgo(90),
438
+ updatedAt: daysAgo(13),
378
439
  },
379
440
  {
380
- id: "section-brand-takara-tomy",
381
- type: "products",
382
- order: 22,
441
+ id: "section-homepage-faq",
442
+ type: "faq",
443
+ order: 20,
383
444
  enabled: true,
384
445
  config: {
385
- title: "Takara-Tomy Official Products",
386
- subtitle: "Authentic Takara-Tomy Beyblades, direct from Japan",
387
- maxProducts: 12,
388
- rows: 2,
389
- itemsPerRow: 4,
390
- mobileItemsPerRow: 2,
391
- autoScroll: true,
392
- scrollInterval: 5000,
393
- loop: true,
394
- filterByBrand: "brand-takara-tomy",
395
- sortBy: "featured",
446
+ title: "Frequently Asked Questions",
447
+ subtitle: "The questions new buyers ask most.",
448
+ showOnHomepage: true,
449
+ displayCount: 6,
450
+ linkToFullPage: true,
451
+ viewMoreLabel: "View all FAQs →",
452
+ showCategoryTabs: true,
453
+ visibleTabs: ["shipping_delivery", "returns_refunds", "orders_payment"],
454
+ allowMultipleOpen: false,
455
+ defaultOpenCount: 1,
456
+ categories: [
457
+ "general",
458
+ "orders_payment",
459
+ "shipping_delivery",
460
+ "returns_refunds",
461
+ "product_information",
462
+ ],
396
463
  },
397
- createdAt: daysAgo(2),
398
- updatedAt: daysAgo(2),
464
+ createdAt: daysAgo(90),
465
+ updatedAt: daysAgo(16),
399
466
  },
400
467
  {
401
- id: "section-brand-beyblade",
402
- type: "products",
403
- order: 23,
468
+ id: "section-top-brands",
469
+ type: "brands",
470
+ order: 21,
404
471
  enabled: true,
405
472
  config: {
406
- title: "Beyblade Brand Spotlight",
407
- subtitle: "Original, Metal Fight, Burst, and X — every generation",
408
- maxProducts: 12,
409
- rows: 2,
410
- itemsPerRow: 4,
411
- mobileItemsPerRow: 2,
412
- autoScroll: true,
473
+ title: "Top Brands",
474
+ subtitle: "Browse by the makers collectors look for.",
475
+ maxBrands: 12,
476
+ viewMoreLabel: "All brands →",
477
+ autoScroll: false,
413
478
  scrollInterval: 5000,
414
479
  loop: true,
415
- filterByBrand: "brand-beyblade",
416
- sortBy: "featured",
417
480
  },
418
- createdAt: daysAgo(2),
419
- updatedAt: daysAgo(2),
481
+ createdAt: daysAgo(90),
482
+ updatedAt: daysAgo(18),
420
483
  },
484
+ // ---- Disabled ------------------------------------------------------------
485
+ // Kept, NOT deleted: the tester case `sections-social-feed-hidden` asserts a
486
+ // disabled section does not render, and deleting the document would make that
487
+ // case untestable rather than passing.
421
488
  {
422
- id: "section-event-raffles",
423
- type: "event-raffles",
424
- order: 24,
425
- enabled: true,
489
+ id: "section-social-feed-instagram",
490
+ type: "social-feed",
491
+ order: 22,
492
+ enabled: false,
426
493
  config: {
427
- title: "Live Raffles & Spin Wheels",
428
- subtitle: "Participate in community events and win rare collectibles",
429
- maxItems: 4,
430
- raffleType: "all",
431
- showEntryCount: true,
432
- showCountdown: true,
494
+ title: "Follow along",
495
+ subtitle: "New arrivals and community highlights.",
496
+ platform: "instagram",
497
+ handle: "letitrip.in",
498
+ postType: "all",
499
+ count: 9,
500
+ layout: "grid",
501
+ showCaption: true,
502
+ showStats: false,
433
503
  },
434
- createdAt: daysAgo(2),
435
- updatedAt: daysAgo(2),
504
+ createdAt: daysAgo(90),
505
+ updatedAt: daysAgo(25),
436
506
  },
507
+ /*
508
+ * REMOVED — `section-brand-takara-tomy` and `section-brand-beyblade`.
509
+ *
510
+ * Both were `products` sections with a `filterByBrand`. All three products
511
+ * sections share ONE `getFeaturedProducts(12)` result and the brand filter is
512
+ * applied client-side, so each strip filtered the same twelve rows and
513
+ * usually rendered empty. They were also the most catalogue-specific thing on
514
+ * the page.
515
+ *
516
+ * 🛑 `appkit-seed load` UPSERTS and never deletes. Dropping them from this
517
+ * array does not remove them from Firestore — delete both documents at
518
+ * /admin/sections after seeding, or they keep rendering.
519
+ */
437
520
  ];