@mohasinac/appkit 4.53.0 → 4.53.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 (500) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/_internal/client/scaffolds/AppShell.js +1 -1
  3. package/dist/_internal/server/features/auctions/og.d.ts +3 -1
  4. package/dist/_internal/server/features/auctions/og.js +3 -1
  5. package/dist/_internal/server/features/bundles/actions.js +1 -1
  6. package/dist/_internal/server/features/business-documents/download.d.ts +41 -0
  7. package/dist/_internal/server/features/business-documents/download.js +91 -0
  8. package/dist/_internal/server/features/categories/adapters.d.ts +1 -1
  9. package/dist/_internal/server/features/categories/adapters.js +10 -0
  10. package/dist/_internal/server/features/checkout/actions.d.ts +14 -0
  11. package/dist/_internal/server/features/checkout/actions.js +106 -12
  12. package/dist/_internal/server/features/checkout/bundle-expansion.js +17 -0
  13. package/dist/_internal/server/features/checkout/data.d.ts +22 -0
  14. package/dist/_internal/server/features/checkout/group-rule-revalidation.d.ts +34 -0
  15. package/dist/_internal/server/features/checkout/group-rule-revalidation.js +124 -0
  16. package/dist/_internal/server/features/checkout/supplier-identity.d.ts +55 -0
  17. package/dist/_internal/server/features/checkout/supplier-identity.js +81 -0
  18. package/dist/_internal/server/features/classified/metadata.js +1 -1
  19. package/dist/_internal/server/features/classified/og.d.ts +3 -1
  20. package/dist/_internal/server/features/classified/og.js +3 -1
  21. package/dist/_internal/server/features/digital-code/metadata.js +1 -1
  22. package/dist/_internal/server/features/digital-code/og.d.ts +3 -1
  23. package/dist/_internal/server/features/digital-code/og.js +3 -1
  24. package/dist/_internal/server/features/digital-code/pool.d.ts +19 -4
  25. package/dist/_internal/server/features/digital-code/pool.js +19 -4
  26. package/dist/_internal/server/features/live/metadata.js +1 -1
  27. package/dist/_internal/server/features/live/og.d.ts +3 -1
  28. package/dist/_internal/server/features/live/og.js +3 -1
  29. package/dist/_internal/server/features/messages/actions.js +1 -1
  30. package/dist/_internal/server/features/parts/og.js +1 -1
  31. package/dist/_internal/server/features/pre-orders/og.d.ts +3 -1
  32. package/dist/_internal/server/features/pre-orders/og.js +3 -1
  33. package/dist/_internal/server/features/price-index/search.d.ts +18 -0
  34. package/dist/_internal/server/features/price-index/search.js +47 -7
  35. package/dist/_internal/server/features/prize-draws/og.d.ts +3 -1
  36. package/dist/_internal/server/features/prize-draws/og.js +3 -1
  37. package/dist/_internal/server/features/products/group-members.d.ts +26 -0
  38. package/dist/_internal/server/features/products/group-members.js +7 -1
  39. package/dist/_internal/server/features/products/og.d.ts +3 -1
  40. package/dist/_internal/server/features/products/og.js +3 -1
  41. package/dist/_internal/server/features/search/scoped-sources.d.ts +26 -0
  42. package/dist/_internal/server/features/search/scoped-sources.js +252 -0
  43. package/dist/_internal/server/features/search/search-everything.d.ts +57 -0
  44. package/dist/_internal/server/features/search/search-everything.js +70 -20
  45. package/dist/_internal/server/features/seo/sitemap.js +6 -0
  46. package/dist/_internal/server/features/shared/listing-adapters.js +4 -2
  47. package/dist/_internal/server/features/sticker-trace/adapters.d.ts +11 -0
  48. package/dist/_internal/server/features/sticker-trace/adapters.js +1 -0
  49. package/dist/_internal/server/features/sticker-trace/promote-to-listings.d.ts +26 -0
  50. package/dist/_internal/server/features/sticker-trace/promote-to-listings.js +264 -0
  51. package/dist/_internal/server/features/sticker-trace/sheet-actions.d.ts +3 -1
  52. package/dist/_internal/server/features/sticker-trace/sheet-actions.js +32 -0
  53. package/dist/_internal/server/features/sticker-trace/storage.d.ts +20 -1
  54. package/dist/_internal/server/features/sticker-trace/storage.js +20 -1
  55. package/dist/_internal/server/features/stores/adapters.d.ts +1 -1
  56. package/dist/_internal/server/features/stores/adapters.js +16 -0
  57. package/dist/_internal/server/features/stores/index.d.ts +1 -0
  58. package/dist/_internal/server/features/stores/index.js +1 -0
  59. package/dist/_internal/server/features/stores/tabs.d.ts +25 -0
  60. package/dist/_internal/server/features/stores/tabs.js +122 -0
  61. package/dist/_internal/shared/checkout/rules/_defaults.js +0 -2
  62. package/dist/_internal/shared/checkout/rules/_limits.d.ts +14 -1
  63. package/dist/_internal/shared/checkout/rules/_limits.js +14 -1
  64. package/dist/_internal/shared/checkout/rules/_registry.js +2 -0
  65. package/dist/_internal/shared/checkout/rules/auction.rule.js +9 -1
  66. package/dist/_internal/shared/checkout/rules/bundle.rule.js +13 -0
  67. package/dist/_internal/shared/checkout/rules/index.d.ts +2 -0
  68. package/dist/_internal/shared/checkout/rules/index.js +9 -0
  69. package/dist/_internal/shared/checkout/rules/offer.rule.js +0 -1
  70. package/dist/_internal/shared/checkout/rules/payment-gate.d.ts +26 -0
  71. package/dist/_internal/shared/checkout/rules/payment-gate.js +133 -0
  72. package/dist/_internal/shared/checkout/rules/prize-draw.rule.js +29 -8
  73. package/dist/_internal/shared/checkout/rules/spares.rule.d.ts +16 -0
  74. package/dist/_internal/shared/checkout/rules/spares.rule.js +5 -0
  75. package/dist/_internal/shared/checkout/rules/types.d.ts +26 -2
  76. package/dist/_internal/shared/config/schema.d.ts +122 -0
  77. package/dist/_internal/shared/features/cart/schema.js +3 -2
  78. package/dist/_internal/shared/features/products/group-rules.d.ts +75 -0
  79. package/dist/_internal/shared/features/products/group-rules.js +142 -0
  80. package/dist/_internal/shared/listing-types/_registry.d.ts +24 -0
  81. package/dist/_internal/shared/listing-types/_registry.js +39 -1
  82. package/dist/_internal/shared/listing-types/art/config.d.ts +1 -0
  83. package/dist/_internal/shared/listing-types/art/config.js +2 -0
  84. package/dist/_internal/shared/listing-types/auction/config.d.ts +1 -0
  85. package/dist/_internal/shared/listing-types/auction/config.js +2 -0
  86. package/dist/_internal/shared/listing-types/availability.js +48 -0
  87. package/dist/_internal/shared/listing-types/capabilities.js +19 -0
  88. package/dist/_internal/shared/listing-types/classified/config.d.ts +1 -0
  89. package/dist/_internal/shared/listing-types/classified/config.js +2 -0
  90. package/dist/_internal/shared/listing-types/digital-code/config.d.ts +1 -0
  91. package/dist/_internal/shared/listing-types/digital-code/config.js +2 -0
  92. package/dist/_internal/shared/listing-types/feature-flags.js +1 -0
  93. package/dist/_internal/shared/listing-types/live/config.d.ts +1 -0
  94. package/dist/_internal/shared/listing-types/live/config.js +2 -0
  95. package/dist/_internal/shared/listing-types/pre-order/config.d.ts +1 -0
  96. package/dist/_internal/shared/listing-types/pre-order/config.js +2 -0
  97. package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +1 -0
  98. package/dist/_internal/shared/listing-types/prize-draw/config.js +2 -0
  99. package/dist/_internal/shared/listing-types/spares/config.d.ts +74 -0
  100. package/dist/_internal/shared/listing-types/spares/config.js +60 -0
  101. package/dist/_internal/shared/listing-types/spares/ctas.d.ts +1 -0
  102. package/dist/_internal/shared/listing-types/spares/ctas.js +4 -0
  103. package/dist/_internal/shared/listing-types/spares/og.js +1 -0
  104. package/dist/_internal/shared/listing-types/spares/schema.d.ts +2 -0
  105. package/dist/_internal/shared/listing-types/spares/schema.js +3 -0
  106. package/dist/_internal/shared/listing-types/spares/seed-factory.d.ts +1 -0
  107. package/dist/_internal/shared/listing-types/spares/seed-factory.js +1 -0
  108. package/dist/_internal/shared/listing-types/standard/config.d.ts +1 -0
  109. package/dist/_internal/shared/listing-types/standard/config.js +2 -0
  110. package/dist/_internal/shared/listing-types/stickers/config.d.ts +1 -0
  111. package/dist/_internal/shared/listing-types/stickers/config.js +2 -0
  112. package/dist/_internal/shared/search/match.d.ts +11 -0
  113. package/dist/_internal/shared/search/match.js +2 -1
  114. package/dist/_internal/shared/search/to-groups.d.ts +52 -0
  115. package/dist/_internal/shared/search/to-groups.js +141 -0
  116. package/dist/client.d.ts +8 -2
  117. package/dist/client.js +4 -1
  118. package/dist/constants/api-endpoints.d.ts +39 -15
  119. package/dist/constants/api-endpoints.js +28 -5
  120. package/dist/constants/cache-invalidation.js +3 -1
  121. package/dist/constants/field-names.d.ts +6 -0
  122. package/dist/constants/field-names.js +6 -0
  123. package/dist/features/about/components/PolicyPageView.d.ts +22 -2
  124. package/dist/features/about/components/PolicyPageView.js +14 -2
  125. package/dist/features/about/components/PublicProfileView.js +2 -1
  126. package/dist/features/about/components/ShippingPolicyView.js +42 -2
  127. package/dist/features/account/components/NotificationBell.js +1 -1
  128. package/dist/features/account/hooks/useProfileStats.js +5 -1
  129. package/dist/features/addresses/repository/addresses.repository.d.ts +16 -0
  130. package/dist/features/addresses/repository/addresses.repository.js +21 -0
  131. package/dist/features/admin/actions/admin-actions.js +16 -1
  132. package/dist/features/admin/components/AdminCategoryEditorView.js +19 -2
  133. package/dist/features/admin/components/AdminNavigationView.js +1 -1
  134. package/dist/features/admin/components/AdminPageHeader.js +1 -1
  135. package/dist/features/admin/components/AdminProductEditorView.js +17 -2
  136. package/dist/features/admin/components/AdminSidebar.js +1 -1
  137. package/dist/features/admin/components/AdminSiteSettingsView.js +39 -8
  138. package/dist/features/admin/components/AdminSparesView.d.ts +12 -0
  139. package/dist/features/admin/components/AdminSparesView.js +30 -0
  140. package/dist/features/admin/components/AdminUsersView.js +9 -7
  141. package/dist/features/admin/components/index.d.ts +2 -0
  142. package/dist/features/admin/components/index.js +1 -0
  143. package/dist/features/admin/components/sections/adminSectionsTypes.js +7 -0
  144. package/dist/features/admin/constants/filter-tabs.d.ts +3 -0
  145. package/dist/features/admin/constants/filter-tabs.js +1 -0
  146. package/dist/features/admin/schemas/firestore.d.ts +26 -2
  147. package/dist/features/auctions/components/AuctionDetailPageView.js +4 -11
  148. package/dist/features/auth/repository/user.repository.d.ts +13 -0
  149. package/dist/features/auth/repository/user.repository.js +28 -0
  150. package/dist/features/auth/schemas/firestore.d.ts +2 -0
  151. package/dist/features/auth/schemas/firestore.js +2 -0
  152. package/dist/features/business-documents/repository/business-documents.repository.d.ts +58 -0
  153. package/dist/features/business-documents/repository/business-documents.repository.js +54 -0
  154. package/dist/features/business-documents/schemas/firestore.d.ts +105 -0
  155. package/dist/features/business-documents/schemas/firestore.js +75 -0
  156. package/dist/features/cart/actions/cart-actions.js +83 -6
  157. package/dist/features/cart/repository/cart.repository.js +32 -4
  158. package/dist/features/cart/schemas/firestore.d.ts +20 -0
  159. package/dist/features/cart/schemas/index.d.ts +2 -2
  160. package/dist/features/catalogue/components/PublicCatalogueItemDetailView.js +1 -1
  161. package/dist/features/categories/api/[id]/price-guidance/route.d.ts +42 -0
  162. package/dist/features/categories/api/[id]/price-guidance/route.js +113 -0
  163. package/dist/features/categories/components/BrandDetailPageView.js +19 -3
  164. package/dist/features/categories/components/BrandDetailTabs.js +10 -0
  165. package/dist/features/categories/components/CategoriesIndexListing.js +23 -8
  166. package/dist/features/categories/components/CategoryDetailPageView.js +141 -14
  167. package/dist/features/categories/components/CategoryDetailTabs.js +12 -0
  168. package/dist/features/categories/components/CategoryGrid.js +10 -1
  169. package/dist/features/categories/components/PriceGuidanceHint.d.ts +29 -0
  170. package/dist/features/categories/components/PriceGuidanceHint.js +61 -0
  171. package/dist/features/categories/components/SubcategoryCardRow.d.ts +27 -0
  172. package/dist/features/categories/components/SubcategoryCardRow.js +98 -0
  173. package/dist/features/categories/constants/category-tabs.d.ts +20 -25
  174. package/dist/features/categories/constants/category-tabs.js +22 -39
  175. package/dist/features/categories/repository/categories.repository.d.ts +12 -0
  176. package/dist/features/categories/repository/categories.repository.js +20 -0
  177. package/dist/features/categories/schemas/firestore.d.ts +22 -1
  178. package/dist/features/categories/schemas/firestore.js +10 -0
  179. package/dist/features/categories/schemas/index.d.ts +6 -0
  180. package/dist/features/categories/schemas/index.js +2 -0
  181. package/dist/features/categories/types/index.d.ts +8 -0
  182. package/dist/features/categories/utils/taxonomy-visual.d.ts +16 -3
  183. package/dist/features/categories/utils/taxonomy-visual.js +26 -10
  184. package/dist/features/classified/components/ClassifiedDetailPageView.js +4 -9
  185. package/dist/features/contact/components/ContactPageView.d.ts +33 -1
  186. package/dist/features/contact/components/ContactPageView.js +58 -28
  187. package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +4 -9
  188. package/dist/features/grouped/components/GroupedListingDetailView.js +9 -1
  189. package/dist/features/grouped/schemas/firestore.d.ts +5 -0
  190. package/dist/features/homepage/actions/homepage-section-actions.d.ts +3 -3
  191. package/dist/features/homepage/components/CollectionCardsSection.d.ts +28 -6
  192. package/dist/features/homepage/components/CollectionCardsSection.js +43 -8
  193. package/dist/features/homepage/components/HowItWorksSection.d.ts +23 -6
  194. package/dist/features/homepage/components/HowItWorksSection.js +4 -4
  195. package/dist/features/homepage/components/PromoGrid.d.ts +31 -2
  196. package/dist/features/homepage/components/PromoGrid.js +12 -3
  197. package/dist/features/homepage/components/TestimonialsCarousel.d.ts +34 -2
  198. package/dist/features/homepage/components/TestimonialsCarousel.js +1 -1
  199. package/dist/features/homepage/components/index.d.ts +0 -20
  200. package/dist/features/homepage/components/index.js +0 -11
  201. package/dist/features/homepage/index.d.ts +0 -2
  202. package/dist/features/homepage/index.js +0 -2
  203. package/dist/features/homepage/lib/section-renderer.d.ts +9 -0
  204. package/dist/features/homepage/lib/section-renderer.js +202 -58
  205. package/dist/features/homepage/repository/homepage-sections.repository.d.ts +35 -3
  206. package/dist/features/homepage/repository/homepage-sections.repository.js +58 -8
  207. package/dist/features/homepage/schemas/firestore.d.ts +106 -3
  208. package/dist/features/homepage/schemas/firestore.js +32 -2
  209. package/dist/features/homepage/schemas/index.d.ts +36 -7
  210. package/dist/features/homepage/schemas/index.js +39 -27
  211. package/dist/features/homepage/server.d.ts +0 -3
  212. package/dist/features/homepage/server.js +0 -3
  213. package/dist/features/homepage/types/index.d.ts +0 -47
  214. package/dist/features/homepage/types/index.js +49 -0
  215. package/dist/features/layout/AppLayoutShell.js +1 -1
  216. package/dist/features/layout/BottomNavItem.js +1 -1
  217. package/dist/features/layout/BottomSheet.js +1 -1
  218. package/dist/features/layout/TitleBarLayout.js +1 -1
  219. package/dist/features/live/components/LiveItemDetailPageView.js +4 -9
  220. package/dist/features/media/hooks/useMedia.js +17 -0
  221. package/dist/features/media/repository/media-assets.repository.d.ts +46 -0
  222. package/dist/features/media/repository/media-assets.repository.js +31 -0
  223. package/dist/features/media/trust-signals.d.ts +85 -0
  224. package/dist/features/media/trust-signals.js +126 -0
  225. package/dist/features/parts/components/PartDetailPageView.d.ts +14 -1
  226. package/dist/features/parts/components/PartDetailPageView.js +2 -2
  227. package/dist/features/parts/components/PartsIndexPageView.d.ts +11 -2
  228. package/dist/features/parts/components/PartsIndexPageView.js +2 -2
  229. package/dist/features/parts/components/PartsSearchBox.d.ts +9 -0
  230. package/dist/features/parts/components/PartsSearchBox.js +57 -0
  231. package/dist/features/parts/schemas/firestore.d.ts +149 -3
  232. package/dist/features/parts/schemas/firestore.js +184 -0
  233. package/dist/features/payments/repository/payout.repository.d.ts +15 -0
  234. package/dist/features/payments/repository/payout.repository.js +21 -0
  235. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +4 -11
  236. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +1 -1
  237. package/dist/features/price-index/components/PriceIndexToolView.d.ts +3 -1
  238. package/dist/features/price-index/components/PriceIndexToolView.js +92 -13
  239. package/dist/features/products/components/CompareOverlay.d.ts +18 -1
  240. package/dist/features/products/components/CompareOverlay.js +21 -2
  241. package/dist/features/products/components/CustomSectionTabContent.d.ts +31 -0
  242. package/dist/features/products/components/CustomSectionTabContent.js +29 -3
  243. package/dist/features/products/components/GroupMemberPicker.d.ts +19 -1
  244. package/dist/features/products/components/GroupMemberPicker.js +46 -8
  245. package/dist/features/products/components/GroupSettingsPanel.d.ts +11 -1
  246. package/dist/features/products/components/GroupSettingsPanel.js +91 -3
  247. package/dist/features/products/components/PrizeDrawDetailPageView.js +1 -1
  248. package/dist/features/products/components/PrizeDrawEntryActions.d.ts +15 -1
  249. package/dist/features/products/components/PrizeDrawEntryActions.js +70 -8
  250. package/dist/features/products/components/ProductDetailPageView.js +74 -15
  251. package/dist/features/products/components/ProductForm.d.ts +13 -1
  252. package/dist/features/products/components/ProductForm.js +16 -2
  253. package/dist/features/products/components/ProductsIndexListing.d.ts +16 -1
  254. package/dist/features/products/components/ProductsIndexListing.js +3 -3
  255. package/dist/features/products/components/ShowGroupSection.js +15 -2
  256. package/dist/features/products/components/SparesListView.d.ts +7 -0
  257. package/dist/features/products/components/SparesListView.js +39 -0
  258. package/dist/features/products/constants/action-defs.d.ts +1 -0
  259. package/dist/features/products/constants/action-defs.js +1 -0
  260. package/dist/features/products/repository/products.repository.d.ts +98 -0
  261. package/dist/features/products/repository/products.repository.js +235 -17
  262. package/dist/features/products/schemas/firestore.d.ts +97 -4
  263. package/dist/features/products/schemas/firestore.js +104 -0
  264. package/dist/features/products/schemas/index.d.ts +10 -19
  265. package/dist/features/products/schemas/index.js +23 -6
  266. package/dist/features/products/types/index.d.ts +45 -1
  267. package/dist/features/products/utils/group-member-image.d.ts +39 -0
  268. package/dist/features/products/utils/group-member-image.js +3 -0
  269. package/dist/features/products/utils/listing-badge-variant.js +4 -0
  270. package/dist/features/reviews/components/ReviewsList.js +1 -1
  271. package/dist/features/scams/components/ScamProfileView.js +1 -1
  272. package/dist/features/search/components/EntityTypeahead.d.ts +44 -0
  273. package/dist/features/search/components/EntityTypeahead.js +92 -0
  274. package/dist/features/search/components/Search.d.ts +12 -1
  275. package/dist/features/search/components/Search.js +47 -3
  276. package/dist/features/search/components/SearchFacetRail.d.ts +11 -0
  277. package/dist/features/search/components/SearchFacetRail.js +92 -0
  278. package/dist/features/search/components/SearchResultsClient.d.ts +33 -0
  279. package/dist/features/search/components/SearchResultsClient.js +103 -0
  280. package/dist/features/search/components/SearchResultsPageView.d.ts +15 -1
  281. package/dist/features/search/components/SearchResultsPageView.js +2 -2
  282. package/dist/features/search/components/index.d.ts +0 -6
  283. package/dist/features/search/components/index.js +0 -3
  284. package/dist/features/search/hooks/useNavSuggestions.d.ts +13 -0
  285. package/dist/features/search/hooks/useScopedSearch.d.ts +34 -0
  286. package/dist/features/search/hooks/useScopedSearch.js +114 -0
  287. package/dist/features/search/hooks/useSiteSearch.d.ts +26 -0
  288. package/dist/features/search/hooks/useSiteSearch.js +149 -0
  289. package/dist/features/search/index.d.ts +0 -4
  290. package/dist/features/search/index.js +0 -4
  291. package/dist/features/search/manifest.d.ts +12 -0
  292. package/dist/features/search/manifest.js +17 -2
  293. package/dist/features/search/server.d.ts +0 -3
  294. package/dist/features/search/server.js +0 -3
  295. package/dist/features/seller/components/SellerListingTypeView.d.ts +1 -1
  296. package/dist/features/seller/components/SellerListingTypeView.js +20 -0
  297. package/dist/features/seller/components/SellerPayoutSettingsView.js +35 -14
  298. package/dist/features/seller/components/SellerProductShell.d.ts +1 -1
  299. package/dist/features/seller/components/SellerProductShell.js +2 -1
  300. package/dist/features/seller/components/SellerSidebar.js +1 -1
  301. package/dist/features/seller/components/SellerSparesView.d.ts +17 -0
  302. package/dist/features/seller/components/SellerSparesView.js +6 -0
  303. package/dist/features/seller/components/index.d.ts +2 -0
  304. package/dist/features/seller/components/index.js +1 -0
  305. package/dist/features/shell/CommandPalette.js +1 -1
  306. package/dist/features/sticker-trace/schemas/firestore.d.ts +19 -0
  307. package/dist/features/stores/components/StoreDetailLayoutView.d.ts +1 -1
  308. package/dist/features/stores/components/StoreDetailLayoutView.js +7 -82
  309. package/dist/features/stores/components/StoreHeader.js +1 -2
  310. package/dist/features/stores/components/StoreSparesPageView.d.ts +27 -0
  311. package/dist/features/stores/components/StoreSparesPageView.js +48 -0
  312. package/dist/features/stores/schemas/firestore.d.ts +19 -0
  313. package/dist/features/tester/seed-data/authored/buying__spares-and-groups.d.ts +2 -0
  314. package/dist/features/tester/seed-data/authored/buying__spares-and-groups.js +96 -0
  315. package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.d.ts +2 -0
  316. package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.js +280 -45
  317. package/dist/features/tester/seed-data/authored/content-discovery__category-tabs-franchise-bundles.js +54 -32
  318. package/dist/features/tester/seed-data/authored/content-discovery__parts-database.js +3 -2
  319. package/dist/features/tester/seed-data/authored/content-discovery__price-index-and-compare.d.ts +2 -0
  320. package/dist/features/tester/seed-data/authored/content-discovery__price-index-and-compare.js +73 -0
  321. package/dist/features/tester/seed-data/authored/content-discovery__site-wide-index.d.ts +2 -0
  322. package/dist/features/tester/seed-data/authored/content-discovery__site-wide-index.js +340 -0
  323. package/dist/features/tester/seed-data/authored/index.js +16 -0
  324. package/dist/features/tester/seed-data/authored/search-and-nav__header-search.d.ts +1 -0
  325. package/dist/features/tester/seed-data/authored/search-and-nav__header-search.js +57 -0
  326. package/dist/features/tester/seed-data/authored/selling__spares-and-group-editing.d.ts +2 -0
  327. package/dist/features/tester/seed-data/authored/selling__spares-and-group-editing.js +77 -0
  328. package/dist/features/tester/seed-data/authored/tools__sticker-promote-to-listings.d.ts +2 -0
  329. package/dist/features/tester/seed-data/authored/tools__sticker-promote-to-listings.js +58 -0
  330. package/dist/features/tester/seed-data/authored/tools__sticker-tracer.js +5 -4
  331. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +372 -18
  332. package/dist/index.d.ts +17 -57
  333. package/dist/index.js +35 -96
  334. package/dist/next/routing/route-map.d.ts +42 -1
  335. package/dist/next/routing/route-map.js +45 -0
  336. package/dist/providers/db-firebase/base.repository.d.ts +22 -0
  337. package/dist/providers/db-firebase/base.repository.js +36 -0
  338. package/dist/schemas/registry.d.ts +15 -6
  339. package/dist/security/blind-index-tokens.d.ts +54 -0
  340. package/dist/security/blind-index-tokens.js +152 -0
  341. package/dist/security/index.d.ts +1 -1
  342. package/dist/security/index.js +1 -1
  343. package/dist/security/settings-encryption.d.ts +35 -0
  344. package/dist/security/settings-encryption.js +91 -0
  345. package/dist/seed/_helpers/brand-rows.js +38 -14
  346. package/dist/seed/_helpers/category-forest.js +73 -7
  347. package/dist/seed/_helpers/category-images-generated.d.ts +25 -6
  348. package/dist/seed/_helpers/category-images-generated.js +81 -6
  349. package/dist/seed/_helpers/category-models.d.ts +1 -1
  350. package/dist/seed/_helpers/category-models.js +7 -1
  351. package/dist/seed/_helpers/category-parts-glossary-map.js +8 -0
  352. package/dist/seed/_helpers/category-parts.d.ts +1 -1
  353. package/dist/seed/_helpers/category-parts.js +50 -2
  354. package/dist/seed/_helpers/character-features.d.ts +1 -1
  355. package/dist/seed/_helpers/character-features.js +2 -1
  356. package/dist/seed/_helpers/franchise-rows.js +10 -2
  357. package/dist/seed/_helpers/media.d.ts +47 -0
  358. package/dist/seed/_helpers/media.js +34 -0
  359. package/dist/seed/authenticity-knowledge-seed-data.d.ts +49 -5
  360. package/dist/seed/authenticity-knowledge-seed-data.js +10001 -549
  361. package/dist/seed/categories-seed-data.js +124 -20
  362. package/dist/seed/grouped-listings-seed-data.js +16 -0
  363. package/dist/seed/homepage-sections-seed-data.js +94 -5
  364. package/dist/seed/index.d.ts +2 -3
  365. package/dist/seed/index.js +2 -2
  366. package/dist/seed/manifest.js +3 -0
  367. package/dist/seed/media-assets-seed-data.d.ts +1 -1
  368. package/dist/seed/media-assets-seed-data.js +746 -196
  369. package/dist/seed/model-composition-seed-data.js +122 -6
  370. package/dist/seed/part-glossary-seed-data.d.ts +1 -1
  371. package/dist/seed/part-glossary-seed-data.js +37219 -463
  372. package/dist/seed/products-art-seed-data.js +7 -18
  373. package/dist/seed/products-auctions-seed-data.js +56 -47
  374. package/dist/seed/products-beyblade-x-seed-data.d.ts +2 -0
  375. package/dist/seed/products-beyblade-x-seed-data.js +441 -0
  376. package/dist/seed/products-catalogue-seed-data.d.ts +5 -5
  377. package/dist/seed/products-catalogue-seed-data.js +1500 -1240
  378. package/dist/seed/products-classifieds-seed-data.js +9 -27
  379. package/dist/seed/products-digital-codes-seed-data.js +9 -18
  380. package/dist/seed/products-live-items-seed-data.js +5 -13
  381. package/dist/seed/products-preorders-seed-data.js +67 -33
  382. package/dist/seed/products-prize-draws-seed-data.js +8 -17
  383. package/dist/seed/products-spares-seed-data.d.ts +2 -0
  384. package/dist/seed/products-spares-seed-data.js +368 -0
  385. package/dist/seed/products-standard-seed-data.js +39 -126
  386. package/dist/seed/products-stickers-seed-data.js +59 -15
  387. package/dist/seed/site-settings-seed-data.js +8 -0
  388. package/dist/seo/json-ld.d.ts +25 -0
  389. package/dist/seo/json-ld.js +28 -0
  390. package/dist/server-entry.d.ts +3 -1
  391. package/dist/server-entry.js +2 -2
  392. package/dist/server.d.ts +9 -9
  393. package/dist/server.js +27 -25
  394. package/dist/styles.css +202 -1
  395. package/dist/tailwind-input.css +31 -17
  396. package/dist/tailwind-utilities.css +1 -1
  397. package/dist/ui/components/Accordion.js +1 -1
  398. package/dist/ui/components/Breadcrumb.js +1 -1
  399. package/dist/ui/components/DetailPageGallery.js +0 -2
  400. package/dist/ui/components/DetailPageHero.js +0 -1
  401. package/dist/ui/components/DetailPageTabs.js +1 -1
  402. package/dist/ui/components/Divider.js +3 -3
  403. package/dist/ui/components/GatedPrice.js +5 -1
  404. package/dist/ui/components/HorizontalScroller.js +1 -1
  405. package/dist/ui/components/ListingLayout.js +3 -3
  406. package/dist/ui/components/MediaTabs.style.css +81 -0
  407. package/dist/ui/components/Pagination.js +1 -1
  408. package/dist/ui/components/PendingValue.d.ts +45 -0
  409. package/dist/ui/components/PendingValue.js +7 -0
  410. package/dist/ui/components/Radio.style.css +119 -0
  411. package/dist/ui/components/RatingDisplay.js +2 -2
  412. package/dist/ui/components/SettingsSection.js +0 -2
  413. package/dist/ui/components/SiteLogo.js +3 -0
  414. package/dist/ui/components/SiteMark.js +3 -0
  415. package/dist/ui/components/SortDropdown.js +1 -1
  416. package/dist/ui/components/SpecTable.d.ts +58 -0
  417. package/dist/ui/components/SpecTable.js +8 -0
  418. package/dist/ui/components/StarRating.js +1 -3
  419. package/dist/ui/components/SummaryCard.js +1 -1
  420. package/dist/ui/components/index.style.css +1 -0
  421. package/dist/ui/icons/icon-registry.d.ts +1 -0
  422. package/dist/ui/icons/icon-registry.js +9 -1
  423. package/dist/ui/index.d.ts +4 -0
  424. package/dist/ui/index.js +2 -0
  425. package/dist/utils/search-txt-query.d.ts +12 -0
  426. package/dist/utils/search-txt-query.js +12 -0
  427. package/package.json +1 -1
  428. package/scripts/dedupe-peer-deps.mjs +18 -0
  429. package/scripts/seed-cli.mjs +135 -26
  430. package/scripts/verify-css-build.mjs +118 -37
  431. package/dist/_internal/server/features/search/actions.d.ts +0 -7
  432. package/dist/_internal/server/features/search/actions.js +0 -21
  433. package/dist/_internal/server/features/search/data.d.ts +0 -15
  434. package/dist/_internal/server/features/search/data.js +0 -18
  435. package/dist/_internal/server/features/search/index.d.ts +0 -3
  436. package/dist/_internal/server/features/search/index.js +0 -2
  437. package/dist/features/homepage/api/[id]/route.d.ts +0 -23
  438. package/dist/features/homepage/api/[id]/route.js +0 -103
  439. package/dist/features/homepage/api/route.d.ts +0 -14
  440. package/dist/features/homepage/api/route.js +0 -140
  441. package/dist/features/homepage/api/sections/[id]/route.d.ts +0 -26
  442. package/dist/features/homepage/api/sections/[id]/route.js +0 -95
  443. package/dist/features/homepage/api/sections/route.d.ts +0 -13
  444. package/dist/features/homepage/api/sections/route.js +0 -82
  445. package/dist/features/homepage/components/AdvertisementBanner.d.ts +0 -14
  446. package/dist/features/homepage/components/AdvertisementBanner.js +0 -35
  447. package/dist/features/homepage/components/BeforeAfterCard.d.ts +0 -9
  448. package/dist/features/homepage/components/BeforeAfterCard.js +0 -73
  449. package/dist/features/homepage/components/FeaturedResultsSection.d.ts +0 -17
  450. package/dist/features/homepage/components/FeaturedResultsSection.js +0 -17
  451. package/dist/features/homepage/components/HeroBanner.d.ts +0 -7
  452. package/dist/features/homepage/components/HeroBanner.js +0 -43
  453. package/dist/features/homepage/components/HeroSection.d.ts +0 -7
  454. package/dist/features/homepage/components/HeroSection.js +0 -6
  455. package/dist/features/homepage/components/HomepageSkeleton.d.ts +0 -2
  456. package/dist/features/homepage/components/HomepageSkeleton.js +0 -21
  457. package/dist/features/homepage/components/HomepageView.d.ts +0 -25
  458. package/dist/features/homepage/components/HomepageView.js +0 -5
  459. package/dist/features/homepage/components/NewsletterBanner.d.ts +0 -23
  460. package/dist/features/homepage/components/NewsletterBanner.js +0 -37
  461. package/dist/features/homepage/components/SiteFeaturesSection.d.ts +0 -14
  462. package/dist/features/homepage/components/SiteFeaturesSection.js +0 -11
  463. package/dist/features/homepage/components/TrustBadges.d.ts +0 -6
  464. package/dist/features/homepage/components/TrustBadges.js +0 -46
  465. package/dist/features/homepage/components/TrustIndicatorsSection.d.ts +0 -12
  466. package/dist/features/homepage/components/TrustIndicatorsSection.js +0 -11
  467. package/dist/features/homepage/hooks/useHomepage.d.ts +0 -11
  468. package/dist/features/homepage/hooks/useHomepage.js +0 -17
  469. package/dist/features/homepage/hooks/useHomepageSections.d.ts +0 -2
  470. package/dist/features/homepage/hooks/useHomepageSections.js +0 -10
  471. package/dist/features/homepage/repository/homepage.repository.d.ts +0 -11
  472. package/dist/features/homepage/repository/homepage.repository.js +0 -25
  473. package/dist/features/search/actions/index.d.ts +0 -1
  474. package/dist/features/search/actions/index.js +0 -1
  475. package/dist/features/search/actions/search-actions.d.ts +0 -18
  476. package/dist/features/search/actions/search-actions.js +0 -43
  477. package/dist/features/search/api/route.d.ts +0 -22
  478. package/dist/features/search/api/route.js +0 -128
  479. package/dist/features/search/columns/index.d.ts +0 -17
  480. package/dist/features/search/columns/index.js +0 -49
  481. package/dist/features/search/components/SearchFiltersRow.d.ts +0 -22
  482. package/dist/features/search/components/SearchFiltersRow.js +0 -21
  483. package/dist/features/search/components/SearchResultsSection.d.ts +0 -53
  484. package/dist/features/search/components/SearchResultsSection.js +0 -35
  485. package/dist/features/search/components/SearchView.d.ts +0 -27
  486. package/dist/features/search/components/SearchView.js +0 -8
  487. package/dist/features/search/hooks/useSearch.d.ts +0 -21
  488. package/dist/features/search/hooks/useSearch.js +0 -33
  489. package/dist/features/search/repository/search.repository.d.ts +0 -14
  490. package/dist/features/search/repository/search.repository.js +0 -59
  491. package/dist/features/search/schemas/index.d.ts +0 -70
  492. package/dist/features/search/schemas/index.js +0 -36
  493. package/dist/features/search/types/index.d.ts +0 -48
  494. package/dist/features/stores/components/StoreScopedSearch.d.ts +0 -17
  495. package/dist/features/stores/components/StoreScopedSearch.js +0 -27
  496. package/dist/seed/defaults/homepage-sections.d.ts +0 -2
  497. package/dist/seed/defaults/homepage-sections.js +0 -60
  498. package/dist/seed/factories/homepage-section.factory.d.ts +0 -10
  499. package/dist/seed/factories/homepage-section.factory.js +0 -13
  500. /package/dist/{features/search/types/index.js → _internal/shared/listing-types/spares/og.d.ts} +0 -0
@@ -7,7 +7,7 @@ import { DatabaseError } from "../../../errors/index.js";
7
7
  import { HOMEPAGE_SECTION_FIELDS } from "../../../constants/field-names.js";
8
8
  import { BaseRepository, prepareForFirestore, parseSieveDateValue, } from "../../../providers/db-firebase/index.js";
9
9
  import { normalizeError } from "../../../errors/normalize.js";
10
- import { HOMEPAGE_SECTIONS_COLLECTION, createHomepageSectionId, } from "../schemas/index.js";
10
+ import { DEFAULT_SECTION_SURFACE, HOMEPAGE_SECTIONS_COLLECTION, createHomepageSectionId, } from "../schemas/index.js";
11
11
  export class HomepageSectionsRepository extends BaseRepository {
12
12
  constructor() {
13
13
  super(HOMEPAGE_SECTIONS_COLLECTION);
@@ -16,7 +16,9 @@ export class HomepageSectionsRepository extends BaseRepository {
16
16
  return this.sieveQuery(model, HomepageSectionsRepository.SIEVE_FIELDS, { defaultPageSize: 50, maxPageSize: 200 });
17
17
  }
18
18
  async create(input) {
19
- const id = createHomepageSectionId(input.type);
19
+ // Surface participates in the id, or a category `products` section would
20
+ // overwrite the homepage's — same type, same slug, one document.
21
+ const id = createHomepageSectionId(input.type, input.surface);
20
22
  const sectionData = {
21
23
  ...input,
22
24
  createdAt: new Date(),
@@ -68,14 +70,36 @@ export class HomepageSectionsRepository extends BaseRepository {
68
70
  },
69
71
  });
70
72
  }
71
- async getEnabledSections() {
73
+ /**
74
+ * Enabled sections for one surface, in `order`.
75
+ *
76
+ * 🛑 The parameter DEFAULTS to `"homepage"`, and that default is the safety
77
+ * property, not a convenience. This method previously returned every enabled
78
+ * row regardless of surface — so the moment a category-surface row exists,
79
+ * an unfiltered homepage would render it. Defaulting here means the existing
80
+ * homepage call site is correct with no change at all, and a caller that
81
+ * wants another surface has to say so.
82
+ *
83
+ * 🛑 The surface is matched IN MEMORY, deliberately. The only composite index
84
+ * on this collection is `(enabled, order)`;
85
+ * `where(enabled).where(surface).orderBy(order)` is a three-field composite it
86
+ * does not cover, and Firestore throws FAILED_PRECONDITION at RUNTIME rather
87
+ * than at build time. `MarketplaceHomepageView` already filters sections in
88
+ * memory for the listing-type gate — this follows that precedent. Section
89
+ * counts are tens, so the read is unchanged in cost.
90
+ */
91
+ async getEnabledSections(surface = DEFAULT_SECTION_SURFACE) {
72
92
  try {
73
93
  const snapshot = await this.db
74
94
  .collection(this.collection)
75
95
  .where(HOMEPAGE_SECTION_FIELDS.ENABLED, "==", true)
76
96
  .orderBy(HOMEPAGE_SECTION_FIELDS.ORDER, "asc")
77
97
  .get();
78
- return snapshot.docs.map((doc) => this.mapDoc(doc));
98
+ return snapshot.docs
99
+ .map((doc) => this.mapDoc(doc))
100
+ // Absent means "homepage" — every row written before `surface` existed
101
+ // was a homepage row, so this keeps all 23 of them on the homepage.
102
+ .filter((row) => (row.surface ?? DEFAULT_SECTION_SURFACE) === surface);
79
103
  }
80
104
  catch (error) {
81
105
  void normalizeError(error);
@@ -96,17 +120,35 @@ export class HomepageSectionsRepository extends BaseRepository {
96
120
  throw new DatabaseError(`Failed to retrieve disabled sections: ${error instanceof Error ? error.message : "Unknown error"}`);
97
121
  }
98
122
  }
99
- async getSectionByType(type) {
123
+ /**
124
+ * 🛑 `surface` is NOT optional in spirit, even though it defaults.
125
+ *
126
+ * This was `where(type == X).limit(1)`, which assumed ONE document per type.
127
+ * With surfaces that assumption is false — a `products` section can exist on
128
+ * the homepage AND on a category page — and `limit(1)` would return whichever
129
+ * Firestore happened to order first. An arbitrary-but-plausible answer is the
130
+ * worst failure shape available here, because nothing errors.
131
+ *
132
+ * The surface is matched IN MEMORY rather than added as a second `where`: the
133
+ * only composite index on this collection is `(enabled, order)`, and
134
+ * `where(type).where(surface)` needs one that does not exist. Fetching the few
135
+ * rows of a type and picking by surface costs nothing at these counts.
136
+ */
137
+ async getSectionByType(type, surface = DEFAULT_SECTION_SURFACE) {
100
138
  try {
101
139
  const snapshot = await this.db
102
140
  .collection(this.collection)
103
141
  .where(HOMEPAGE_SECTION_FIELDS.TYPE, "==", type)
104
- .limit(1)
105
142
  .get();
106
143
  if (snapshot.empty)
107
144
  return null;
108
- const doc = snapshot.docs[0];
109
- return this.mapDoc(doc);
145
+ const match = snapshot.docs.find((d) => {
146
+ const rowSurface = d.data().surface ?? DEFAULT_SECTION_SURFACE;
147
+ return rowSurface === surface;
148
+ });
149
+ if (!match)
150
+ return null;
151
+ return this.mapDoc(match);
110
152
  }
111
153
  catch (error) {
112
154
  void normalizeError(error);
@@ -219,6 +261,14 @@ export class HomepageSectionsRepository extends BaseRepository {
219
261
  HomepageSectionsRepository.SIEVE_FIELDS = {
220
262
  type: { canFilter: true, canSort: false },
221
263
  enabled: { canFilter: true, canSort: false },
264
+ /*
265
+ * 🛑 Required, not optional polish. `sieve.ts` sets
266
+ * `throwExceptions: false`, so a field absent from this allowlist does not
267
+ * raise — `findField()` returns undefined and the clause is silently
268
+ * DROPPED. `?filters=surface==category` would then return every section on
269
+ * every surface while looking like it had filtered. Root Cause #62.
270
+ */
271
+ surface: { canFilter: true, canSort: false },
222
272
  order: { canFilter: true, canSort: true },
223
273
  createdAt: { canFilter: true, canSort: true, parseValue: parseSieveDateValue },
224
274
  updatedAt: { canFilter: true, canSort: true, parseValue: parseSieveDateValue },
@@ -671,22 +671,125 @@ export interface GoogleReviewsSectionConfig {
671
671
  linkToGoogleMaps?: boolean;
672
672
  googleMapsUrl?: string;
673
673
  }
674
- export type SectionType = "welcome" | "carousel" | "stats" | "trust-indicators" | "categories" | "brands" | "products" | "pre-orders" | "auctions" | "banner" | "features" | "reviews" | "whatsapp-community" | "faq" | "blog-articles" | "newsletter" | "stores" | "events" | "social-feed" | "custom-cards" | "google-reviews" | "featured-bundles" | "prize-draws" | "event-raffles" | "collection-cards";
674
+ /**
675
+ * Added 2026-10-19 promoting `HowItWorksSection` out of the orphan set — see
676
+ * `HowItWorksSection.tsx`'s own docstring for why `renderIcon`/`onCtaClick`
677
+ * (function props, not serialisable) became `iconKey`/`ctaLink`. `steps` is
678
+ * inline because the step count/order IS the authored content, same reasoning
679
+ * as `TestimonialsSectionConfig.testimonials` below.
680
+ */
681
+ export interface HowItWorksStepConfig {
682
+ number: number;
683
+ title: string;
684
+ desc: string;
685
+ iconKey?: string;
686
+ iconColor?: string;
687
+ iconBg?: string;
688
+ badgeBg?: string;
689
+ }
690
+ export interface HowItWorksSectionConfig {
691
+ title: string;
692
+ subtitle?: string;
693
+ pillLabel?: string;
694
+ ctaLabel?: string;
695
+ ctaLink?: string;
696
+ steps: HowItWorksStepConfig[];
697
+ }
698
+ /**
699
+ * Added 2026-10-19 promoting `TestimonialsCarousel` out of the orphan set.
700
+ * Deliberately NOT a read from the `testimonials` collection shape
701
+ * (`Testimonial` in `types/index.ts`) — `featured`/`sortOrder`/`active` are
702
+ * collection-row housekeeping with no meaning inside an already-ordered
703
+ * config array, and `avatarUrl` was declared there and never rendered. No
704
+ * `autoScroll`/`scrollInterval`/`loop` either: the component has no autoplay,
705
+ * arrows or dots — it is not actually a carousel, despite the name.
706
+ */
707
+ /** An embedded sub-document with its own `id` — a type alias, not a Firestore collection root, so it does not extend `BaseDocument`. */
708
+ export type TestimonialConfigEntry = {
709
+ id: string;
710
+ name: string;
711
+ rating: 1 | 2 | 3 | 4 | 5;
712
+ text: string;
713
+ };
714
+ export interface TestimonialsSectionConfig {
715
+ eyebrow?: string;
716
+ heading?: string;
717
+ testimonials: TestimonialConfigEntry[];
718
+ }
719
+ /**
720
+ * Added 2026-10-19 promoting `PromoGrid` out of the orphan set. `banners` is
721
+ * capped at `PROMO_GRID_MAX_BANNERS` (4) by the component itself — the
722
+ * layout has exactly one hero slot and three regular ones, so a 5th banner
723
+ * is silently dropped, not a bug. No admin background/colour field: the dark
724
+ * theme is intentionally hardcoded (Root Cause #67 — a themed background
725
+ * paired with fixed white ink would invert wrong in a light theme; this
726
+ * component is always dark, by design, so it never pairs the two).
727
+ */
728
+ /** An embedded sub-document with its own `id` — a type alias, not a Firestore collection root, so it does not extend `BaseDocument`. */
729
+ export type PromoBannerConfigEntry = {
730
+ id: string;
731
+ title: string;
732
+ ctaLabel: string;
733
+ ctaUrl: string;
734
+ image: string;
735
+ };
736
+ export interface PromoGridSectionConfig {
737
+ eyebrow?: string;
738
+ heading?: string;
739
+ banners: PromoBannerConfigEntry[];
740
+ }
741
+ export type SectionType = "welcome" | "carousel" | "stats" | "trust-indicators" | "categories" | "brands" | "products" | "pre-orders" | "auctions" | "banner" | "features" | "reviews" | "whatsapp-community" | "faq" | "blog-articles" | "newsletter" | "stores" | "events" | "social-feed" | "custom-cards" | "google-reviews" | "featured-bundles" | "prize-draws" | "event-raffles" | "collection-cards" | "how-it-works" | "testimonials" | "promo-grid";
675
742
  export type SectionConfig = CarouselSectionConfig | WelcomeSectionConfig | StatsSectionConfig | TrustIndicatorsSectionConfig | CategoriesSectionConfig | BrandsSectionConfig | ProductsSectionConfig | PreOrdersSectionConfig | AuctionsSectionConfig | BannerSectionConfig | FeaturesSectionConfig | ReviewsSectionConfig | WhatsAppCommunitySectionConfig | FAQSectionConfig | BlogArticlesSectionConfig | NewsletterSectionConfig | StoresSectionConfig | EventsSectionConfig | SocialFeedSectionConfig | CustomCardsSectionConfig | GoogleReviewsSectionConfig | FeaturedBundlesSectionConfig | PrizeDrawsSectionConfig | EventRafflesSectionConfig | CollectionCardsSectionConfig;
743
+ /**
744
+ * Which page a section row belongs to.
745
+ *
746
+ * One collection, one owner per surface. This does NOT reintroduce the
747
+ * `siteSettings.homepageLayout` that `sectionTemplates.ts` deliberately refuses
748
+ * — that note forbids a SECOND owner of the homepage's layout, and this keeps
749
+ * `homepageSections` the single source of truth while letting a category or a
750
+ * brand page own its own ordered list.
751
+ */
752
+ export declare const SECTION_SURFACE_VALUES: readonly ["homepage", "category", "brand", "product", "store"];
753
+ export type SectionSurface = (typeof SECTION_SURFACE_VALUES)[number];
754
+ /** Absent means `"homepage"`. See the field comment below. */
755
+ export declare const DEFAULT_SECTION_SURFACE: SectionSurface;
676
756
  export interface HomepageSectionDocument extends BaseDocument {
677
757
  type: SectionType;
678
758
  order: number;
679
759
  enabled: boolean;
680
760
  config: SectionConfig;
761
+ /**
762
+ * 🛑 OPTIONAL, and that is load-bearing. Every other field on this document
763
+ * is required, so a non-optional `surface` would make every one of the 23
764
+ * existing rows fail the type on read. Absent therefore means
765
+ * `DEFAULT_SECTION_SURFACE` — which is also the honest reading of history,
766
+ * since every row written before this existed was a homepage row.
767
+ *
768
+ * 🛑 Filter it IN MEMORY, never as a Firestore clause. The only composite
769
+ * index on this collection is `(enabled, order)`;
770
+ * `where(enabled).where(surface).orderBy(order)` is a three-field composite
771
+ * it does not cover and Firestore throws FAILED_PRECONDITION at RUNTIME, not
772
+ * at build time. `MarketplaceHomepageView` already filters sections in memory
773
+ * for the listing-type gate — follow that precedent. Section counts are tens.
774
+ */
775
+ surface?: SectionSurface;
681
776
  }
682
777
  export declare const HOMEPAGE_SECTIONS_COLLECTION: "homepageSections";
683
778
  export declare const HOMEPAGE_SECTIONS_INDEXED_FIELDS: readonly ["enabled", "order", "type"];
684
779
  export declare const DEFAULT_SECTION_ORDER: Record<SectionType, number>;
685
780
  export declare const BANNER_HEIGHTS: Record<BannerSectionConfig["height"], string>;
686
781
  export type HomepageSectionCreateInput = Omit<HomepageSectionDocument, "id" | "createdAt" | "updatedAt">;
687
- export type HomepageSectionUpdateInput = Partial<Pick<HomepageSectionDocument, "order" | "enabled" | "config">>;
782
+ export type HomepageSectionUpdateInput = Partial<Pick<HomepageSectionDocument, "order" | "enabled" | "config" | "surface">>;
688
783
  export declare const homepageSectionQueryHelpers: {
689
784
  readonly enabled: () => readonly ["enabled", "==", true];
690
785
  readonly byType: (type: SectionType) => readonly ["type", "==", SectionType];
691
786
  };
692
- export declare function createHomepageSectionId(type: SectionType): string;
787
+ /**
788
+ * 🛑 The surface is part of the id, or a category's `products` section collides
789
+ * with the homepage's — same type, same generated slug, one document.
790
+ *
791
+ * `"homepage"` is omitted from the id so every existing row keeps the exact id
792
+ * it already has. A migration here would be a rename of 23 live documents to
793
+ * gain nothing.
794
+ */
795
+ export declare function createHomepageSectionId(type: SectionType, surface?: SectionSurface): string;
@@ -67,6 +67,24 @@ export const ALLOWED_LIVE_COLLECTIONS = [
67
67
  "bids",
68
68
  ];
69
69
  export const COLLECTION_CARDS_MAX_ENTRIES = 3;
70
+ /**
71
+ * Which page a section row belongs to.
72
+ *
73
+ * One collection, one owner per surface. This does NOT reintroduce the
74
+ * `siteSettings.homepageLayout` that `sectionTemplates.ts` deliberately refuses
75
+ * — that note forbids a SECOND owner of the homepage's layout, and this keeps
76
+ * `homepageSections` the single source of truth while letting a category or a
77
+ * brand page own its own ordered list.
78
+ */
79
+ export const SECTION_SURFACE_VALUES = [
80
+ "homepage",
81
+ "category",
82
+ "brand",
83
+ "product",
84
+ "store",
85
+ ];
86
+ /** Absent means `"homepage"`. See the field comment below. */
87
+ export const DEFAULT_SECTION_SURFACE = "homepage";
70
88
  export const HOMEPAGE_SECTIONS_COLLECTION = "homepageSections";
71
89
  export const HOMEPAGE_SECTIONS_INDEXED_FIELDS = [
72
90
  "enabled",
@@ -99,6 +117,9 @@ export const DEFAULT_SECTION_ORDER = {
99
117
  "prize-draws": 21,
100
118
  "event-raffles": 22,
101
119
  "collection-cards": 23,
120
+ "how-it-works": 24,
121
+ testimonials: 25,
122
+ "promo-grid": 26,
102
123
  };
103
124
  export const BANNER_HEIGHTS = {
104
125
  sm: "200px",
@@ -110,6 +131,15 @@ export const homepageSectionQueryHelpers = {
110
131
  enabled: () => ["enabled", "==", true],
111
132
  byType: (type) => ["type", "==", type],
112
133
  };
113
- export function createHomepageSectionId(type) {
114
- return generateHomepageSectionId({ type });
134
+ /**
135
+ * 🛑 The surface is part of the id, or a category's `products` section collides
136
+ * with the homepage's — same type, same generated slug, one document.
137
+ *
138
+ * `"homepage"` is omitted from the id so every existing row keeps the exact id
139
+ * it already has. A migration here would be a rename of 23 live documents to
140
+ * gain nothing.
141
+ */
142
+ export function createHomepageSectionId(type, surface = DEFAULT_SECTION_SURFACE) {
143
+ const base = generateHomepageSectionId({ type });
144
+ return surface === DEFAULT_SECTION_SURFACE ? base : `${base}-${surface}`;
115
145
  }
@@ -1,7 +1,32 @@
1
1
  export * from "./firestore";
2
2
  import { z } from "zod";
3
+ import type { SectionType } from "./firestore";
3
4
  import type { JsonValue } from "../../../schemas/types";
4
- export declare const homepageSectionTypeSchema: z.ZodEnum<["welcome", "carousel", "stats", "trust-indicators", "categories", "brands", "products", "pre-orders", "auctions", "banner", "features", "reviews", "whatsapp-community", "faq", "blog-articles", "newsletter", "stores", "events", "social-feed", "custom-cards", "google-reviews", "featured-bundles", "prize-draws", "event-raffles", "collection-cards"]>;
5
+ /**
6
+ * 🛑 GENUINELY derived from `SectionType`, not a parallel hand-written list.
7
+ *
8
+ * This used to be a literal `z.enum([...25 strings...])`, with a docstring one
9
+ * screen up claiming it was "derived from the union, so that gap cannot
10
+ * reopen." It was not derived — it was a hand-typed duplicate that happened to
11
+ * agree with `SectionType` on the day it was written, with nothing enforcing
12
+ * that agreement afterward. Adding a 26th section type without also editing
13
+ * this array would 400 every save of the new type — exactly the failure the
14
+ * docstring claimed was already closed.
15
+ *
16
+ * `DEFAULT_SECTION_ORDER: Record<SectionType, number>` (`./firestore.ts`) is
17
+ * already compile-checked exhaustive over `SectionType` — TypeScript refuses
18
+ * to compile it if a union member is missing a key, or if an extra key exists
19
+ * that isn't in the union. So `Object.keys(DEFAULT_SECTION_ORDER)` IS the
20
+ * `SectionType` value set, genuinely, every time this file is built — adding
21
+ * a type to the union without updating `DEFAULT_SECTION_ORDER` is now a `tsc`
22
+ * error at THAT assignment, not a runtime 400 discovered on save.
23
+ *
24
+ * The cast is sound, not a loosening: `Object.keys` returns `string[]` only
25
+ * because that's TypeScript's (overly conservative) built-in signature for
26
+ * it — the compile-time guarantee from `DEFAULT_SECTION_ORDER`'s own type
27
+ * is what actually makes the runtime values correct.
28
+ */
29
+ export declare const homepageSectionTypeSchema: z.ZodEnum<[SectionType, ...SectionType[]]>;
5
30
  export declare const homepageSectionFirestoreSchema: z.ZodObject<{
6
31
  createdAt: z.ZodUnion<[z.ZodDate, z.ZodString, z.ZodObject<{
7
32
  toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
@@ -18,12 +43,12 @@ export declare const homepageSectionFirestoreSchema: z.ZodObject<{
18
43
  toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
19
44
  }, z.ZodTypeAny, "passthrough">>]>;
20
45
  id: z.ZodString;
21
- type: z.ZodEnum<["welcome", "carousel", "stats", "trust-indicators", "categories", "brands", "products", "pre-orders", "auctions", "banner", "features", "reviews", "whatsapp-community", "faq", "blog-articles", "newsletter", "stores", "events", "social-feed", "custom-cards", "google-reviews", "featured-bundles", "prize-draws", "event-raffles", "collection-cards"]>;
46
+ type: z.ZodEnum<[SectionType, ...SectionType[]]>;
22
47
  order: z.ZodNumber;
23
48
  enabled: z.ZodBoolean;
24
49
  config: z.ZodRecord<z.ZodString, z.ZodType<JsonValue, z.ZodTypeDef, JsonValue>>;
25
50
  }, "strip", z.ZodTypeAny, {
26
- type: "banner" | "stores" | "products" | "pre-orders" | "prize-draws" | "auctions" | "reviews" | "events" | "categories" | "brands" | "carousel" | "newsletter" | "features" | "stats" | "welcome" | "trust-indicators" | "whatsapp-community" | "faq" | "blog-articles" | "social-feed" | "custom-cards" | "google-reviews" | "featured-bundles" | "event-raffles" | "collection-cards";
51
+ type: SectionType;
27
52
  id: string;
28
53
  createdAt: string | Date | z.objectOutputType<{
29
54
  toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
@@ -35,7 +60,7 @@ export declare const homepageSectionFirestoreSchema: z.ZodObject<{
35
60
  order: number;
36
61
  config: Record<string, JsonValue>;
37
62
  }, {
38
- type: "banner" | "stores" | "products" | "pre-orders" | "prize-draws" | "auctions" | "reviews" | "events" | "categories" | "brands" | "carousel" | "newsletter" | "features" | "stats" | "welcome" | "trust-indicators" | "whatsapp-community" | "faq" | "blog-articles" | "social-feed" | "custom-cards" | "google-reviews" | "featured-bundles" | "event-raffles" | "collection-cards";
63
+ type: SectionType;
39
64
  id: string;
40
65
  createdAt: string | Date | z.objectInputType<{
41
66
  toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
@@ -61,19 +86,23 @@ export declare const homepageSectionFirestoreSchema: z.ZodObject<{
61
86
  * `type` comes from `homepageSectionTypeSchema`, which is derived from the
62
87
  * union, so that gap cannot reopen.
63
88
  */
89
+ export declare const sectionSurfaceSchema: z.ZodEnum<["homepage", "category", "brand", "product", "store"]>;
64
90
  export declare const homepageSectionCreateSchema: z.ZodObject<{
65
- type: z.ZodEnum<["welcome", "carousel", "stats", "trust-indicators", "categories", "brands", "products", "pre-orders", "auctions", "banner", "features", "reviews", "whatsapp-community", "faq", "blog-articles", "newsletter", "stores", "events", "social-feed", "custom-cards", "google-reviews", "featured-bundles", "prize-draws", "event-raffles", "collection-cards"]>;
91
+ type: z.ZodEnum<[SectionType, ...SectionType[]]>;
66
92
  enabled: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
67
93
  order: z.ZodOptional<z.ZodNumber>;
94
+ surface: z.ZodOptional<z.ZodEnum<["homepage", "category", "brand", "product", "store"]>>;
68
95
  config: z.ZodRecord<z.ZodString, z.ZodType<JsonValue, z.ZodTypeDef, JsonValue>>;
69
96
  }, "strip", z.ZodTypeAny, {
70
- type: "banner" | "stores" | "products" | "pre-orders" | "prize-draws" | "auctions" | "reviews" | "events" | "categories" | "brands" | "carousel" | "newsletter" | "features" | "stats" | "welcome" | "trust-indicators" | "whatsapp-community" | "faq" | "blog-articles" | "social-feed" | "custom-cards" | "google-reviews" | "featured-bundles" | "event-raffles" | "collection-cards";
97
+ type: SectionType;
71
98
  enabled: boolean;
72
99
  config: Record<string, JsonValue>;
100
+ surface?: "brand" | "category" | "store" | "product" | "homepage" | undefined;
73
101
  order?: number | undefined;
74
102
  }, {
75
- type: "banner" | "stores" | "products" | "pre-orders" | "prize-draws" | "auctions" | "reviews" | "events" | "categories" | "brands" | "carousel" | "newsletter" | "features" | "stats" | "welcome" | "trust-indicators" | "whatsapp-community" | "faq" | "blog-articles" | "social-feed" | "custom-cards" | "google-reviews" | "featured-bundles" | "event-raffles" | "collection-cards";
103
+ type: SectionType;
76
104
  config: Record<string, JsonValue>;
105
+ surface?: "brand" | "category" | "store" | "product" | "homepage" | undefined;
77
106
  enabled?: boolean | undefined;
78
107
  order?: number | undefined;
79
108
  }>;
@@ -10,34 +10,33 @@ export * from "./firestore.js";
10
10
  // Here the `config` field is treated as a typed `Record<string, JsonValue>` —
11
11
  // the section-builder schemas validate it at the form boundary.
12
12
  import { z } from "zod";
13
+ import { DEFAULT_SECTION_ORDER, SECTION_SURFACE_VALUES } from "./firestore.js";
13
14
  import { auditTimestampsShape, firestoreDateSchema } from "../../../schemas/firestore-helpers.js";
14
- export const homepageSectionTypeSchema = z.enum([
15
- "welcome",
16
- "carousel",
17
- "stats",
18
- "trust-indicators",
19
- "categories",
20
- "brands",
21
- "products",
22
- "pre-orders",
23
- "auctions",
24
- "banner",
25
- "features",
26
- "reviews",
27
- "whatsapp-community",
28
- "faq",
29
- "blog-articles",
30
- "newsletter",
31
- "stores",
32
- "events",
33
- "social-feed",
34
- "custom-cards",
35
- "google-reviews",
36
- "featured-bundles",
37
- "prize-draws",
38
- "event-raffles",
39
- "collection-cards",
40
- ]);
15
+ /**
16
+ * 🛑 GENUINELY derived from `SectionType`, not a parallel hand-written list.
17
+ *
18
+ * This used to be a literal `z.enum([...25 strings...])`, with a docstring one
19
+ * screen up claiming it was "derived from the union, so that gap cannot
20
+ * reopen." It was not derived — it was a hand-typed duplicate that happened to
21
+ * agree with `SectionType` on the day it was written, with nothing enforcing
22
+ * that agreement afterward. Adding a 26th section type without also editing
23
+ * this array would 400 every save of the new type — exactly the failure the
24
+ * docstring claimed was already closed.
25
+ *
26
+ * `DEFAULT_SECTION_ORDER: Record<SectionType, number>` (`./firestore.ts`) is
27
+ * already compile-checked exhaustive over `SectionType` — TypeScript refuses
28
+ * to compile it if a union member is missing a key, or if an extra key exists
29
+ * that isn't in the union. So `Object.keys(DEFAULT_SECTION_ORDER)` IS the
30
+ * `SectionType` value set, genuinely, every time this file is built — adding
31
+ * a type to the union without updating `DEFAULT_SECTION_ORDER` is now a `tsc`
32
+ * error at THAT assignment, not a runtime 400 discovered on save.
33
+ *
34
+ * The cast is sound, not a loosening: `Object.keys` returns `string[]` only
35
+ * because that's TypeScript's (overly conservative) built-in signature for
36
+ * it — the compile-time guarantee from `DEFAULT_SECTION_ORDER`'s own type
37
+ * is what actually makes the runtime values correct.
38
+ */
39
+ export const homepageSectionTypeSchema = z.enum(Object.keys(DEFAULT_SECTION_ORDER));
41
40
  // JsonValue Zod — used for section configs whose shape varies per section type.
42
41
  // The section-builder schemas (W5 row 1) provide the per-type validation.
43
42
  const jsonValueSchema = z.lazy(() => z.union([
@@ -70,10 +69,23 @@ export const homepageSectionFirestoreSchema = z.object({
70
69
  * `type` comes from `homepageSectionTypeSchema`, which is derived from the
71
70
  * union, so that gap cannot reopen.
72
71
  */
72
+ /*
73
+ * 🛑 Derived from SECTION_SURFACE_VALUES, not restated as a literal list —
74
+ * same discipline `homepageSectionTypeSchema` above now follows too (fixed
75
+ * 2026-10-19; it used to be the hand-written duplicate this comment used to
76
+ * warn about, with nothing enforcing parity with `SectionType`).
77
+ */
78
+ export const sectionSurfaceSchema = z.enum(SECTION_SURFACE_VALUES);
73
79
  export const homepageSectionCreateSchema = z.object({
74
80
  type: homepageSectionTypeSchema,
75
81
  enabled: z.boolean().optional().default(true),
76
82
  order: z.number().int().optional(),
83
+ /*
84
+ * A plain `z.object()` STRIPS unknown keys silently, so without this line a
85
+ * caller's `surface` vanishes between the request and the handler with no
86
+ * error anywhere — Root Cause #76. Absent still means "homepage".
87
+ */
88
+ surface: sectionSurfaceSchema.optional(),
77
89
  // Deliberately open. Every section type carries a different config shape,
78
90
  // and a closed schema here would silently STRIP the builder's output for any
79
91
  // type it did not enumerate — the `productBaseSchema` failure, one domain
@@ -1,9 +1,6 @@
1
1
  export * from "./actions";
2
- export { HomepageSectionsRepository } from "./repository/homepage.repository";
3
2
  export { carouselRepository } from "./repository/carousel.repository";
4
3
  export { homepageSectionsRepository } from "./repository/homepage-sections.repository";
5
4
  export { manifest } from "./manifest";
6
- export { GET as homepageGET, GET, POST } from "./api/route";
7
- export { homepageSectionItemGET, homepageSectionItemPATCH, homepageSectionItemDELETE, } from "./api/[id]/route";
8
5
  export { carouselGET, carouselPOST } from "./api/carousel/route";
9
6
  export { carouselItemGET, carouselItemPATCH, carouselItemDELETE, } from "./api/carousel/[id]/route";
@@ -1,9 +1,6 @@
1
1
  export * from "./actions/index.js";
2
- export { HomepageSectionsRepository } from "./repository/homepage.repository.js";
3
2
  export { carouselRepository } from "./repository/carousel.repository.js";
4
3
  export { homepageSectionsRepository } from "./repository/homepage-sections.repository.js";
5
4
  export { manifest } from "./manifest.js";
6
- export { GET as homepageGET, GET, POST } from "./api/route.js";
7
- export { homepageSectionItemGET, homepageSectionItemPATCH, homepageSectionItemDELETE, } from "./api/[id]/route.js";
8
5
  export { carouselGET, carouselPOST } from "./api/carousel/route.js";
9
6
  export { carouselItemGET, carouselItemPATCH, carouselItemDELETE, } from "./api/carousel/[id]/route.js";
@@ -1,31 +1,3 @@
1
- export type HomepageSectionType = "hero" | "featured_categories" | "featured_products" | "banner" | "testimonials" | "promotions" | "blog_posts" | "sellers" | "custom";
2
- export interface HomepageSectionContent {
3
- title?: string;
4
- subtitle?: string;
5
- ctaLabel?: string;
6
- ctaUrl?: string;
7
- imageUrl?: string;
8
- videoUrl?: string;
9
- itemIds?: string[];
10
- html?: string;
11
- }
12
- export interface HomepageSection {
13
- id: string;
14
- type: HomepageSectionType;
15
- title?: string;
16
- /** Primary enable/disable flag stored in Firestore as `enabled` */
17
- enabled?: boolean;
18
- /** Alias kept for older consumers */
19
- isVisible?: boolean;
20
- order?: number;
21
- content?: HomepageSectionContent;
22
- mobile?: Partial<HomepageSectionContent>;
23
- createdAt?: string;
24
- updatedAt?: string;
25
- }
26
- export interface HomepageData {
27
- sections: HomepageSection[];
28
- }
29
1
  export interface HotspotPin {
30
2
  id: string;
31
3
  name: string;
@@ -62,15 +34,6 @@ export interface Banner {
62
34
  sortOrder: number;
63
35
  active: boolean;
64
36
  }
65
- export interface PromoBanner {
66
- id: string;
67
- title: string;
68
- ctaLabel: string;
69
- ctaUrl: string;
70
- image: string;
71
- sortOrder: number;
72
- active: boolean;
73
- }
74
37
  export type TrustBadgeIconKey = "shipping" | "support" | "rewards" | "secure";
75
38
  export interface TrustBadge {
76
39
  id: string;
@@ -80,16 +43,6 @@ export interface TrustBadge {
80
43
  sortOrder: number;
81
44
  active: boolean;
82
45
  }
83
- export interface Testimonial {
84
- id: string;
85
- name: string;
86
- rating: 1 | 2 | 3 | 4 | 5;
87
- text: string;
88
- avatarUrl?: string;
89
- featured: boolean;
90
- sortOrder: number;
91
- active: boolean;
92
- }
93
46
  export interface BeforeAfterItem {
94
47
  id: string;
95
48
  beforeImage: string;
@@ -1 +1,50 @@
1
+ /*
2
+ * 🛑 DELETED 2026-10-19 — a second, incompatible section vocabulary, attached
3
+ * to LIVE, MOUNTED, publicly-reachable code.
4
+ *
5
+ * This file declared `HomepageSectionType` (9 values: `hero`,
6
+ * `featured_categories`, `featured_products`, `banner`, `testimonials`,
7
+ * `promotions`, `blog_posts`, `sellers`, `custom`), `HomepageSectionContent`,
8
+ * `HomepageSection` and `HomepageData`, against the live `SectionType` in
9
+ * `../schemas/firestore.ts`, which holds 25 values sharing exactly ONE
10
+ * (`banner`) with this union. A second, independently-declared copy of the
11
+ * same 9-value union lived in `seed/factories/homepage-section.factory.ts`
12
+ * too — THREE incompatible section vocabularies in one codebase, none of them
13
+ * the one the real renderer and repository use.
14
+ *
15
+ * This was not dead code sitting unused — `GET /api/homepage-sections` and
16
+ * `GET/POST /api/homepage-sections/[id]` were REAL, MOUNTED routes (stubs
17
+ * literally headed "feat-homepage — Pure stub", from a generic starter kit
18
+ * never adapted to this project) reading/writing the SAME `homepageSections`
19
+ * Firestore collection the real system owns, through a SECOND,
20
+ * identically-named `HomepageSectionsRepository` class (a generic
21
+ * `IRepository<HomepageSection>` wrapper in `repository/homepage.repository.ts`,
22
+ * distinct from the real `BaseRepository`-backed one in
23
+ * `homepage-sections.repository.ts`) — Root Cause #36's two-same-named-types
24
+ * defect, on a REPOSITORY CLASS this time, with a live route behind it.
25
+ *
26
+ * Concretely, before this deletion: the stub's GET filtered on `isVisible==true`,
27
+ * a field that does not exist on a real `HomepageSectionDocument` (the real
28
+ * field is `enabled`), so unauthenticated requests always got `[]`; its POST
29
+ * (admin-gated) would have written a document shaped `{ type: "hero", title,
30
+ * content: {...} }` into the collection the real renderer reads, where
31
+ * `SECTION_REGISTRY[section.type]` — see `../lib/section-renderer.tsx` — would
32
+ * resolve to `undefined` and render nothing, with no error anywhere: a
33
+ * corrupted, uneditable-through-the-real-admin-UI row, silently invisible.
34
+ *
35
+ * `useHomepage()` (the hook typed against `HomepageData`) fetched
36
+ * `HOMEPAGE_ENDPOINTS.GET = "/api/homepage"`, which was never mounted at all.
37
+ * `useHomepageSections()` called the stub above and had zero real callers —
38
+ * only a comment in `AdminSectionsView.tsx` mentioning it existed.
39
+ *
40
+ * All of it is deleted: the two hooks, the stub API routes (`api/route.ts`,
41
+ * `api/[id]/`, and a THIRD unused parallel stub at `api/sections/` for
42
+ * `/api/homepage/sections`), the stub repository class, `HeroSection.tsx`
43
+ * (zero real consumers), the seed factory, and the matching consumer-side
44
+ * `src/app/api/homepage-sections/{route.ts,[id]/route.ts}`.
45
+ *
46
+ * The live contract is `SectionType` / `SectionConfig` / `HomepageSectionDocument`
47
+ * in `../schemas/firestore.ts`, served by `GET /api/admin/sections` and read
48
+ * directly by `MarketplaceHomepageView` via `homepageSectionsRepository`.
49
+ */
1
50
  export {};
@@ -176,7 +176,7 @@ function SidebarContent({ sidebarItems, sidebarSections, sidebarPrimaryActions,
176
176
  action.variant === "outline"
177
177
  ? "border hover:bg-surface-hover border-[var(--appkit-color-border)] text-[var(--appkit-color-text)]"
178
178
  : "bg-primary text-white hover:bg-primary-600 dark:bg-primary dark:hover:bg-primary-600 btn-glow",
179
- ].join(" "), children: action.label }, `${action.href}-${action.label}`))) })), isAuthenticated && (_jsx(CollapsibleNavGroup, { title: labels.sectionTitle, hasActive: !!activeProfileLink, children: _jsxs(Ul, { spacing: "2xs", children: [_jsx(Li, { children: _jsx(TextLink, { href: profileHref, variant: "none", className: activeProfileLink?.href === profileHref ? navItemActiveClass : navItemClass, "aria-current": activeProfileLink?.href === profileHref ? "page" : undefined, children: labels.profile }) }), userOrdersHref && (_jsx(Li, { children: _jsx(TextLink, { href: userOrdersHref, variant: "none", className: activeProfileLink?.href === userOrdersHref ? navItemActiveClass : navItemClass, "aria-current": activeProfileLink?.href === userOrdersHref ? "page" : undefined, children: labels.orders }) })), userWishlistHref && (_jsx(Li, { children: _jsx(TextLink, { href: userWishlistHref, variant: "none", className: activeProfileLink?.href === userWishlistHref ? navItemActiveClass : navItemClass, "aria-current": activeProfileLink?.href === userWishlistHref ? "page" : undefined, children: labels.wishlist }) })), userSettingsHref && (_jsx(Li, { children: _jsx(TextLink, { href: userSettingsHref, variant: "none", className: activeProfileLink?.href === userSettingsHref ? navItemActiveClass : navItemClass, "aria-current": activeProfileLink?.href === userSettingsHref ? "page" : undefined, children: labels.settings }) }))] }) })), isAuthenticated && user?.stats && (_jsxs(Div, { layout: "grid", gap: "2", className: "grid-cols-2", children: [user.stats.totalOrders != null && (_jsxs(Div, { className: CLS_STAT_BOX, children: [_jsx(Text, { className: "leading-none", color: "primary", size: "lg", weight: "bold", children: user.stats.totalOrders }), _jsx(Text, { className: CLS_STAT_LABEL, children: "Orders" })] })), user.stats.reviewsCount != null && (_jsxs(Div, { className: CLS_STAT_BOX, children: [_jsx(Text, { className: "leading-none", color: "primary", size: "lg", weight: "bold", children: user.stats.reviewsCount }), _jsx(Text, { className: CLS_STAT_LABEL, children: "Reviews" })] })), user.stats.auctionsWon != null && (_jsxs(Div, { className: CLS_STAT_BOX, children: [_jsx(Text, { className: "leading-none", color: "primary", size: "lg", weight: "bold", children: user.stats.auctionsWon }), _jsx(Text, { className: CLS_STAT_LABEL, children: "Auctions Won" })] })), user.stats.itemsSold != null && (_jsxs(Div, { className: CLS_STAT_BOX, children: [_jsx(Text, { className: "leading-none", color: "primary", size: "lg", weight: "bold", children: user.stats.itemsSold }), _jsx(Text, { className: CLS_STAT_LABEL, children: "Items Sold" })] }))] })), isAuthenticated && isAdminOrSeller && (adminHref || resolvedStoreHref) && (_jsx(CollapsibleNavGroup, { title: labels.dashboardSectionTitle, hasActive: !!activeDashboardLink, children: _jsxs(Ul, { spacing: "2xs", children: [adminHref && role === "admin" && (_jsx(Li, { children: _jsx(TextLink, { href: adminHref, variant: "none", className: activeDashboardLink?.href === adminHref ? navItemActiveClass : navItemClass, "aria-current": activeDashboardLink?.href === adminHref ? "page" : undefined, children: labels.adminDashboard }) })), resolvedStoreHref && isAdminOrSeller && (_jsx(Li, { children: _jsx(TextLink, { href: resolvedStoreHref, variant: "none", className: activeDashboardLink?.href === resolvedStoreHref ? navItemActiveClass : navItemClass, "aria-current": activeDashboardLink?.href === resolvedStoreHref ? "page" : undefined, children: labels.storeDashboard }) }))] }) })), normalizedSections.map((section, sectionIndex) => (_jsx(CollapsibleSidebarSection, { section: section, navItemClass: navItemClass, navItemActiveClass: navItemActiveClass, activeHref: activeHref }, `sidebar-section-${sectionIndex}`))), (sidebarLocaleSlot || showThemeToggleInSidebar || (isAuthenticated && onLogout)) && (_jsxs(Stack, { border: "default", className: "border-t border-[var(--appkit-color-border-subtle)]", padding: "t-md", gap: "3", children: [sidebarLocaleSlot, showThemeToggleInSidebar && (_jsxs("button", { type: "button", onClick: toggleTheme, className: "flex w-full items-center justify-end gap-[var(--appkit-space-3)] rounded-lg px-[var(--appkit-space-3)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] text-[var(--appkit-color-text-muted)] transition-colors hover:bg-primary-surface hover:text-primary-800", children: [_jsx(Span, { "aria-hidden": "true", children: theme === "dark" ? "☀️" : "🌙" }), activeThemeName] })), isAuthenticated && onLogout && (_jsx("button", { type: "button", onClick: () => { onLogout(); onAfterLogout(); }, className: CLS_LOGOUT_BTN, children: labels.logout }))] }))] }));
179
+ ].join(" "), children: action.label }, `${action.href}-${action.label}`))) })), isAuthenticated && (_jsx(CollapsibleNavGroup, { title: labels.sectionTitle, hasActive: !!activeProfileLink, children: _jsxs(Ul, { spacing: "2xs", children: [_jsx(Li, { children: _jsx(TextLink, { href: profileHref, variant: "none", className: activeProfileLink?.href === profileHref ? navItemActiveClass : navItemClass, "aria-current": activeProfileLink?.href === profileHref ? "page" : undefined, children: labels.profile }) }), userOrdersHref && (_jsx(Li, { children: _jsx(TextLink, { href: userOrdersHref, variant: "none", className: activeProfileLink?.href === userOrdersHref ? navItemActiveClass : navItemClass, "aria-current": activeProfileLink?.href === userOrdersHref ? "page" : undefined, children: labels.orders }) })), userWishlistHref && (_jsx(Li, { children: _jsx(TextLink, { href: userWishlistHref, variant: "none", className: activeProfileLink?.href === userWishlistHref ? navItemActiveClass : navItemClass, "aria-current": activeProfileLink?.href === userWishlistHref ? "page" : undefined, children: labels.wishlist }) })), userSettingsHref && (_jsx(Li, { children: _jsx(TextLink, { href: userSettingsHref, variant: "none", className: activeProfileLink?.href === userSettingsHref ? navItemActiveClass : navItemClass, "aria-current": activeProfileLink?.href === userSettingsHref ? "page" : undefined, children: labels.settings }) }))] }) })), isAuthenticated && user?.stats && (_jsxs(Div, { layout: "grid", gap: "2", className: "grid-cols-2", children: [user.stats.totalOrders != null && (_jsxs(Div, { className: CLS_STAT_BOX, children: [_jsx(Text, { className: "leading-none", color: "primary", size: "lg", weight: "bold", children: user.stats.totalOrders }), _jsx(Text, { className: CLS_STAT_LABEL, children: "Orders" })] })), user.stats.reviewsCount != null && (_jsxs(Div, { className: CLS_STAT_BOX, children: [_jsx(Text, { className: "leading-none", color: "primary", size: "lg", weight: "bold", children: user.stats.reviewsCount }), _jsx(Text, { className: CLS_STAT_LABEL, children: "Reviews" })] })), user.stats.auctionsWon != null && (_jsxs(Div, { className: CLS_STAT_BOX, children: [_jsx(Text, { className: "leading-none", color: "primary", size: "lg", weight: "bold", children: user.stats.auctionsWon }), _jsx(Text, { className: CLS_STAT_LABEL, children: "Auctions Won" })] })), user.stats.itemsSold != null && (_jsxs(Div, { className: CLS_STAT_BOX, children: [_jsx(Text, { className: "leading-none", color: "primary", size: "lg", weight: "bold", children: user.stats.itemsSold }), _jsx(Text, { className: CLS_STAT_LABEL, children: "Items Sold" })] }))] })), isAuthenticated && isAdminOrSeller && (adminHref || resolvedStoreHref) && (_jsx(CollapsibleNavGroup, { title: labels.dashboardSectionTitle, hasActive: !!activeDashboardLink, children: _jsxs(Ul, { spacing: "2xs", children: [adminHref && role === "admin" && (_jsx(Li, { children: _jsx(TextLink, { href: adminHref, variant: "none", className: activeDashboardLink?.href === adminHref ? navItemActiveClass : navItemClass, "aria-current": activeDashboardLink?.href === adminHref ? "page" : undefined, children: labels.adminDashboard }) })), resolvedStoreHref && isAdminOrSeller && (_jsx(Li, { children: _jsx(TextLink, { href: resolvedStoreHref, variant: "none", className: activeDashboardLink?.href === resolvedStoreHref ? navItemActiveClass : navItemClass, "aria-current": activeDashboardLink?.href === resolvedStoreHref ? "page" : undefined, children: labels.storeDashboard }) }))] }) })), normalizedSections.map((section, sectionIndex) => (_jsx(CollapsibleSidebarSection, { section: section, navItemClass: navItemClass, navItemActiveClass: navItemActiveClass, activeHref: activeHref }, `sidebar-section-${sectionIndex}`))), (sidebarLocaleSlot || showThemeToggleInSidebar || (isAuthenticated && onLogout)) && (_jsxs(Stack, { border: "default", className: "border-t border-[var(--appkit-color-border-subtle)]", padding: "t-md", gap: "3", children: [sidebarLocaleSlot, showThemeToggleInSidebar && (_jsxs("button", { type: "button", onClick: toggleTheme, className: "flex w-full items-center justify-end gap-[var(--appkit-space-3)] rounded-lg px-[var(--appkit-space-3)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] text-[var(--appkit-color-text-muted)] transition-colors hover:bg-primary-surface hover:text-primary-800 dark:hover:text-primary-200", children: [_jsx(Span, { "aria-hidden": "true", children: theme === "dark" ? "☀️" : "🌙" }), activeThemeName] })), isAuthenticated && onLogout && (_jsx("button", { type: "button", onClick: () => { onLogout(); onAfterLogout(); }, className: CLS_LOGOUT_BTN, children: labels.logout }))] }))] }));
180
180
  }
181
181
  // ─── Main component ────────────────────────────────────────────────────────────
182
182
  export function AppLayoutShell({ children, navItems, sidebarItems = [], sidebarSections, sidebarPrimaryActions, sidebarTitle = "Navigation", hiddenNavItems, user, brandName, brandShortName, siteLogoUrl, logoHref, promotionsHref, cartHref, wishlistHref, messagesHref, unreadMessageCount, userId, profileHref, loginHref, registerHref, homeHref, shopHref, footer, searchSlot, searchSlotRenderer, titleBarNavSlot, titleBarNotificationSlot, titleBarDevSlot, titleBarPromoStripText, showThemeToggle = false, suppressDashboardNav = false, hideSidebarToggle = false, onLogout, adminHref, storeHref, sellerHref, userOrdersHref, userWishlistHref, userSettingsHref, sidebarLocaleSlot, showThemeToggleInSidebar = false, sidebarProfileLabels, eventBannerSlot, showBottomNav = true, contentClassName, lightBackground = DEFAULT_LIGHT_BG, darkBackground = DEFAULT_DARK_BG, }) {