@mohasinac/appkit 4.53.2 → 4.54.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 (350) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/_internal/server/features/auth/capabilities.js +7 -5
  3. package/dist/_internal/server/features/checkout/actions.d.ts +22 -6
  4. package/dist/_internal/server/features/checkout/actions.js +96 -51
  5. package/dist/_internal/server/features/checkout/index.d.ts +1 -1
  6. package/dist/_internal/server/features/checkout/index.js +1 -1
  7. package/dist/_internal/server/features/checkout/supplier-identity.js +28 -6
  8. package/dist/_internal/server/features/orders/adapters.js +1 -3
  9. package/dist/_internal/server/features/products/listing-tab-counts.js +81 -25
  10. package/dist/_internal/server/features/search/index-build/sources.js +43 -2
  11. package/dist/_internal/server/features/site-settings/adapters.js +1 -1
  12. package/dist/_internal/server/features/stores/adapters.d.ts +1 -1
  13. package/dist/_internal/server/features/stores/adapters.js +0 -1
  14. package/dist/_internal/server/jobs/core/analyticsAlertEvaluate.js +2 -5
  15. package/dist/_internal/server/jobs/core/jobRunners.js +0 -10
  16. package/dist/_internal/server/jobs/core/onOrderCreate.js +10 -104
  17. package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +0 -2
  18. package/dist/_internal/server/jobs/core/onOrderStatusChange.js +0 -1
  19. package/dist/_internal/server/jobs/core/onScamReportCreate.js +0 -1
  20. package/dist/_internal/server/jobs/core/onScamReportRejected.js +0 -1
  21. package/dist/_internal/server/jobs/core/onScamReportVerified.js +0 -1
  22. package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +0 -1
  23. package/dist/_internal/server/jobs/core/pendingOrderTimeout.js +0 -1
  24. package/dist/_internal/server/notifications/channel-health.d.ts +7 -3
  25. package/dist/_internal/server/notifications/channel-health.js +2 -2
  26. package/dist/_internal/server/notifications/send-guard.d.ts +1 -1
  27. package/dist/_internal/server/notifications/send-guard.js +2 -4
  28. package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
  29. package/dist/_internal/shared/actions/action-registry.js +128 -28
  30. package/dist/_internal/shared/checkout/order-math.d.ts +1 -1
  31. package/dist/_internal/shared/checkout/order-math.js +1 -1
  32. package/dist/_internal/shared/features/categories/bundle-copy.d.ts +1 -1
  33. package/dist/_internal/shared/features/checkout/config.d.ts +0 -2
  34. package/dist/_internal/shared/features/checkout/config.js +0 -2
  35. package/dist/_internal/shared/features/messaging/config.d.ts +7 -5
  36. package/dist/_internal/shared/features/messaging/config.js +1 -4
  37. package/dist/_internal/shared/features/site-settings/fees.d.ts +0 -2
  38. package/dist/_internal/shared/features/site-settings/fees.js +0 -2
  39. package/dist/_internal/shared/features/site-settings/supplier-of-record.d.ts +56 -0
  40. package/dist/_internal/shared/features/site-settings/supplier-of-record.js +57 -0
  41. package/dist/_internal/shared/fees/calculator.d.ts +0 -8
  42. package/dist/_internal/shared/fees/calculator.js +0 -7
  43. package/dist/_internal/shared/listing-types/tiers.d.ts +94 -0
  44. package/dist/_internal/shared/listing-types/tiers.js +150 -0
  45. package/dist/cli/index.js +0 -2
  46. package/dist/client.d.ts +25 -4
  47. package/dist/client.js +36 -5
  48. package/dist/constants/api-endpoints.d.ts +21 -15
  49. package/dist/constants/api-endpoints.js +7 -8
  50. package/dist/constants/field-names.d.ts +1 -0
  51. package/dist/constants/field-names.js +1 -0
  52. package/dist/constants/notification-types.d.ts +1 -1
  53. package/dist/constants/notification-types.js +1 -1
  54. package/dist/core/integration-keys.d.ts +5 -5
  55. package/dist/core/integration-keys.js +21 -10
  56. package/dist/features/about/components/FeesView.js +0 -6
  57. package/dist/features/about/components/GuidesHubView.js +15 -2
  58. package/dist/features/account/components/NotificationPreferencesPanel.js +3 -4
  59. package/dist/features/account/components/UserOrdersView.js +26 -7
  60. package/dist/features/account/types/index.d.ts +0 -2
  61. package/dist/features/addresses/utils/postal-autofill.d.ts +39 -0
  62. package/dist/features/addresses/utils/postal-autofill.js +54 -0
  63. package/dist/features/admin/actions/notification-actions.d.ts +2 -8
  64. package/dist/features/admin/actions/notification-actions.js +9 -104
  65. package/dist/features/admin/components/AdminGuideHubView.js +1 -8
  66. package/dist/features/admin/components/AdminOrderEditorView.d.ts +1 -1
  67. package/dist/features/admin/components/AdminOrdersView.js +0 -2
  68. package/dist/features/admin/components/AdminSectionsView.js +3 -2
  69. package/dist/features/admin/components/AdminSiteSettingsView.js +22 -68
  70. package/dist/features/admin/components/AdminStoreEditorView.js +72 -34
  71. package/dist/features/admin/components/OwnerQuickActions.d.ts +29 -0
  72. package/dist/features/admin/components/OwnerQuickActions.js +142 -0
  73. package/dist/features/admin/components/sections/adminSectionsTypes.js +13 -4
  74. package/dist/features/admin/components/sections/icon-options.d.ts +21 -0
  75. package/dist/features/admin/components/sections/icon-options.js +23 -0
  76. package/dist/features/admin/components/sections/sectionTemplates.js +4 -1
  77. package/dist/features/admin/constants/site-settings-tabs.d.ts +7 -12
  78. package/dist/features/admin/constants/site-settings-tabs.js +6 -12
  79. package/dist/features/admin/repository/site-settings.repository.js +1 -1
  80. package/dist/features/admin/schemas/admin-editor-forms.d.ts +1 -1
  81. package/dist/features/admin/schemas/admin-editor-forms.js +4 -1
  82. package/dist/features/admin/schemas/admin-user-form.d.ts +0 -61
  83. package/dist/features/admin/schemas/admin-user-form.js +3 -44
  84. package/dist/features/admin/schemas/firestore.d.ts +28 -54
  85. package/dist/features/admin/schemas/firestore.js +40 -18
  86. package/dist/features/auctions/components/AuctionDetailPageView.js +4 -3
  87. package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +11 -1
  88. package/dist/features/auctions/components/MarketplaceAuctionCard.js +9 -2
  89. package/dist/features/auth/checkout-value-otp.d.ts +1 -1
  90. package/dist/features/auth/checkout-value-otp.js +1 -1
  91. package/dist/features/auth/permissions/constants.d.ts +29 -2
  92. package/dist/features/auth/permissions/constants.js +67 -1
  93. package/dist/features/blog/components/BlogFeaturedCard.d.ts +11 -1
  94. package/dist/features/blog/components/BlogFeaturedCard.js +9 -2
  95. package/dist/features/cart/components/CartDrawer.js +3 -2
  96. package/dist/features/cart/components/CartGroupLineRow.js +2 -1
  97. package/dist/features/cart/components/CartPriceBreakdown.d.ts +0 -2
  98. package/dist/features/cart/components/CartPriceBreakdown.js +1 -1
  99. package/dist/features/cart/components/StoreAddonsPicker.d.ts +2 -5
  100. package/dist/features/cart/components/StoreAddonsPicker.js +4 -5
  101. package/dist/features/cart/hooks/useAddToCart.js +10 -5
  102. package/dist/features/cart/repository/cart.repository.js +1 -2
  103. package/dist/features/cart/schemas/firestore.d.ts +1 -2
  104. package/dist/features/cart/utils/pending-ops.d.ts +11 -1
  105. package/dist/features/cart/utils/pending-ops.js +14 -2
  106. package/dist/features/categories/components/BrandDetailPageView.js +2 -1
  107. package/dist/features/categories/components/BundleDetailView.js +2 -1
  108. package/dist/features/categories/components/CategoryDetailPageView.js +2 -1
  109. package/dist/features/categories/components/CategoryGrid.d.ts +11 -1
  110. package/dist/features/categories/components/CategoryGrid.js +9 -2
  111. package/dist/features/checkout/actions/checkout-value-otp-actions.d.ts +10 -5
  112. package/dist/features/checkout/actions/checkout-value-otp-actions.js +2 -88
  113. package/dist/features/classified/components/ClassifiedDetailPageView.js +2 -1
  114. package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +2 -1
  115. package/dist/features/events/components/EventCard.d.ts +11 -1
  116. package/dist/features/events/components/EventCard.js +9 -2
  117. package/dist/features/grouped/components/GroupedListingDetailView.js +3 -1
  118. package/dist/features/homepage/components/CTABannerSection.d.ts +3 -1
  119. package/dist/features/homepage/components/CTABannerSection.js +6 -3
  120. package/dist/features/homepage/components/HeroCarousel.js +8 -6
  121. package/dist/features/homepage/components/MarketplaceHomepageView.js +33 -7
  122. package/dist/features/homepage/components/SectionCarousel.js +13 -5
  123. package/dist/features/homepage/components/SecurityHighlightsSection.d.ts +8 -3
  124. package/dist/features/homepage/components/SecurityHighlightsSection.js +2 -2
  125. package/dist/features/homepage/components/StatsCounterSection.d.ts +9 -4
  126. package/dist/features/homepage/components/StatsCounterSection.js +2 -2
  127. package/dist/features/homepage/components/TestimonialsCarousel.js +1 -1
  128. package/dist/features/homepage/components/TrustFeaturesSection.d.ts +18 -4
  129. package/dist/features/homepage/components/TrustFeaturesSection.js +5 -5
  130. package/dist/features/homepage/components/WelcomeSection.d.ts +13 -2
  131. package/dist/features/homepage/components/WelcomeSection.js +3 -3
  132. package/dist/features/homepage/components/WhatsAppCommunitySection.d.ts +28 -0
  133. package/dist/features/homepage/components/WhatsAppCommunitySection.js +42 -6
  134. package/dist/features/homepage/components/WhatsAppGlyph.d.ts +20 -0
  135. package/dist/features/homepage/components/WhatsAppGlyph.js +20 -0
  136. package/dist/features/homepage/constants/hero-carousel-styles.d.ts +8 -6
  137. package/dist/features/homepage/constants/hero-carousel-styles.js +8 -6
  138. package/dist/features/homepage/constants/section-copy.d.ts +12 -10
  139. package/dist/features/homepage/constants/section-copy.js +28 -6
  140. package/dist/features/homepage/constants/stat-icons.d.ts +12 -0
  141. package/dist/features/homepage/constants/stat-icons.js +17 -0
  142. package/dist/features/homepage/constants/trust-icon-aliases.d.ts +8 -0
  143. package/dist/features/homepage/constants/trust-icon-aliases.js +75 -0
  144. package/dist/features/homepage/lib/section-defaults.d.ts +16 -1
  145. package/dist/features/homepage/lib/section-defaults.js +24 -4
  146. package/dist/features/homepage/lib/section-renderer.js +48 -8
  147. package/dist/features/homepage/schemas/firestore.d.ts +18 -1
  148. package/dist/features/layout/AppLayoutShell.js +2 -1
  149. package/dist/features/layout/BottomActions.d.ts +1 -0
  150. package/dist/features/layout/BottomActions.js +330 -0
  151. package/dist/features/layout/BottomChrome.d.ts +45 -0
  152. package/dist/features/layout/BottomChrome.js +5 -17
  153. package/dist/features/layout/SideActionDock.js +36 -13
  154. package/dist/features/layout/index.d.ts +2 -7
  155. package/dist/features/layout/index.js +7 -7
  156. package/dist/features/layout/useIsDesktop.d.ts +36 -0
  157. package/dist/features/layout/useIsDesktop.js +48 -0
  158. package/dist/features/live/components/LiveItemDetailPageView.js +2 -1
  159. package/dist/features/orders/actions/refund-actions.js +0 -1
  160. package/dist/features/orders/components/OrderAddonBadges.d.ts +1 -3
  161. package/dist/features/orders/components/OrderAddonBadges.js +3 -4
  162. package/dist/features/orders/components/OrderPaymentSummary.js +15 -2
  163. package/dist/features/orders/components/YourPurchaseStrip.d.ts +24 -0
  164. package/dist/features/orders/components/YourPurchaseStrip.js +77 -0
  165. package/dist/features/orders/components/index.d.ts +2 -1
  166. package/dist/features/orders/components/index.js +1 -1
  167. package/dist/features/orders/repository/orders.repository.d.ts +0 -8
  168. package/dist/features/orders/repository/orders.repository.js +0 -2
  169. package/dist/features/orders/schemas/firestore.d.ts +17 -9
  170. package/dist/features/orders/types/index.d.ts +2 -5
  171. package/dist/features/orders/utils/order-announcement-message.d.ts +18 -0
  172. package/dist/features/orders/utils/order-announcement-message.js +16 -0
  173. package/dist/features/orders/utils/payment-proof-message.d.ts +20 -0
  174. package/dist/features/orders/utils/payment-proof-message.js +17 -0
  175. package/dist/features/parts/components/PartDetailPageView.js +96 -1
  176. package/dist/features/parts/schemas/firestore.d.ts +247 -0
  177. package/dist/features/parts/schemas/firestore.js +6 -6
  178. package/dist/features/pre-orders/components/MarketplacePreorderCard.d.ts +11 -1
  179. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +10 -3
  180. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +4 -3
  181. package/dist/features/products/api/[id]/route.js +8 -1
  182. package/dist/features/products/api/route.js +16 -4
  183. package/dist/features/products/components/AvailabilityScopeHint.js +1 -1
  184. package/dist/features/products/components/InteractiveProductCard.d.ts +7 -1
  185. package/dist/features/products/components/InteractiveProductCard.js +16 -4
  186. package/dist/features/products/components/MarketplaceBundleCard.d.ts +11 -1
  187. package/dist/features/products/components/MarketplaceBundleCard.js +9 -2
  188. package/dist/features/products/components/MarketplacePrizeDrawCard.d.ts +11 -1
  189. package/dist/features/products/components/MarketplacePrizeDrawCard.js +9 -2
  190. package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -1
  191. package/dist/features/products/components/ProductDetailPageView.js +27 -2
  192. package/dist/features/products/components/ProductGrid.d.ts +14 -1
  193. package/dist/features/products/components/ProductGrid.js +22 -5
  194. package/dist/features/products/components/ProductsIndexListing.js +2 -2
  195. package/dist/features/reviews/api/[id]/route.js +83 -23
  196. package/dist/features/reviews/components/PurchaseReviewAffordance.d.ts +6 -0
  197. package/dist/features/reviews/components/PurchaseReviewAffordance.js +42 -0
  198. package/dist/features/reviews/components/ReviewFormDrawer.d.ts +34 -0
  199. package/dist/features/reviews/components/ReviewFormDrawer.js +127 -0
  200. package/dist/features/reviews/components/index.d.ts +4 -0
  201. package/dist/features/reviews/components/index.js +2 -0
  202. package/dist/features/scams/schemas/index.d.ts +10 -10
  203. package/dist/features/search/action-index/settings-entries.js +0 -9
  204. package/dist/features/seller/actions/seller-actions.d.ts +1 -1
  205. package/dist/features/seller/actions/seller-actions.js +49 -3
  206. package/dist/features/seller/components/SellerPayoutSettingsView.js +30 -2
  207. package/dist/features/seller/components/SellerProductShell.d.ts +17 -1
  208. package/dist/features/seller/hooks/useStoreListingEntitlements.d.ts +8 -0
  209. package/dist/features/seller/hooks/useStoreListingEntitlements.js +70 -0
  210. package/dist/features/store-extensions/repository/store-extensions.repositories.d.ts +1 -6
  211. package/dist/features/store-extensions/repository/store-extensions.repositories.js +1 -10
  212. package/dist/features/store-extensions/schemas/firestore.d.ts +1 -17
  213. package/dist/features/store-extensions/schemas/firestore.js +0 -10
  214. package/dist/features/stores/components/InteractiveStoreCard.d.ts +11 -1
  215. package/dist/features/stores/components/InteractiveStoreCard.js +9 -2
  216. package/dist/features/stores/components/StoreCapabilitiesGuideView.js +0 -1
  217. package/dist/features/stores/components/StoreGuideHubView.js +2 -8
  218. package/dist/features/stores/components/StoreSettingsGuideView.js +2 -6
  219. package/dist/features/stores/components/index.d.ts +0 -2
  220. package/dist/features/stores/components/index.js +0 -1
  221. package/dist/features/stores/repository/store.repository.d.ts +1 -26
  222. package/dist/features/stores/repository/store.repository.js +5 -60
  223. package/dist/features/stores/schemas/firestore.d.ts +6 -25
  224. package/dist/features/stores/schemas/firestore.js +6 -3
  225. package/dist/features/stores/schemas/index.d.ts +1 -87
  226. package/dist/features/stores/schemas/index.js +10 -15
  227. package/dist/features/tester/seed-data/authored/admin__site-system.js +0 -48
  228. package/dist/features/tester/seed-data/authored/buying__buying-checkout.js +0 -40
  229. package/dist/features/tester/seed-data/authored/selling__quick-add-minimum-details.js +0 -16
  230. package/dist/features/tester/seed-data/authored/selling__seller-guide.js +1 -1
  231. package/dist/features/tester/seed-data/authored/selling__seller-marketing-extras.js +0 -79
  232. package/dist/features/tester/seed-data/authored/selling__seller-orders.js +1 -1
  233. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +415 -69
  234. package/dist/index.d.ts +20 -32
  235. package/dist/index.js +34 -43
  236. package/dist/next/routing/route-map.d.ts +2 -8
  237. package/dist/next/routing/route-map.js +21 -4
  238. package/dist/providers/db-firebase/base.repository.d.ts +1 -1
  239. package/dist/providers/db-firebase/base.repository.js +1 -1
  240. package/dist/providers/payment-razorpay/index.d.ts +125 -0
  241. package/dist/providers/payment-razorpay/index.js +232 -0
  242. package/dist/providers/payment-razorpay/signature.d.ts +53 -0
  243. package/dist/providers/payment-razorpay/signature.js +71 -0
  244. package/dist/providers/shipping-shiprocket/index.d.ts +98 -0
  245. package/dist/providers/shipping-shiprocket/index.js +356 -0
  246. package/dist/providers.d.ts +3 -0
  247. package/dist/providers.js +3 -0
  248. package/dist/react/hooks/useCanSeePrices.d.ts +0 -27
  249. package/dist/react/hooks/useCanSeePrices.js +25 -0
  250. package/dist/repositories/index.d.ts +1 -1
  251. package/dist/repositories/index.js +1 -1
  252. package/dist/schemas/registry.d.ts +10 -115
  253. package/dist/schemas/registry.js +1 -2
  254. package/dist/security/pii-encrypt.js +1 -1
  255. package/dist/seed/_helpers/category-forest.js +27 -0
  256. package/dist/seed/_helpers/category-parts-glossary-map.js +1816 -88
  257. package/dist/seed/_helpers/category-parts.d.ts +1 -1
  258. package/dist/seed/_helpers/category-parts.js +13399 -3019
  259. package/dist/seed/carousel-slides-seed-data.js +47 -10
  260. package/dist/seed/categories-seed-data.js +48 -6
  261. package/dist/seed/faq-seed-data.js +2 -2
  262. package/dist/seed/homepage-sections-seed-data.js +286 -54
  263. package/dist/seed/index.d.ts +1 -1
  264. package/dist/seed/index.js +1 -1
  265. package/dist/seed/manifest.d.ts +1 -1
  266. package/dist/seed/manifest.js +1 -2
  267. package/dist/seed/model-composition-seed-data.js +6 -8
  268. package/dist/seed/part-glossary/chunk0.d.ts +9 -0
  269. package/dist/seed/part-glossary/chunk0.js +35448 -0
  270. package/dist/seed/part-glossary/chunk1.d.ts +9 -0
  271. package/dist/seed/part-glossary/chunk1.js +40494 -0
  272. package/dist/seed/part-glossary/chunk2.d.ts +9 -0
  273. package/dist/seed/part-glossary/chunk2.js +51242 -0
  274. package/dist/seed/part-glossary/chunk3.d.ts +9 -0
  275. package/dist/seed/part-glossary/chunk3.js +53337 -0
  276. package/dist/seed/part-glossary/chunk4.d.ts +9 -0
  277. package/dist/seed/part-glossary/chunk4.js +51454 -0
  278. package/dist/seed/part-glossary-seed-data.d.ts +1 -1
  279. package/dist/seed/part-glossary-seed-data.js +23 -47483
  280. package/dist/seed/products-catalogue-seed-data.d.ts +5 -5
  281. package/dist/seed/products-catalogue-seed-data.js +63936 -13803
  282. package/dist/seed/site-settings-seed-data.js +34 -35
  283. package/dist/seed/store-extensions-seed-data.d.ts +1 -2
  284. package/dist/seed/store-extensions-seed-data.js +1 -23
  285. package/dist/seed/stores-seed-data.js +0 -1
  286. package/dist/server-entry.d.ts +1 -1
  287. package/dist/server-entry.js +1 -1
  288. package/dist/server.d.ts +8 -10
  289. package/dist/server.js +16 -22
  290. package/dist/styles.css +392 -43
  291. package/dist/tailwind-utilities.css +1 -1
  292. package/dist/tokens/themes/default-dark.js +1 -1
  293. package/dist/tokens/themes/default-light.js +2 -1
  294. package/dist/tokens/tokens.css +6 -2
  295. package/dist/ui/components/Button.d.ts +11 -0
  296. package/dist/ui/components/Button.js +11 -0
  297. package/dist/ui/components/Button.style.css +29 -0
  298. package/dist/ui/components/CarouselNav.d.ts +57 -0
  299. package/dist/ui/components/CarouselNav.js +25 -0
  300. package/dist/ui/components/CarouselNav.style.css +265 -0
  301. package/dist/ui/components/GatedPrice.js +30 -3
  302. package/dist/ui/components/GatedPrice.style.css +43 -40
  303. package/dist/ui/components/HorizontalScroller.d.ts +12 -1
  304. package/dist/ui/components/HorizontalScroller.js +43 -3
  305. package/dist/ui/components/ImageMosaic.d.ts +8 -1
  306. package/dist/ui/components/ImageMosaic.js +3 -2
  307. package/dist/ui/components/ImageMosaic.style.css +22 -0
  308. package/dist/ui/components/Layout.style.css +6 -0
  309. package/dist/ui/components/Semantic.d.ts +3 -2
  310. package/dist/ui/components/Semantic.js +1 -0
  311. package/dist/ui/components/Typography.d.ts +2 -0
  312. package/dist/ui/components/Typography.js +2 -0
  313. package/dist/ui/components/Typography.style.css +19 -0
  314. package/dist/ui/components/index.style.css +1 -0
  315. package/dist/ui/index.d.ts +3 -1
  316. package/dist/ui/index.js +4 -0
  317. package/package.json +3 -2
  318. package/dist/_internal/server/jobs/core/whatsappCatalogImport.d.ts +0 -27
  319. package/dist/_internal/server/jobs/core/whatsappCatalogImport.js +0 -172
  320. package/dist/_internal/server/jobs/core/whatsappNotify.d.ts +0 -35
  321. package/dist/_internal/server/jobs/core/whatsappNotify.js +0 -140
  322. package/dist/features/admin/components/AdminWhatsAppGuideView.d.ts +0 -2
  323. package/dist/features/admin/components/AdminWhatsAppGuideView.js +0 -35
  324. package/dist/features/orders/components/MarketplaceOrderCard.d.ts +0 -36
  325. package/dist/features/orders/components/MarketplaceOrderCard.js +0 -57
  326. package/dist/features/stores/components/StoreWhatsAppGuideView.d.ts +0 -3
  327. package/dist/features/stores/components/StoreWhatsAppGuideView.js +0 -12
  328. package/dist/features/whatsapp-bot/api/send-status/route.d.ts +0 -12
  329. package/dist/features/whatsapp-bot/api/send-status/route.js +0 -38
  330. package/dist/features/whatsapp-bot/api/webhook/route.d.ts +0 -12
  331. package/dist/features/whatsapp-bot/api/webhook/route.js +0 -43
  332. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.d.ts +0 -6
  333. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +0 -270
  334. package/dist/features/whatsapp-bot/components/WhatsAppChatButton.d.ts +0 -9
  335. package/dist/features/whatsapp-bot/components/WhatsAppChatButton.js +0 -7
  336. package/dist/features/whatsapp-bot/components/index.d.ts +0 -3
  337. package/dist/features/whatsapp-bot/components/index.js +0 -2
  338. package/dist/features/whatsapp-bot/helpers/payment-proof-message.d.ts +0 -14
  339. package/dist/features/whatsapp-bot/helpers/payment-proof-message.js +0 -17
  340. package/dist/features/whatsapp-bot/helpers/whatsapp.d.ts +0 -52
  341. package/dist/features/whatsapp-bot/helpers/whatsapp.js +0 -283
  342. package/dist/features/whatsapp-bot/index.d.ts +0 -3
  343. package/dist/features/whatsapp-bot/index.js +0 -3
  344. package/dist/features/whatsapp-bot/manifest.d.ts +0 -2
  345. package/dist/features/whatsapp-bot/manifest.js +0 -13
  346. package/dist/features/whatsapp-bot/messages/en.json +0 -7
  347. package/dist/features/whatsapp-bot/server.d.ts +0 -7
  348. package/dist/features/whatsapp-bot/server.js +0 -7
  349. package/dist/features/whatsapp-bot/types/index.d.ts +0 -126
  350. package/dist/features/whatsapp-bot/types/index.js +0 -1
@@ -11,4 +11,32 @@ export interface WhatsAppCommunitySectionProps {
11
11
  isLoading?: boolean;
12
12
  className?: string;
13
13
  }
14
+ /**
15
+ * The community invite.
16
+ *
17
+ * ## 🛑 It looks like a chat because it IS a chat invite
18
+ *
19
+ * This was a single flat card: icon row → heading → description → a 2-column
20
+ * grid of four identical `✓` circles → an italic blockquote → a button, all
21
+ * left-aligned in one top-down stack. Two of those blocks (the `✓` grid and the
22
+ * blockquote) spent a lot of vertical space *telling* you the group is useful.
23
+ * As bubbles on WhatsApp's own wallpaper they *show* it, in less room.
24
+ *
25
+ * Everything needed already existed and had no consumer: `Card`'s
26
+ * `chat-bubble-mine` / `chat-bubble-theirs` variants (with the correct corner
27
+ * notches and an auto-margin for right alignment) and the
28
+ * `--appkit-color-whatsapp-bg` beige token.
29
+ *
30
+ * ## 🛑 Three things that are deliberate
31
+ *
32
+ * 1. **No fabricated timestamps and no `✓✓` read receipts.** Tempting, and the
33
+ * same category of claim as a made-up member count — which this feature
34
+ * already refuses to invent. The bubble shape carries the motif on its own.
35
+ * 2. **`align="start"` on the thread is load-bearing.** `chat-bubble-*` is
36
+ * `display:inline-block; max-width:80%`, and a stretched flex item defeats
37
+ * both, so the bubbles would become full-width boxes.
38
+ * 3. **`tone="whatsapp"`, not `tone="accent-banner"`.** The old tone is brand
39
+ * primary→secondary — the SAME gradient as `CTABannerSection` a couple of
40
+ * sections below, which is a real part of why the page read monotonous.
41
+ */
14
42
  export declare function WhatsAppCommunitySection({ title, descriptionHtml, memberCount, memberCountLabel, testimonial, benefits, buttonText, groupLink, isLoading, className, }: WhatsAppCommunitySectionProps): React.JSX.Element | null;
@@ -1,12 +1,38 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Blockquote, Button, Div, Heading, RichText, Row, Section, Span, Text } from "../../../ui/index.js";
4
- import { Users } from "lucide-react";
3
+ import { Button, Card, Div, Grid, Heading, Icon, RichText, Row, Section, Span, Stack, Text } from "../../../ui/index.js";
5
4
  import { getDefaultLocale } from "../../../core/baseline-resolver.js";
6
- import { useHandMode } from "../../../_internal/client/hand-mode/index.js";
5
+ import { WhatsAppGlyph } from "./WhatsAppGlyph.js";
7
6
  // --- Section -----------------------------------------------------------------
7
+ /**
8
+ * The community invite.
9
+ *
10
+ * ## 🛑 It looks like a chat because it IS a chat invite
11
+ *
12
+ * This was a single flat card: icon row → heading → description → a 2-column
13
+ * grid of four identical `✓` circles → an italic blockquote → a button, all
14
+ * left-aligned in one top-down stack. Two of those blocks (the `✓` grid and the
15
+ * blockquote) spent a lot of vertical space *telling* you the group is useful.
16
+ * As bubbles on WhatsApp's own wallpaper they *show* it, in less room.
17
+ *
18
+ * Everything needed already existed and had no consumer: `Card`'s
19
+ * `chat-bubble-mine` / `chat-bubble-theirs` variants (with the correct corner
20
+ * notches and an auto-margin for right alignment) and the
21
+ * `--appkit-color-whatsapp-bg` beige token.
22
+ *
23
+ * ## 🛑 Three things that are deliberate
24
+ *
25
+ * 1. **No fabricated timestamps and no `✓✓` read receipts.** Tempting, and the
26
+ * same category of claim as a made-up member count — which this feature
27
+ * already refuses to invent. The bubble shape carries the motif on its own.
28
+ * 2. **`align="start"` on the thread is load-bearing.** `chat-bubble-*` is
29
+ * `display:inline-block; max-width:80%`, and a stretched flex item defeats
30
+ * both, so the bubbles would become full-width boxes.
31
+ * 3. **`tone="whatsapp"`, not `tone="accent-banner"`.** The old tone is brand
32
+ * primary→secondary — the SAME gradient as `CTABannerSection` a couple of
33
+ * sections below, which is a real part of why the page read monotonous.
34
+ */
8
35
  export function WhatsAppCommunitySection({ title, descriptionHtml, memberCount, memberCountLabel = "members", testimonial, benefits = [], buttonText = "Join our WhatsApp community", groupLink, isLoading = false, className = "", }) {
9
- const { hand } = useHandMode();
10
36
  if (isLoading) {
11
37
  return (_jsx(Section, { paddingX: "x-md-2xl", className: className, surface: "subtle", paddingY: "y-4xl", children: _jsx(Div, { className: "w-full max-w-7xl mx-auto", children: _jsx(Div, { className: "h-72 animate-pulse", surface: "subtle", rounded: "2xl" }) }) }));
12
38
  }
@@ -14,7 +40,17 @@ export function WhatsAppCommunitySection({ title, descriptionHtml, memberCount,
14
40
  return null;
15
41
  const handleJoin = () => {
16
42
  if (groupLink)
17
- window.open(groupLink, "_blank");
43
+ window.open(groupLink, "_blank", "noopener,noreferrer");
18
44
  };
19
- return (_jsx(Section, { paddingX: "x-md-2xl", className: className, surface: "subtle", paddingY: "y-4xl", children: _jsx(Div, { className: "w-full max-w-7xl mx-auto", children: _jsxs(Section, { color: "inverse", tone: "accent-banner", rounded: "2xl", shadow: "lg", className: "relative overflow-hidden", children: [_jsx(Div, { className: "absolute inset-0 opacity-[0.06] pointer-events-none bg-[repeating-linear-gradient(45deg,white_0,white_1px,transparent_0,transparent_50%)] bg-[size:10px_10px]", "aria-hidden": true }), _jsxs(Div, { className: "relative z-10 px-[1.5rem] sm:px-[2.5rem] sm:py-[3rem]", padding: "y-2xl", children: [_jsxs(Row, { align: "center", justify: "between", gap: "md", wrap: true, className: "mb-8", reverse: hand === "left", children: [_jsxs(Row, { align: "center", gap: "3", children: [_jsx(Row, { className: "w-12 h-12 bg-[var(--appkit-color-whatsapp)] flex-shrink-0", align: "center", justify: "center", rounded: "xl", shadow: "lg", children: _jsx("svg", { className: "w-7 h-7 text-white", fill: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" }) }) }), _jsx(Span, { color: "inverse", size: "sm", weight: "medium", className: "/80 tracking-wide", transform: "uppercase", children: "WhatsApp Community" })] }), memberCount && (_jsxs(Row, { paddingY: "y-2xs-tall", className: "backdrop-blur-sm", surface: "frost", padding: "x-md", align: "center", gap: "sm", rounded: "full", children: [_jsx(Users, { className: "w-4 h-4 text-white/80" }), _jsxs(Span, { color: "inverse", size: "sm", weight: "semibold", children: [memberCount.toLocaleString(getDefaultLocale()), "+ ", memberCountLabel] })] }))] }), _jsx(Heading, { color: "inverse", level: 2, className: "mb-3 leading-tight", smSize: "3xl", size: "2xl", weight: "bold", children: title }), descriptionHtml && (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm max-w-none prose-invert", className: "text-white/80 text-[length:var(--appkit-text-base)] mb-6 max-w-2xl leading-relaxed" })), benefits.length > 0 && (_jsx(Div, { layout: "grid", gap: "3", className: "grid-cols-1 sm:grid-cols-2 mb-8 max-w-2xl", children: benefits.slice(0, 4).map((benefit, i) => (_jsxs(Row, { align: "start", gap: "2.5", children: [_jsx(Span, { layout: "flex-center", className: "mt-0.5 flex-shrink-0 w-5 h-5 bg-[rgba(255,255,255,0.2)]", rounded: "full", children: _jsx("svg", { className: "w-3 h-3 text-white", fill: "currentColor", viewBox: "0 0 20 20", "aria-hidden": "true", children: _jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }) }), _jsx(Span, { color: "inverse", size: "sm", className: "/90 leading-snug", children: benefit })] }, i))) })), testimonial && (_jsx(Blockquote, { paddingX: "x-md", className: "border-l-2 border-white/30 mb-8 max-w-xl", children: _jsxs(Text, { color: "inverse", variant: "none", className: "/75 italic leading-relaxed", size: "sm", children: ["\u201C", testimonial, "\u201D"] }) })), groupLink && (_jsxs(Button, { gap: "md", variant: "primary", size: "lg", onClick: handleJoin, "aria-label": buttonText, className: "!bg-[var(--appkit-color-whatsapp)] hover:!bg-[var(--appkit-color-whatsapp-light)] !text-white !border-0 font-[600]", shadow: "lg", children: [_jsx("svg", { className: "w-5 h-5 shrink-0", fill: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" }) }), buttonText] }))] })] }) }) }));
45
+ /* The thread. Benefits read as incoming messages; the testimonial closes it.
46
+ Below two there is no conversation to show, so the panel stands down and
47
+ the pitch column takes the full width rather than sitting beside an
48
+ almost-empty box. */
49
+ const thread = [...benefits.slice(0, 4), ...(testimonial ? [`“${testimonial}”`] : [])];
50
+ const showThread = thread.length >= 2;
51
+ return (_jsx(Section, { paddingX: "x-md-2xl", className: className, surface: "subtle", paddingY: "y-4xl", children: _jsx(Div, { className: "w-full max-w-7xl mx-auto", children: _jsxs(Section, { color: "inverse", tone: "whatsapp", rounded: "3xl", shadow: "xl", className: "relative overflow-hidden", children: [_jsx(Div, { className: "absolute inset-0 opacity-[0.10] pointer-events-none bg-[radial-gradient(circle_at_1px_1px,white_1px,transparent_0)] bg-[size:18px_18px]", "aria-hidden": true }), _jsxs(Grid, { cols: showThread ? "halves" : "autoLg", gap: "hero", align: "center", className: "relative z-10 px-[1.5rem] py-[2.5rem] sm:px-[2.5rem] sm:py-[3rem]", children: [_jsxs(Stack, { gap: "lg", children: [_jsxs(Row, { align: "center", gap: "md", wrap: true, children: [_jsxs(Row, { surface: "frost", rounded: "full", padding: "x-sm", paddingY: "y-2xs-tall", align: "center", gap: "xs", className: "backdrop-blur-sm", children: [_jsx(WhatsAppGlyph, { className: "h-4 w-4" }), _jsx(Span, { color: "inverse", size: "xs", weight: "semibold", transform: "uppercase", className: "tracking-[0.18em]", children: "WhatsApp Community" })] }), memberCount && (_jsxs(Row, { align: "center", gap: "xs", children: [_jsxs(Span, { layout: "flex", className: "relative h-2 w-2", "aria-hidden": true, children: [_jsx(Span, { rounded: "full", className: "absolute inline-flex h-full w-full animate-ping bg-[var(--appkit-color-surface)] opacity-75" }), _jsx(Span, { rounded: "full", className: "relative inline-flex h-2 w-2 bg-[var(--appkit-color-surface)]" })] }), _jsxs(Span, { color: "inverse-muted", size: "xs", weight: "medium", numeric: true, children: [memberCount.toLocaleString(getDefaultLocale()), "+ ", memberCountLabel] })] }))] }), _jsx(Heading, { color: "inverse", level: 2, size: "3xl", mdSize: "4xl", weight: "bold", className: "leading-[1.1] tracking-tight", children: title }), descriptionHtml && (
52
+ /* No colour class here. `prose-invert` sets `--tw-prose-body`
53
+ itself, so ANY wrapper colour loses to it — the previous
54
+ `text-white/80` on this element did nothing. */
55
+ _jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm prose-invert max-w-none", className: "max-w-md text-[length:var(--appkit-text-base)] leading-relaxed" })), groupLink && (_jsx(Row, { children: _jsxs(Button, { variant: "inverse", size: "lg", shadow: "lg", gap: "md", onClick: handleJoin, "aria-label": buttonText, children: [_jsx(WhatsAppGlyph, { className: "h-5 w-5" }), buttonText] }) }))] }), showThread && (_jsxs(Stack, { gap: "sm", align: "start", rounded: "2xl", padding: "md", shadow: "2xl", className: "bg-[var(--appkit-color-whatsapp-bg)]", role: "img", "aria-label": "Example messages from the community group", children: [thread.map((line, i) => (_jsx(Card, { padding: "none", variant: i % 2 === 1 ? "chat-bubble-mine" : "chat-bubble-theirs", children: _jsx(Text, { size: "sm", className: "leading-snug", children: line }) }, i))), _jsxs(Row, { align: "center", gap: "xs", className: "self-end pt-[var(--appkit-space-1)]", children: [_jsx(Icon, { name: "lock", size: "xs", tone: "muted" }), _jsx(Span, { size: "xs", color: "muted", children: "End-to-end encrypted by WhatsApp" })] })] }))] })] }) }) }));
20
56
  }
@@ -0,0 +1,20 @@
1
+ import React from "react";
2
+ /**
3
+ * The WhatsApp brand mark.
4
+ *
5
+ * ## 🛑 Why this is NOT in `icon-registry.ts`
6
+ *
7
+ * That registry's keys are INTENT names (`verify`, `restore`, `ship`) resolving
8
+ * to lucide glyphs, and its header is explicit that it is deliberately small
9
+ * and not a re-export of an icon set. A third-party brand mark is neither an
10
+ * intent nor a lucide glyph — registering it would make "which icon set is this
11
+ * key from?" a question with two answers.
12
+ *
13
+ * It lives here because it was inlined TWICE in `WhatsAppCommunitySection`
14
+ * (~1.2KB of identical path data in one file), and the second copy had no
15
+ * `shrink-0`, so inside a padded flex control it could shrink below its stated
16
+ * size — Root Cause #80's `UNSHRINKABLE_GLYPH`.
17
+ */
18
+ export declare function WhatsAppGlyph({ className }: {
19
+ className?: string;
20
+ }): React.JSX.Element;
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * The WhatsApp brand mark.
4
+ *
5
+ * ## 🛑 Why this is NOT in `icon-registry.ts`
6
+ *
7
+ * That registry's keys are INTENT names (`verify`, `restore`, `ship`) resolving
8
+ * to lucide glyphs, and its header is explicit that it is deliberately small
9
+ * and not a re-export of an icon set. A third-party brand mark is neither an
10
+ * intent nor a lucide glyph — registering it would make "which icon set is this
11
+ * key from?" a question with two answers.
12
+ *
13
+ * It lives here because it was inlined TWICE in `WhatsAppCommunitySection`
14
+ * (~1.2KB of identical path data in one file), and the second copy had no
15
+ * `shrink-0`, so inside a padded flex control it could shrink below its stated
16
+ * size — Root Cause #80's `UNSHRINKABLE_GLYPH`.
17
+ */
18
+ export function WhatsAppGlyph({ className = "" }) {
19
+ return (_jsx("svg", { className: `shrink-0 ${className}`, fill: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" }) }));
20
+ }
@@ -1,12 +1,14 @@
1
1
  /**
2
- * HeroCarousel-specific class strings (arrow + active/inactive dots).
2
+ * HeroCarousel-specific class strings.
3
3
  *
4
- * Extracted from `THEME_CONSTANTS.carousel.{arrow,dotActive,dotInactive}`
5
- * so the consumer sweep can drop the THEME_CONSTANTS dependency.
4
+ * 🛑 `HERO_CAROUSEL_ARROW`, `HERO_CAROUSEL_DOT_ACTIVE` and
5
+ * `HERO_CAROUSEL_DOT_INACTIVE` were DELETED 2026-10-20 along with the markup
6
+ * that consumed them. They were one of three unrelated carousel-indicator
7
+ * implementations on the homepage; all three are now
8
+ * `ui/components/CarouselNav`, whose docstring records what each of them got
9
+ * wrong. Do not reintroduce a per-surface dot or arrow style here — a second
10
+ * appearance is how the three diverged in the first place.
6
11
  */
7
- export declare const HERO_CAROUSEL_ARROW = "w-10 h-10 rounded-2xl bg-[color-mix(in_srgb,var(--appkit-color-surface)_85%,transparent)] backdrop-blur-sm shadow-lg border border-[var(--appkit-color-border)] text-[var(--appkit-color-text)] hover:-translate-y-0.5 hover:bg-[var(--appkit-color-surface)] hover:shadow-xl active:scale-95 transition-all duration-200 flex items-center justify-center";
8
- export declare const HERO_CAROUSEL_DOT_ACTIVE = "w-8 h-2 !min-h-0 rounded-full bg-[var(--appkit-color-surface)] shadow-sm transition-all duration-500";
9
- export declare const HERO_CAROUSEL_DOT_INACTIVE = "w-2 h-2 !min-h-0 rounded-full bg-white/55 shadow-sm transition-all duration-500";
10
12
  /** Absolute fill helper — `position: absolute; inset: 0`. */
11
13
  export declare const POSITION_FILL = "absolute inset-0";
12
14
  /** Flex centering helper — `flex items-center justify-center`. */
@@ -1,12 +1,14 @@
1
1
  /**
2
- * HeroCarousel-specific class strings (arrow + active/inactive dots).
2
+ * HeroCarousel-specific class strings.
3
3
  *
4
- * Extracted from `THEME_CONSTANTS.carousel.{arrow,dotActive,dotInactive}`
5
- * so the consumer sweep can drop the THEME_CONSTANTS dependency.
4
+ * 🛑 `HERO_CAROUSEL_ARROW`, `HERO_CAROUSEL_DOT_ACTIVE` and
5
+ * `HERO_CAROUSEL_DOT_INACTIVE` were DELETED 2026-10-20 along with the markup
6
+ * that consumed them. They were one of three unrelated carousel-indicator
7
+ * implementations on the homepage; all three are now
8
+ * `ui/components/CarouselNav`, whose docstring records what each of them got
9
+ * wrong. Do not reintroduce a per-surface dot or arrow style here — a second
10
+ * appearance is how the three diverged in the first place.
6
11
  */
7
- export const HERO_CAROUSEL_ARROW = "w-10 h-10 rounded-2xl bg-[color-mix(in_srgb,var(--appkit-color-surface)_85%,transparent)] backdrop-blur-sm shadow-lg border border-[var(--appkit-color-border)] text-[var(--appkit-color-text)] hover:-translate-y-0.5 hover:bg-[var(--appkit-color-surface)] hover:shadow-xl active:scale-95 transition-all duration-200 flex items-center justify-center";
8
- export const HERO_CAROUSEL_DOT_ACTIVE = "w-8 h-2 !min-h-0 rounded-full bg-[var(--appkit-color-surface)] shadow-sm transition-all duration-500";
9
- export const HERO_CAROUSEL_DOT_INACTIVE = "w-2 h-2 !min-h-0 rounded-full bg-white/55 shadow-sm transition-all duration-500";
10
12
  /** Absolute fill helper — `position: absolute; inset: 0`. */
11
13
  export const POSITION_FILL = "absolute inset-0";
12
14
  /** Flex centering helper — `flex items-center justify-center`. */
@@ -71,8 +71,10 @@ export declare const SECTION_COPY: {
71
71
  readonly featuresPill: "Built for trust";
72
72
  readonly featuresLearnMore: "Learn about our security →";
73
73
  readonly bannerPrimaryCta: "Shop All Products →";
74
- readonly bannerSecondaryCta: "Browse Auctions →";
75
- readonly whatsappDescription: "Get deal alerts, auction updates, and exclusive drops before anyone else.";
74
+ readonly bannerSecondaryCta: "Browse Categories →";
75
+ /** Eyebrow above the CTA banner headline — replaces a decorative ✨. */
76
+ readonly bannerEyebrow: "Start here";
77
+ readonly whatsappDescription: "Get deal alerts, new arrivals, and exclusive drops before anyone else.";
76
78
  /**
77
79
  * Shown only when `siteSettings.announcementBar` has no message. Was a
78
80
  * hardcoded seasonal Pokémon TCG discount, which would have gone out as
@@ -90,18 +92,18 @@ export declare const SECTION_COPY: {
90
92
  */
91
93
  export declare const WELCOME_TRUST_CHIPS: readonly [{
92
94
  readonly key: "delivery";
93
- readonly emoji: "🚀";
94
- readonly label: "Fast Delivery";
95
+ readonly iconName: "ship";
96
+ readonly label: "Fast delivery";
95
97
  }, {
96
98
  readonly key: "secure";
97
- readonly emoji: "🔒";
98
- readonly label: "Secure Payments";
99
+ readonly iconName: "lock";
100
+ readonly label: "Secure payments";
99
101
  }, {
100
102
  readonly key: "rating";
101
- readonly emoji: "⭐";
102
- readonly label: "Buyer Rated";
103
+ readonly iconName: "review";
104
+ readonly label: "Buyer rated";
103
105
  }, {
104
106
  readonly key: "returns";
105
- readonly emoji: "↩️";
106
- readonly label: "Easy Returns";
107
+ readonly iconName: "restore";
108
+ readonly label: "Easy returns";
107
109
  }];
@@ -71,8 +71,18 @@ export const SECTION_COPY = {
71
71
  featuresPill: "Built for trust",
72
72
  featuresLearnMore: "Learn about our security →",
73
73
  bannerPrimaryCta: "Shop All Products →",
74
- bannerSecondaryCta: "Browse Auctions →",
75
- whatsappDescription: "Get deal alerts, auction updates, and exclusive drops before anyone else.",
74
+ /*
75
+ * 🛑 Not "Browse Auctions →". The CTA banner is NOT in
76
+ * `HOMEPAGE_SECTION_LISTING_TYPE`, so unlike the auctions rail it is never
77
+ * gated — it renders whatever this says on a site running
78
+ * `listings.listingTypes.auction: false`, which is a button on the homepage
79
+ * leading to a browse page with nothing in it. The `secondaryHref` default in
80
+ * CTABannerSection.tsx moved with it; they are one control in two files.
81
+ */
82
+ bannerSecondaryCta: "Browse Categories →",
83
+ /** Eyebrow above the CTA banner headline — replaces a decorative ✨. */
84
+ bannerEyebrow: "Start here",
85
+ whatsappDescription: "Get deal alerts, new arrivals, and exclusive drops before anyone else.",
76
86
  /**
77
87
  * Shown only when `siteSettings.announcementBar` has no message. Was a
78
88
  * hardcoded seasonal Pokémon TCG discount, which would have gone out as
@@ -89,8 +99,20 @@ export const SECTION_COPY = {
89
99
  * Revisit if a consumer needs different ones.
90
100
  */
91
101
  export const WELCOME_TRUST_CHIPS = [
92
- { key: "delivery", emoji: "🚀", label: "Fast Delivery" },
93
- { key: "secure", emoji: "🔒", label: "Secure Payments" },
94
- { key: "rating", emoji: "⭐", label: "Buyer Rated" },
95
- { key: "returns", emoji: "↩️", label: "Easy Returns" },
102
+ /*
103
+ * 🛑 Registry icon keys, not emoji.
104
+ *
105
+ * An emoji cannot be sized — no width or height utility reaches a text
106
+ * character, so it renders at whatever the platform font fallback is, next to
107
+ * a label that IS sized (Root Cause #80). It is also a different glyph on
108
+ * every OS, which is the opposite of a design system.
109
+ *
110
+ * `🚀` was additionally just wrong: a rocket is not delivery. `ship` is a
111
+ * truck. Labels are sentence case — Title Case On Four Short Chips reads
112
+ * dated on its own.
113
+ */
114
+ { key: "delivery", iconName: "ship", label: "Fast delivery" },
115
+ { key: "secure", iconName: "lock", label: "Secure payments" },
116
+ { key: "rating", iconName: "review", label: "Buyer rated" },
117
+ { key: "returns", iconName: "restore", label: "Easy returns" },
96
118
  ];
@@ -0,0 +1,12 @@
1
+ import type { LiveStatPreset } from "../schemas/firestore";
2
+ import type { IconKey } from "../../../ui/icons/icon-registry";
3
+ /**
4
+ * `LiveStatPreset` → the glyph that means it.
5
+ *
6
+ * A live stat therefore gets a correct icon with ZERO config: the preset is
7
+ * already a closed 6-member union, so the icon is derivable from what the stat
8
+ * measures rather than being a second thing an admin has to fill in and keep
9
+ * consistent. Declared `Record<LiveStatPreset, IconKey>` so a seventh preset
10
+ * is a compile error here rather than a silently iconless tile.
11
+ */
12
+ export declare const STAT_PRESET_ICON: Record<LiveStatPreset, IconKey>;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `LiveStatPreset` → the glyph that means it.
3
+ *
4
+ * A live stat therefore gets a correct icon with ZERO config: the preset is
5
+ * already a closed 6-member union, so the icon is derivable from what the stat
6
+ * measures rather than being a second thing an admin has to fill in and keep
7
+ * consistent. Declared `Record<LiveStatPreset, IconKey>` so a seventh preset
8
+ * is a compile error here rather than a silently iconless tile.
9
+ */
10
+ export const STAT_PRESET_ICON = {
11
+ total_listings: "order",
12
+ verified_sellers: "verify",
13
+ total_buyers: "user",
14
+ platform_rating: "review",
15
+ total_orders: "cart",
16
+ total_reviews: "message",
17
+ };
@@ -0,0 +1,8 @@
1
+ import { type IconKey } from "../../../ui/icons/icon-registry";
2
+ /**
3
+ * Resolve a stored icon string to a registry key.
4
+ *
5
+ * Accepts an already-valid `IconKey` unchanged, so a value authored after the
6
+ * admin editor moved to a key picker needs no alias entry.
7
+ */
8
+ export declare function resolveTrustIcon(stored: string | undefined | null): IconKey | undefined;
@@ -0,0 +1,75 @@
1
+ import { isIconKey } from "../../../ui/icons/icon-registry.js";
2
+ /**
3
+ * Stored icon strings → `IconKey`s, for the trust / security / stats tiles.
4
+ *
5
+ * ## 🛑 Why an alias map and not a retype
6
+ *
7
+ * `TrustIndicator.icon` is a `string` and live documents hold TWO unrelated
8
+ * spellings of it:
9
+ *
10
+ * - kebab lucide names, from the seed — `"shield-check"`, `"rotate-ccw"`,
11
+ * `"message-circle"`;
12
+ * - intent slugs, from `section-defaults.ts` — `"secure-payments"`,
13
+ * `"fast-delivery"`, `"easy-returns"`, `"support"`.
14
+ *
15
+ * Neither set is a valid `IconKey` (the registry is intent-named: `verify`,
16
+ * `restore`, `message`…), so retyping the field would invalidate every stored
17
+ * document at once. Mapping instead means existing admin-authored values keep
18
+ * working and the field stays editable.
19
+ *
20
+ * ## 🛑 Why the icon was invisible before this existed
21
+ *
22
+ * All three components declared `renderIcon?: (props) => ReactNode` and the
23
+ * section renderer never passed it — a function prop has no representation in a
24
+ * Firestore document, so it was unreachable by construction. The result was
25
+ * four trust tiles rendering the same hardcoded `✓` while four *different*
26
+ * promises sat beside them, and no icon at all on the stats and security
27
+ * tiles. The admin editor round-tripped `icon` the whole time and the component
28
+ * used it only as a React key. Root Cause #51.
29
+ *
30
+ * An unmapped value resolves to `undefined` and the tile renders text-only,
31
+ * which is strictly better than one glyph standing in for everything.
32
+ */
33
+ const TRUST_ICON_ALIASES = {
34
+ // Lucide kebab names, as written by the seed and the admin editor.
35
+ "shield-check": "verify",
36
+ lock: "lock",
37
+ "rotate-ccw": "restore",
38
+ "message-circle": "message",
39
+ truck: "ship",
40
+ star: "review",
41
+ package: "order",
42
+ "trending-up": "analytics",
43
+ "help-circle": "help",
44
+ tag: "deals",
45
+ flag: "report",
46
+ // Intent slugs, as written by DEFAULT_TRUST_FEATURES.
47
+ "secure-payments": "lock",
48
+ "fast-delivery": "ship",
49
+ "easy-returns": "restore",
50
+ support: "help",
51
+ authenticity: "verify",
52
+ // Intent slugs, as written by the `features` seed config.
53
+ escrow: "lock",
54
+ "verified-sellers": "verify",
55
+ "scam-registry": "report",
56
+ "encrypted-data": "lock",
57
+ encryption: "lock",
58
+ tls: "lock",
59
+ rbac: "user",
60
+ "min-priv": "settings",
61
+ };
62
+ /**
63
+ * Resolve a stored icon string to a registry key.
64
+ *
65
+ * Accepts an already-valid `IconKey` unchanged, so a value authored after the
66
+ * admin editor moved to a key picker needs no alias entry.
67
+ */
68
+ export function resolveTrustIcon(stored) {
69
+ if (!stored)
70
+ return undefined;
71
+ const aliased = TRUST_ICON_ALIASES[stored];
72
+ if (aliased)
73
+ return aliased;
74
+ return isIconKey(stored) ? stored : undefined;
75
+ }
@@ -1,11 +1,26 @@
1
1
  /** Static default content used when Firestore section config has no override. */
2
+ import type { IconKey } from "../../../ui/icons/icon-registry";
3
+ /**
4
+ * 🛑 `iconName` holds a real `IconKey`, not a slug.
5
+ *
6
+ * These used to carry intent slugs (`"secure-payments"`, `"fast-delivery"`…)
7
+ * that nothing resolved, because the component's only icon channel was a
8
+ * `renderIcon` function prop the section renderer never passed. The slugs are
9
+ * still accepted from STORED documents via `resolveTrustIcon`, but a default
10
+ * authored here has no reason to go through an alias — so these are typed.
11
+ *
12
+ * `id` is separate from `iconName` because the old shape used the icon string
13
+ * as the React key, which collides as soon as two tiles share a glyph.
14
+ */
2
15
  export declare const DEFAULT_TRUST_FEATURES: {
3
- iconName: string;
16
+ id: string;
4
17
  title: string;
5
18
  description: string;
19
+ iconName?: IconKey;
6
20
  }[];
7
21
  export declare const DEFAULT_SECURITY_ITEMS: {
8
22
  key: string;
9
23
  title: string;
10
24
  description: string;
25
+ iconName?: IconKey;
11
26
  }[];
@@ -1,22 +1,38 @@
1
1
  /** Static default content used when Firestore section config has no override. */
2
+ /**
3
+ * 🛑 `iconName` holds a real `IconKey`, not a slug.
4
+ *
5
+ * These used to carry intent slugs (`"secure-payments"`, `"fast-delivery"`…)
6
+ * that nothing resolved, because the component's only icon channel was a
7
+ * `renderIcon` function prop the section renderer never passed. The slugs are
8
+ * still accepted from STORED documents via `resolveTrustIcon`, but a default
9
+ * authored here has no reason to go through an alias — so these are typed.
10
+ *
11
+ * `id` is separate from `iconName` because the old shape used the icon string
12
+ * as the React key, which collides as soon as two tiles share a glyph.
13
+ */
2
14
  export const DEFAULT_TRUST_FEATURES = [
3
15
  {
4
- iconName: "secure-payments",
16
+ id: "secure-payments",
17
+ iconName: "lock",
5
18
  title: "Secure Payments",
6
19
  description: "Protected payments with transparent order tracking.",
7
20
  },
8
21
  {
9
- iconName: "fast-delivery",
22
+ id: "fast-delivery",
23
+ iconName: "ship",
10
24
  title: "Fast Delivery",
11
25
  description: "Fast shipping with reliable nationwide logistics partners.",
12
26
  },
13
27
  {
14
- iconName: "easy-returns",
28
+ id: "easy-returns",
29
+ iconName: "restore",
15
30
  title: "Easy Returns",
16
31
  description: "Hassle-free returns within the policy window.",
17
32
  },
18
33
  {
19
- iconName: "support",
34
+ id: "support",
35
+ iconName: "help",
20
36
  title: "24/7 Support",
21
37
  description: "Real help from our team across pre and post purchase.",
22
38
  },
@@ -24,21 +40,25 @@ export const DEFAULT_TRUST_FEATURES = [
24
40
  export const DEFAULT_SECURITY_ITEMS = [
25
41
  {
26
42
  key: "encryption",
43
+ iconName: "lock",
27
44
  title: "End-to-End Encryption",
28
45
  description: "All sensitive data is encrypted in transit and at rest.",
29
46
  },
30
47
  {
31
48
  key: "tls",
49
+ iconName: "verify",
32
50
  title: "TLS 1.3 in Transit",
33
51
  description: "Every API call and page load is secured with modern TLS.",
34
52
  },
35
53
  {
36
54
  key: "rbac",
55
+ iconName: "user",
37
56
  title: "Role-Based Access",
38
57
  description: "Strict role boundaries keep buyer, seller, and admin data separate.",
39
58
  },
40
59
  {
41
60
  key: "min-priv",
61
+ iconName: "settings",
42
62
  title: "Minimum-Privilege Tokens",
43
63
  description: "Short-lived, scoped tokens minimise exposure on every request.",
44
64
  },
@@ -5,6 +5,11 @@ import { cleanTitle, parseWelcomeDescription } from "./section-helpers.js";
5
5
  import { DEFAULT_TRUST_FEATURES, DEFAULT_SECURITY_ITEMS } from "./section-defaults.js";
6
6
  import { SECTION_TITLE, SECTION_COPY, VIEW_MORE_LABEL, WELCOME_TRUST_CHIPS, } from "../constants/section-copy.js";
7
7
  import { FAQ_CATEGORY_LABELS } from "../constants/faq-category-labels.js";
8
+ /* Root Cause #51 — the stored `icon` string had no reader. These resolve it to
9
+ a registry key so the trust / security / stats tiles render a real glyph
10
+ instead of one hardcoded ✓ (or nothing at all). */
11
+ import { resolveTrustIcon } from "../constants/trust-icon-aliases.js";
12
+ import { STAT_PRESET_ICON } from "../constants/stat-icons.js";
8
13
  import { FAQ_HOMEPAGE_READ_CAP } from "../../faq/constants/read-caps.js";
9
14
  import { AnnouncementBar, hashBannerMessage } from "../components/AnnouncementBar.js";
10
15
  import { HeroCarousel } from "../components/HeroCarousel.js";
@@ -66,9 +71,26 @@ const SECTION_REGISTRY = {
66
71
  },
67
72
  welcome: {
68
73
  surfaces: ["homepage"],
69
- render: ({ config, brand }) => {
74
+ render: ({ config, brand, sectionData }) => {
70
75
  const cfg = config;
71
- return (_jsx(WelcomeSection, { title: cleanTitle(cfg?.h1) || SECTION_TITLE.welcome,
76
+ /*
77
+ * Hero imagery, taken from the featured categories' own covers.
78
+ *
79
+ * Deterministic — the first five in CONFIGURED order, never shuffled, so
80
+ * the server and client render the same mosaic (ImageMosaic's header is
81
+ * explicit about why `Math.random()` is wrong here).
82
+ *
83
+ * 🛑 `sectionData.categories` is only populated when the page also has a
84
+ * `categories` section enabled, because MarketplaceHomepageView gates
85
+ * each fetch on `activeTypes`. `welcome` is registered as a trigger for
86
+ * that fetch for exactly this reason; without it the mosaic silently
87
+ * falls back to the brand panel and nothing says why.
88
+ */
89
+ const heroImages = (sectionData.categories ?? [])
90
+ .map((c) => c.display?.coverImage)
91
+ .filter((src) => Boolean(src))
92
+ .slice(0, 5);
93
+ return (_jsx(WelcomeSection, { heroImages: heroImages, title: cleanTitle(cfg?.h1) || SECTION_TITLE.welcome,
72
94
  // A real `subtitle` wins; `description` is the legacy source and is
73
95
  // still parsed for documents that only carry it.
74
96
  subtitle: cfg?.subtitle?.trim() || parseWelcomeDescription(cfg?.description), pillLabel: cfg?.pillLabel || SECTION_COPY.welcomePill, showCTA: cfg?.showCTA ?? true, ctaLabel: cfg?.ctaText || SECTION_COPY.welcomePrimaryCta, ctaHref: cfg?.ctaLink || ROUTES.PUBLIC.PRODUCTS, secondaryCtaLabel: cfg?.secondaryCtaText || SECTION_COPY.welcomeSecondaryCta, secondaryCtaHref: cfg?.secondaryCtaLink || ROUTES.PUBLIC.PRODUCTS, trustChips: [...WELCOME_TRUST_CHIPS], brandLogoText: brand?.shortName }));
@@ -103,6 +125,11 @@ const SECTION_REGISTRY = {
103
125
  : `stat-${index}`,
104
126
  label: item.label,
105
127
  value: displayValue,
128
+ // Derived from the preset, so a live stat gets a correct icon
129
+ // with no extra config — the preset already says what the
130
+ // number measures. `iconName` on the config entry wins for a
131
+ // static stat, which has no metric to derive from.
132
+ iconName: resolveTrustIcon(item.iconName) ?? (item.metric ? STAT_PRESET_ICON[item.metric] : undefined),
106
133
  };
107
134
  })
108
135
  : [];
@@ -165,7 +192,7 @@ const SECTION_REGISTRY = {
165
192
  // defaults fill in when none are set. Previously both labels and both
166
193
  // hrefs were hardcoded here and `buttons[]` was ignored entirely.
167
194
  const [primaryBtn, secondaryBtn] = cfg?.buttons ?? [];
168
- return (_jsx(CTABannerSection, { title: cfg?.content?.title || SECTION_TITLE.banner, subtitle: cfg?.content?.subtitle, description: cfg?.content?.description, height: cfg?.height, backgroundImage: cfg?.backgroundImage, primaryLabel: primaryBtn?.text, primaryHref: primaryBtn?.link, secondaryLabel: secondaryBtn?.text, secondaryHref: secondaryBtn?.link }));
195
+ return (_jsx(CTABannerSection, { title: cfg?.content?.title || SECTION_TITLE.banner, eyebrow: cfg?.content?.eyebrow || SECTION_COPY.bannerEyebrow, subtitle: cfg?.content?.subtitle, description: cfg?.content?.description, height: cfg?.height, backgroundImage: cfg?.backgroundImage, primaryLabel: primaryBtn?.text, primaryHref: primaryBtn?.link, secondaryLabel: secondaryBtn?.text, secondaryHref: secondaryBtn?.link }));
169
196
  },
170
197
  },
171
198
  "trust-indicators": {
@@ -175,8 +202,10 @@ const SECTION_REGISTRY = {
175
202
  const configured = (cfg?.indicators ?? [])
176
203
  .filter((ind) => ind?.title?.trim())
177
204
  .map((ind) => ({
178
- key: ind.id,
179
- iconName: ind.icon,
205
+ // `id` is the React key; `iconName` is the glyph. These were one
206
+ // field before, so two indicators sharing an icon collided.
207
+ id: ind.id,
208
+ iconName: resolveTrustIcon(ind.icon),
180
209
  title: ind.title,
181
210
  description: ind.description,
182
211
  }));
@@ -191,7 +220,13 @@ const SECTION_REGISTRY = {
191
220
  // `items` is the real shape; `features: string[]` is the legacy one and
192
221
  // becomes title-only cards. Neither reached the component before — it
193
222
  // always rendered DEFAULT_SECURITY_ITEMS regardless of config.
194
- const configured = cfg?.items?.filter((item) => item?.title?.trim()) ??
223
+ const configured = cfg?.items
224
+ ?.filter((item) => item?.title?.trim())
225
+ // The stored `key` doubles as the icon hint — the seeded items carry
226
+ // intent slugs (`escrow`, `scam-registry`, `encrypted-data`) that the
227
+ // alias map resolves, so these tiles get real glyphs with no new
228
+ // config field. An explicit `iconName` wins when present.
229
+ .map((item) => ({ ...item, iconName: resolveTrustIcon(item.iconName ?? item.key) })) ??
195
230
  cfg?.features
196
231
  ?.filter((label) => label?.trim())
197
232
  .map((label, index) => ({ key: `feature-${index}`, title: label, description: "" })) ??
@@ -206,7 +241,7 @@ const SECTION_REGISTRY = {
206
241
  return (_jsx(WhatsAppCommunitySection, { title: cleanTitle(cfg?.title) || SECTION_TITLE.whatsappCommunity, descriptionHtml: cfg?.description || SECTION_COPY.whatsappDescription,
207
242
  // No `|| 5000` fallback: inventing a member count the site cannot
208
243
  // verify is a fabricated social-proof number.
209
- memberCount: cfg?.memberCount, groupLink: cfg?.groupLink || "https://chat.whatsapp.com/", benefits: cfg?.benefits ?? [], testimonial: cfg?.testimonial, buttonText: cfg?.buttonText }));
244
+ memberCount: cfg?.memberCount, groupLink: cfg?.groupLink || undefined, benefits: cfg?.benefits ?? [], testimonial: cfg?.testimonial, buttonText: cfg?.buttonText }));
210
245
  },
211
246
  },
212
247
  faq: {
@@ -331,7 +366,12 @@ const SECTION_REGISTRY = {
331
366
  const cfg = config;
332
367
  if (!cfg?.title || !Array.isArray(cfg.steps) || cfg.steps.length === 0)
333
368
  return null;
334
- return (_jsx(HowItWorksSection, { title: cfg.title, subtitle: cfg.subtitle, pillLabel: cfg.pillLabel, ctaLabel: cfg.ctaLabel, ctaLink: cfg.ctaLink, steps: cfg.steps }));
369
+ return (_jsx(HowItWorksSection, { title: cfg.title, subtitle: cfg.subtitle, pillLabel: cfg.pillLabel, ctaLabel: cfg.ctaLabel, ctaLink: cfg.ctaLink,
370
+ /* `cfg.steps[].iconKey` is a loose `string` (it is admin data) while
371
+ the component's is an `IconKey`. Resolving rather than casting
372
+ means an unrecognised stored value renders a step with no icon
373
+ instead of handing `<Icon>` a key it will silently drop. */
374
+ steps: cfg.steps.map((s) => ({ ...s, iconKey: resolveTrustIcon(s.iconKey) })) }));
335
375
  },
336
376
  },
337
377
  testimonials: {