@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
@@ -1,4 +1,7 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { normalizeError } from "../../../errors/normalize.js";
3
+ import { serverLogger } from "../../../monitoring/server-logger.js";
4
+ import { siteSettingsRepository } from "../../../repositories/index.js";
2
5
  import { ROUTES } from "../../../constants/index.js";
3
6
  import { PAGE_CONTAINER } from "../../../_internal/shared/styles/page.js";
4
7
  import { Div, Heading, Text, Section, Stack, FlowDiagram } from "../../../ui/index.js";
@@ -8,6 +11,35 @@ export async function ShippingPolicyView({} = {}) {
8
11
  const page = { container: PAGE_CONTAINER };
9
12
  const { getTranslations } = await import("next-intl/server");
10
13
  const t = await getTranslations("shippingPolicy");
14
+ /*
15
+ * 🛑 `siteSettings.legalPages.shipping` was WRITTEN by the admin form and
16
+ * read by nothing.
17
+ *
18
+ * Every other legal page renders through `PolicyPageView`, which checks that
19
+ * group for an admin HTML override. This page does not — it has a bespoke
20
+ * layout with a five-step delivery diagram that a flat `sections[]` cannot
21
+ * express — so the override had no reader and an admin who rewrote the
22
+ * shipping policy saw their text saved successfully and never appear.
23
+ *
24
+ * Reading it here rather than converting the page is the deliberate choice:
25
+ * converting would mean flattening 38 i18n keys into `sections[]` and losing
26
+ * the diagram, which is a regression dressed up as consolidation.
27
+ */
28
+ let adminHtml = "";
29
+ try {
30
+ const settings = await siteSettingsRepository.getSingleton();
31
+ adminHtml = settings.legalPages?.shipping ?? "";
32
+ }
33
+ catch (_err) {
34
+ void normalizeError(_err);
35
+ // The i18n copy below is a complete policy in its own right, so a failed
36
+ // read degrades to it — but an admin who HAS overridden this page would
37
+ // silently see the old text, so the operator needs to know.
38
+ serverLogger.warn("about.shippingPolicyView: siteSettings.legalPages read failed", {
39
+ field: "shipping",
40
+ error: normalizeError(_err).message,
41
+ });
42
+ }
11
43
  const SECTIONS = [
12
44
  { title: t("orderProcessTitle"), text: t("orderProcessText") },
13
45
  { title: t("standardTitle"), text: t("standardText") },
@@ -55,5 +87,13 @@ export async function ShippingPolicyView({} = {}) {
55
87
  desc: t("diagramStatus5Desc"),
56
88
  },
57
89
  ];
58
- return (_jsxs(Div, { className: "-mx-4 md:-mx-6 lg:-mx-8 -mt-6 sm:-mt-8 lg:-mt-10", children: [_jsx(Section, { color: "inverse", tone: "accent-banner", padding: "banner", children: _jsxs(Div, { className: `${page.container.sm}`, children: [_jsx(Heading, { color: "inverse", level: 1, variant: "none", className: "mb-3", children: t("title") }), _jsx(Text, { color: "inverse", variant: "none", className: "/80", children: t("lastUpdated") })] }) }), _jsxs(Div, { className: `${page.container.sm}`, padding: "content-banner", children: [_jsx(Text, { size: "lg", variant: "secondary", className: "mb-8", children: t("subtitle") }), _jsx(FlowDiagram, { title: `🚚 ${t("diagramTitle")}`, titleClass: "text-sky-700 dark:text-sky-300", connectorClass: "bg-sky-200 dark:bg-sky-800", steps: DIAGRAM_STEPS, className: "mb-10", note: `📌 ${t("diagramNote")}` }), _jsxs(Stack, { gap: "xl", children: [SECTIONS.map(({ title, text }) => (_jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "mb-3", children: title }), _jsx(Text, { variant: "secondary", className: "leading-relaxed", children: text })] }, title))), _jsxs(Section, { rounded: "xl", padding: "lg", border: "default", surface: "subtle", children: [_jsx(Heading, { level: 2, className: "mb-2", children: t("contactTitle") }), _jsx(Text, { variant: "secondary", children: t("contactText") })] })] }), _jsxs(Div, { layout: "flex", gap: "6", textSize: "sm", className: `mt-12 border-t`, border: "default", padding: "t-xl", children: [_jsx(TextLink, { href: String(ROUTES.PUBLIC.TRACK_ORDER), className: CLS_FOOTER_LINK, children: t("trackOrder") }), _jsx(TextLink, { href: String(ROUTES.PUBLIC.HELP), className: CLS_FOOTER_LINK, children: t("helpCenter") }), _jsx(TextLink, { href: String(ROUTES.PUBLIC.CONTACT), className: CLS_FOOTER_LINK, children: t("contactUs") }), _jsx(TextLink, { href: String(ROUTES.PUBLIC.REFUND_POLICY), className: CLS_FOOTER_LINK, children: "Refund Policy" })] })] })] }));
90
+ return (_jsxs(Div, { className: "-mx-4 md:-mx-6 lg:-mx-8 -mt-6 sm:-mt-8 lg:-mt-10", children: [_jsx(Section, { color: "inverse", tone: "accent-banner", padding: "banner", children: _jsxs(Div, { className: `${page.container.sm}`, children: [_jsx(Heading, { color: "inverse", level: 1, variant: "none", className: "mb-3", children: t("title") }), _jsx(Text, { color: "inverse", variant: "none", className: "/80", children: t("lastUpdated") })] }) }), _jsxs(Div, { className: `${page.container.sm}`, padding: "content-banner", children: [adminHtml ? (
91
+ /*
92
+ Admin-set HTML replaces the WHOLE body — subtitle, sections,
93
+ diagram and contact block — matching PolicyPageView's behaviour
94
+ exactly. Rendering the override above the bundled copy would show
95
+ two shipping policies on one page, and the reader has no way to
96
+ know which one binds.
97
+ */
98
+ _jsx(Div, { className: "prose max-w-none", dangerouslySetInnerHTML: { __html: adminHtml } })) : (_jsxs(_Fragment, { children: [_jsx(Text, { size: "lg", variant: "secondary", className: "mb-8", children: t("subtitle") }), _jsx(FlowDiagram, { title: `🚚 ${t("diagramTitle")}`, titleClass: "text-sky-700 dark:text-sky-300", connectorClass: "bg-sky-200 dark:bg-sky-800", steps: DIAGRAM_STEPS, className: "mb-10", note: `📌 ${t("diagramNote")}` }), _jsxs(Stack, { gap: "xl", children: [SECTIONS.map(({ title, text }) => (_jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "mb-3", children: title }), _jsx(Text, { variant: "secondary", className: "leading-relaxed", children: text })] }, title))), _jsxs(Section, { rounded: "xl", padding: "lg", border: "default", surface: "subtle", children: [_jsx(Heading, { level: 2, className: "mb-2", children: t("contactTitle") }), _jsx(Text, { variant: "secondary", children: t("contactText") })] })] })] })), _jsxs(Div, { layout: "flex", gap: "6", textSize: "sm", className: `mt-12 border-t`, border: "default", padding: "t-xl", children: [_jsx(TextLink, { href: String(ROUTES.PUBLIC.TRACK_ORDER), className: CLS_FOOTER_LINK, children: t("trackOrder") }), _jsx(TextLink, { href: String(ROUTES.PUBLIC.HELP), className: CLS_FOOTER_LINK, children: t("helpCenter") }), _jsx(TextLink, { href: String(ROUTES.PUBLIC.CONTACT), className: CLS_FOOTER_LINK, children: t("contactUs") }), _jsx(TextLink, { href: String(ROUTES.PUBLIC.REFUND_POLICY), className: CLS_FOOTER_LINK, children: "Refund Policy" })] })] })] }));
59
99
  }
@@ -109,5 +109,5 @@ function renderNotificationListContent(props) {
109
109
  return _jsx(Row, { align: "center", justify: "center", padding: "y-2xl", children: _jsx(Spinner, { size: "md" }) });
110
110
  if (notifications.length === 0)
111
111
  return (_jsxs(Stack, { justify: "center", className: "text-left", paddingY: "y-2xl", paddingX: "x-md", align: "start", children: [_jsx("svg", { className: "w-12 h-12 text-[var(--appkit-color-text-faint)] mb-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" }) }), _jsx(Text, { weight: "medium", color: "primary", children: labels.empty }), _jsx(Text, { size: "sm", className: "mt-1", color: "muted", children: labels.emptyDesc })] }));
112
- return (_jsx(Ul, { children: notifications.map((notification) => (_jsxs(Li, { layout: "flex-start", gap: "3", padding: "inline", className: `group border-b border-[var(--appkit-color-border)] last:border-0 transition-colors hover:bg-[var(--appkit-color-bg)] dark:hover:bg-[var(--appkit-color-surface-elevated)] ${!notification.isRead ? "bg-primary/5 dark:bg-primary/10" : ""}`, children: [_jsx(Span, { size: "xl", className: "flex-shrink-0 mt-0.5", children: notificationIcons[notification.type] ?? "🔔" }), _jsxs(Div, { className: "flex-1 min-w-0", children: [_jsxs(Row, { align: "start", justify: "between", gap: "xs", children: [_jsxs(Text, { size: "sm", className: "leading-tight", color: "primary", weight: "medium", children: [notification.title, !notification.isRead && _jsx(Span, { className: "ml-1.5 inline-block w-2 h-2 bg-primary flex-shrink-0 align-middle", rounded: "full" })] }), _jsx(Span, { size: "xs", className: "flex-shrink-0", color: "muted", children: formatRelativeTime(notification.createdAt) })] }), _jsx(Text, { size: "sm", className: `mt-0.5`, truncate: 2, color: "muted", children: notification.message }), _jsxs(Row, { gap: "3", className: "mt-1.5", children: [notification.actionUrl && renderActionLink({ href: notification.actionUrl, onClick: () => { void handleMarkReadAndClose(notification); }, className: "text-[length:var(--appkit-text-xs)] text-primary hover:underline font-medium", children: notification.actionLabel ?? labels.viewAction }), !notification.isRead && _jsx(Button, { variant: "ghost", onClick: () => void handleMarkRead(notification.id), className: "text-[length:var(--appkit-text-xs)] text-[var(--appkit-color-text-muted)] hover:text-zinc-700 hover:text-[var(--appkit-color-text-muted)] hover:underline p-[var(--appkit-space-0)] h-auto", children: labels.markRead })] })] })] }, notification.id))) }));
112
+ return (_jsx(Ul, { children: notifications.map((notification) => (_jsxs(Li, { layout: "flex-start", gap: "3", padding: "inline", className: `group border-b border-[var(--appkit-color-border)] last:border-0 transition-colors hover:bg-[var(--appkit-color-bg)] dark:hover:bg-[var(--appkit-color-surface-elevated)] ${!notification.isRead ? "bg-primary/5 dark:bg-primary/10" : ""}`, children: [_jsx(Span, { size: "xl", className: "flex-shrink-0 mt-0.5", children: notificationIcons[notification.type] ?? "🔔" }), _jsxs(Div, { className: "flex-1 min-w-0", children: [_jsxs(Row, { align: "start", justify: "between", gap: "xs", children: [_jsxs(Text, { size: "sm", className: "leading-tight", color: "primary", weight: "medium", children: [notification.title, !notification.isRead && _jsx(Span, { className: "ml-1.5 inline-block w-2 h-2 bg-primary flex-shrink-0 align-middle", rounded: "full" })] }), _jsx(Span, { size: "xs", className: "flex-shrink-0", color: "muted", children: formatRelativeTime(notification.createdAt) })] }), _jsx(Text, { size: "sm", className: `mt-0.5`, truncate: 2, color: "muted", children: notification.message }), _jsxs(Row, { gap: "3", className: "mt-1.5", children: [notification.actionUrl && renderActionLink({ href: notification.actionUrl, onClick: () => { void handleMarkReadAndClose(notification); }, className: "text-[length:var(--appkit-text-xs)] text-primary hover:underline font-medium", children: notification.actionLabel ?? labels.viewAction }), !notification.isRead && _jsx(Button, { variant: "ghost", onClick: () => void handleMarkRead(notification.id), className: "text-[length:var(--appkit-text-xs)] text-[var(--appkit-color-text-muted)] hover:text-[var(--appkit-color-text)] hover:underline p-[var(--appkit-space-0)] h-auto", children: labels.markRead })] })] })] }, notification.id))) }));
113
113
  }
@@ -4,7 +4,11 @@ import { ACCOUNT_ENDPOINTS } from "../../../constants/api-endpoints.js";
4
4
  export function useProfileStats(enabled) {
5
5
  const { data: ordersData, isLoading: ordersLoading } = useQuery({
6
6
  queryKey: ["user-orders-count"],
7
- queryFn: () => apiClient.get(ACCOUNT_ENDPOINTS.ORDERS),
7
+ queryFn: () =>
8
+ // `items`, not `orders` — GET /api/user/orders emits the shared list
9
+ // envelope. Only `total` is read below, so the wrong key never threw
10
+ // here; it was a false declaration waiting for someone to read it.
11
+ apiClient.get(ACCOUNT_ENDPOINTS.ORDERS),
8
12
  enabled,
9
13
  });
10
14
  const { data: addressesData, isLoading: addressesLoading } = useQuery({
@@ -1,3 +1,4 @@
1
+ import type { JsonValue } from "../../../schemas/types";
1
2
  import { BaseRepository } from "../../../providers/db-firebase";
2
3
  import { type AddressBanStatus, type AddressCreateInput, type AddressDocument, type AddressPlain, type AddressOwnerType, type AddressUpdateInput } from "../schemas";
3
4
  export declare class AddressesRepository extends BaseRepository<AddressDocument> {
@@ -14,6 +15,21 @@ export declare class AddressesRepository extends BaseRepository<AddressDocument>
14
15
  * call.
15
16
  */
16
17
  protected piiFields: readonly ["fullName", "phone", "addressLine1", "addressLine2"];
18
+ /**
19
+ * Admin search by name, without decryption. ONLY `fullName` — never
20
+ * `addressLine1`: "find everyone on Brigade Road" is not a capability
21
+ * admin needs and is the single most re-identifying field on the
22
+ * document. See `security/blind-index-tokens.ts` for why this is
23
+ * whole-word rather than a prefix-expanded index.
24
+ *
25
+ * Runs through `applyWriteHooks`, so it reaches every write path
26
+ * including a seed load — which is what makes it survive the tester
27
+ * harness's cascade on `addresses` (it references `ownerId`, a
28
+ * PRESERVE-tier user, so the row itself is never actually wiped — but
29
+ * the field regenerating on every write is what makes that true by
30
+ * construction rather than by luck).
31
+ */
32
+ protected buildTokensIndexFor(data: Record<string, JsonValue>): Record<string, string[]> | null;
17
33
  /** Plaintext PII. **Opt-in and named** — shows up in review and in a grep. */
18
34
  revealAddress(doc: AddressDocument): AddressPlain;
19
35
  /** As `revealAddress`, for a list read. */
@@ -14,6 +14,7 @@ import { DatabaseError } from "../../../errors/index.js";
14
14
  import { serverLogger } from "../../../monitoring/index.js";
15
15
  import { BaseRepository, getFirestoreCount, prepareForFirestore, } from "../../../providers/db-firebase/index.js";
16
16
  import { maskPii, revealPii, ADDRESS_PII_FIELDS, } from "../../../security/index.js";
17
+ import { buildTokensIndex } from "../../../security/blind-index-tokens.js";
17
18
  import { ADDRESS_FIELDS, ADDRESSES_COLLECTION, } from "../schemas/index.js";
18
19
  export class AddressesRepository extends BaseRepository {
19
20
  constructor() {
@@ -31,6 +32,26 @@ export class AddressesRepository extends BaseRepository {
31
32
  */
32
33
  this.piiFields = ADDRESS_PII_FIELDS;
33
34
  }
35
+ /**
36
+ * Admin search by name, without decryption. ONLY `fullName` — never
37
+ * `addressLine1`: "find everyone on Brigade Road" is not a capability
38
+ * admin needs and is the single most re-identifying field on the
39
+ * document. See `security/blind-index-tokens.ts` for why this is
40
+ * whole-word rather than a prefix-expanded index.
41
+ *
42
+ * Runs through `applyWriteHooks`, so it reaches every write path
43
+ * including a seed load — which is what makes it survive the tester
44
+ * harness's cascade on `addresses` (it references `ownerId`, a
45
+ * PRESERVE-tier user, so the row itself is never actually wiped — but
46
+ * the field regenerating on every write is what makes that true by
47
+ * construction rather than by luck).
48
+ */
49
+ buildTokensIndexFor(data) {
50
+ const fullName = typeof data.fullName === "string" ? data.fullName : undefined;
51
+ if (!fullName)
52
+ return null;
53
+ return { nameTokensIndex: buildTokensIndex(fullName) };
54
+ }
34
55
  /*
35
56
  * 🛑 `mapDoc` is NOT overridden, and that absence IS the change.
36
57
  *
@@ -238,7 +238,22 @@ export async function adminUpdateProduct(adminId, id, input) {
238
238
  finalized.mainImage = await finalizeStagedMediaUrl(finalized.mainImage);
239
239
  }
240
240
  if (Array.isArray(finalized.images) && finalized.images.length > 0) {
241
- finalized.images = await finalizeStagedMediaArray(finalized.images);
241
+ /*
242
+ * 🛑 Finalise the URL and KEEP THE REST OF THE OBJECT (A6).
243
+ *
244
+ * `finalizeStagedMediaArray` takes and returns `string[]` — it moves
245
+ * staged uploads to their permanent path. Handing it
246
+ * `images.map(i => i.url)` and assigning the result back would have
247
+ * silently dropped `alt`, `width`, `height` and `thumbnailUrl` on every
248
+ * admin save: the exact lossy-write failure `toProductImages` carries its
249
+ * own warning about, on the one code path where a human has just typed
250
+ * the alt text.
251
+ */
252
+ const finalisedUrls = await finalizeStagedMediaArray(finalized.images.map((img) => img.url));
253
+ finalized.images = finalized.images.map((img, i) => ({
254
+ ...img,
255
+ url: finalisedUrls[i] ?? img.url,
256
+ }));
242
257
  }
243
258
  if (finalized.video?.url) {
244
259
  finalized.video = {
@@ -115,6 +115,14 @@ const categoryFormSchema = z.object({
115
115
  .optional()
116
116
  .or(z.literal("")),
117
117
  highlightsText: z.string().optional().or(z.literal("")),
118
+ /*
119
+ * The Hasbro / international-market name for a generation wave, rendered on
120
+ * the category page as "Also known as". Editable here because wave naming is
121
+ * editorial and gets corrected — the seed deliberately leaves it unset
122
+ * wherever a divergence is not evidenced, and this is how one gets filled in
123
+ * later without a reseed.
124
+ */
125
+ hasbroName: z.string().max(120, "Keep the name under 120 characters").optional().or(z.literal("")),
118
126
  taxCodeId: z.string().optional().or(z.literal("")),
119
127
  defaultCondition: z.string().optional().or(z.literal("")),
120
128
  defaultAuthenticity: z.string().optional().or(z.literal("")),
@@ -145,6 +153,7 @@ const EMPTY_VALUES = {
145
153
  showInMenu: true,
146
154
  contentBody: "",
147
155
  highlightsText: "",
156
+ hasbroName: "",
148
157
  taxCodeId: "",
149
158
  defaultCondition: "",
150
159
  defaultAuthenticity: "",
@@ -245,6 +254,13 @@ function buildContentPayload(v, faqs, specs, templates, carriedPriceGuidance) {
245
254
  contentBody: String(v.contentBody ?? ""),
246
255
  highlights: linesToList(String(v.highlightsText ?? "")),
247
256
  faqs: faqs.filter((f) => f.question.trim() !== "" && f.answer.trim() !== ""),
257
+ /*
258
+ * Omitted when blank rather than sent as `""`. The route schema is
259
+ * `.min(1)`, so an empty string is a 400 — and "I cleared the field" has
260
+ * to mean "do not write it", not "write an empty string every reader then
261
+ * has to treat as absent".
262
+ */
263
+ ...(String(v.hasbroName ?? "").trim() ? { hasbroName: String(v.hasbroName).trim() } : {}),
248
264
  descriptionTemplates: templates
249
265
  .filter((t) => t.label.trim() !== "" && t.body.trim() !== "")
250
266
  .map((t) => ({ ...t, id: t.id || toCategorySlug(t.label) || "template" })),
@@ -316,6 +332,7 @@ export function AdminCategoryEditorView({ categoryId, onSaved, onDeleted, embedd
316
332
  showInMenu: cat.display?.showInMenu ?? true,
317
333
  contentBody: cat.contentBody ?? "",
318
334
  highlightsText: listToLines(cat.highlights),
335
+ hasbroName: cat.hasbroName ?? "",
319
336
  taxCodeId: cat.productDefaults?.taxCodeId ?? "",
320
337
  defaultCondition: cat.productDefaults?.defaultCondition ?? "",
321
338
  defaultAuthenticity: cat.productDefaults?.defaultAuthenticity ?? "",
@@ -430,8 +447,8 @@ export function AdminCategoryEditorView({ categoryId, onSaved, onDeleted, embedd
430
447
  {
431
448
  id: "content",
432
449
  label: "Content & Templates",
433
- fields: ["contentBody", "highlightsText"],
434
- render: ({ values: v, onChange, errors }) => (_jsxs(Stack, { gap: "md", children: [_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "medium", children: "Category page body" }), _jsx(Textarea, { value: String(v.contentBody ?? ""), onChange: (e) => onChange({ contentBody: e.target.value }), rows: 8, placeholder: "400\u2013900 characters of keyword-rich HTML with links to sibling and parent categories\u2026" }), errors.contentBody ? (_jsx(Text, { size: "sm", variant: "error", role: "alert", children: errors.contentBody })) : (_jsx(Text, { size: "xs", color: "muted", children: "Rendered on the category page. Distinct from the short Description above, which also feeds the SEO meta and every card. 36 of worldhobbyshop's 46 categories carry one of these and it is their actual ranking mechanism; no Shopify competitor in the crawl has any." }))] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "medium", children: "Highlights \u2014 one per line" }), _jsx(Textarea, { value: String(v.highlightsText ?? ""), onChange: (e) => onChange({ highlightsText: e.target.value }), rows: 4, placeholder: "Genuine Takara Tomy stock\nChecked and photographed before listing" }), _jsx(Text, { size: "xs", color: "muted", children: "Short \"why shop this\" bullets, shown above the FAQs. Blank lines are dropped. Up to 12." })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "medium", children: "Category FAQs" }), _jsx(Text, { size: "xs", color: "muted", children: "Rendered as an accordion on the category page and emitted as FAQPage structured data. Keep platform-wide answers in the global FAQ collection instead \u2014 two copies of one answer means the one that gets fixed is never the one being read." }), _jsx(Repeater, { rows: faqs, onChange: setFaqs, blank: () => ({ question: "", answer: "" }), addLabel: "Add an FAQ", max: 20, renderRow: (row, set) => (_jsxs(_Fragment, { children: [_jsx(Input, { label: "Question", value: row.question, onChange: (e) => set({ question: e.target.value }), placeholder: "Are these compatible with Burst launchers?" }), _jsx(Textarea, { value: row.answer, onChange: (e) => set({ answer: e.target.value }), rows: 3, placeholder: "Answer\u2026" })] })) })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "medium", children: "Description templates" }), _jsxs(Text, { size: "xs", color: "muted", children: ["What the seller form offers when a listing is filed here. One per condition band \u2014 worldhobbyshop reuses exactly two across 1,195 listings. Slots like", " ", _jsx(Span, { family: "mono", children: "{{title}}" }), ",", " ", _jsx(Span, { family: "mono", children: "{{brand}}" }), ",", " ", _jsx(Span, { family: "mono", children: "{{condition}}" }), " and", " ", _jsx(Span, { family: "mono", children: "{{series}}" }), " are filled from the listing; an unresolved one becomes empty and is reported to the seller, never left as a literal brace pair."] }), _jsx(Repeater, { rows: templates, onChange: setTemplates, blank: () => ({ id: "", label: "", variant: "default", body: "" }), addLabel: "Add a template", max: 8, renderRow: (row, set) => (_jsxs(_Fragment, { children: [_jsxs(Div, { layout: "grid", gap: "4", className: "sm:grid-cols-2", children: [_jsx(Input, { label: "Label", value: row.label, onChange: (e) => set({ label: e.target.value }), placeholder: "Pre-owned \u2014 condition as pictured" }), _jsx(Select, { label: "Condition band", value: row.variant, onChange: (e) => set({ variant: e.target.value }), options: TEMPLATE_VARIANT_OPTIONS })] }), _jsx(Textarea, { value: row.body, onChange: (e) => set({ body: e.target.value }), rows: 6, placeholder: "Important things to know about {{title}} \u2014 HTML permitted\u2026" }), _jsx(Text, { size: "xs", color: "muted", children: usedPlaceholders(row.body).length > 0
450
+ fields: ["contentBody", "highlightsText", "hasbroName"],
451
+ render: ({ values: v, onChange, errors }) => (_jsxs(Stack, { gap: "md", children: [_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "medium", children: "Category page body" }), _jsx(Textarea, { value: String(v.contentBody ?? ""), onChange: (e) => onChange({ contentBody: e.target.value }), rows: 8, placeholder: "400\u2013900 characters of keyword-rich HTML with links to sibling and parent categories\u2026" }), errors.contentBody ? (_jsx(Text, { size: "sm", variant: "error", role: "alert", children: errors.contentBody })) : (_jsx(Text, { size: "xs", color: "muted", children: "Rendered on the category page. Distinct from the short Description above, which also feeds the SEO meta and every card. 36 of worldhobbyshop's 46 categories carry one of these and it is their actual ranking mechanism; no Shopify competitor in the crawl has any." }))] }), _jsx(FieldInput, { name: "hasbroName", label: "Hasbro / international name", value: String(v.hasbroName ?? ""), onChange: (val) => onChange({ hasbroName: val }), placeholder: "e.g. Beyblade Burst Turbo", error: errors.hasbroName, hint: "Only when the Hasbro season name genuinely differs from the Takara-Tomy one \u2014 Cho-Z ships as Turbo, God as Evolution. Rendered on the category page as 'Also known as'. Leave blank if there is no divergence, or if you cannot confirm one: a guessed pairing reads as fact." }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "medium", children: "Highlights \u2014 one per line" }), _jsx(Textarea, { value: String(v.highlightsText ?? ""), onChange: (e) => onChange({ highlightsText: e.target.value }), rows: 4, placeholder: "Genuine Takara Tomy stock\nChecked and photographed before listing" }), _jsx(Text, { size: "xs", color: "muted", children: "Short \"why shop this\" bullets, shown above the FAQs. Blank lines are dropped. Up to 12." })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "medium", children: "Category FAQs" }), _jsx(Text, { size: "xs", color: "muted", children: "Rendered as an accordion on the category page and emitted as FAQPage structured data. Keep platform-wide answers in the global FAQ collection instead \u2014 two copies of one answer means the one that gets fixed is never the one being read." }), _jsx(Repeater, { rows: faqs, onChange: setFaqs, blank: () => ({ question: "", answer: "" }), addLabel: "Add an FAQ", max: 20, renderRow: (row, set) => (_jsxs(_Fragment, { children: [_jsx(Input, { label: "Question", value: row.question, onChange: (e) => set({ question: e.target.value }), placeholder: "Are these compatible with Burst launchers?" }), _jsx(Textarea, { value: row.answer, onChange: (e) => set({ answer: e.target.value }), rows: 3, placeholder: "Answer\u2026" })] })) })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "medium", children: "Description templates" }), _jsxs(Text, { size: "xs", color: "muted", children: ["What the seller form offers when a listing is filed here. One per condition band \u2014 worldhobbyshop reuses exactly two across 1,195 listings. Slots like", " ", _jsx(Span, { family: "mono", children: "{{title}}" }), ",", " ", _jsx(Span, { family: "mono", children: "{{brand}}" }), ",", " ", _jsx(Span, { family: "mono", children: "{{condition}}" }), " and", " ", _jsx(Span, { family: "mono", children: "{{series}}" }), " are filled from the listing; an unresolved one becomes empty and is reported to the seller, never left as a literal brace pair."] }), _jsx(Repeater, { rows: templates, onChange: setTemplates, blank: () => ({ id: "", label: "", variant: "default", body: "" }), addLabel: "Add a template", max: 8, renderRow: (row, set) => (_jsxs(_Fragment, { children: [_jsxs(Div, { layout: "grid", gap: "4", className: "sm:grid-cols-2", children: [_jsx(Input, { label: "Label", value: row.label, onChange: (e) => set({ label: e.target.value }), placeholder: "Pre-owned \u2014 condition as pictured" }), _jsx(Select, { label: "Condition band", value: row.variant, onChange: (e) => set({ variant: e.target.value }), options: TEMPLATE_VARIANT_OPTIONS })] }), _jsx(Textarea, { value: row.body, onChange: (e) => set({ body: e.target.value }), rows: 6, placeholder: "Important things to know about {{title}} \u2014 HTML permitted\u2026" }), _jsx(Text, { size: "xs", color: "muted", children: usedPlaceholders(row.body).length > 0
435
452
  ? `Slots used: ${usedPlaceholders(row.body).map((p) => `{{${p}}}`).join(", ")}`
436
453
  : "No slots used — this body will read identically on every listing." })] })) })] })] })),
437
454
  },
@@ -12,7 +12,7 @@ const __O = {
12
12
  hidden: "overflow-hidden",
13
13
  };
14
14
  function NavItemRow({ item, idx, total, reorderPending, onMoveUp, onMoveDown, onVisibilityChange, onEdit, onDelete, }) {
15
- return (_jsxs(Row, { surface: "default", padding: "inline", align: "center", gap: "3", children: [_jsxs(Stack, { className: "shrink-0 gap-[0.125rem]", children: [_jsx(Button, { variant: "ghost", type: "button", onClick: () => onMoveUp(idx), disabled: idx === 0 || reorderPending, className: "text-zinc-400 hover:text-zinc-700 hover:text-[var(--appkit-color-text-muted)] disabled:opacity-30 leading-none text-[length:var(--appkit-text-xs)] p-[var(--appkit-space-0)] min-h-0 h-auto rounded-none", "aria-label": "Move up", children: "\u25B2" }), _jsx(Button, { variant: "ghost", type: "button", onClick: () => onMoveDown(idx), disabled: idx >= total - 1 || reorderPending, className: "text-zinc-400 hover:text-zinc-700 hover:text-[var(--appkit-color-text-muted)] disabled:opacity-30 leading-none text-[length:var(--appkit-text-xs)] p-[var(--appkit-space-0)] min-h-0 h-auto rounded-none", "aria-label": "Move down", children: "\u25BC" })] }), _jsxs(Div, { className: "flex-1 min-w-0", children: [_jsxs(Text, { className: "truncate", color: "primary", size: "sm", weight: "medium", children: [item.parentId ? _jsx(Span, { className: "mr-1", color: "faint", children: "\u21B3" }) : null, item.label] }), _jsx(Text, { className: "truncate", color: "muted", size: "xs", children: item.href })] }), _jsx(Toggle, { checked: item.isVisible ?? true, onChange: (val) => onVisibilityChange(item.id, val), label: "" }), _jsx(RowActionMenu, { actions: [
15
+ return (_jsxs(Row, { surface: "default", padding: "inline", align: "center", gap: "3", children: [_jsxs(Stack, { className: "shrink-0 gap-[0.125rem]", children: [_jsx(Button, { variant: "ghost", type: "button", onClick: () => onMoveUp(idx), disabled: idx === 0 || reorderPending, className: "text-zinc-400 hover:text-[var(--appkit-color-text)] disabled:opacity-30 leading-none text-[length:var(--appkit-text-xs)] p-[var(--appkit-space-0)] min-h-0 h-auto rounded-none", "aria-label": "Move up", children: "\u25B2" }), _jsx(Button, { variant: "ghost", type: "button", onClick: () => onMoveDown(idx), disabled: idx >= total - 1 || reorderPending, className: "text-zinc-400 hover:text-[var(--appkit-color-text)] disabled:opacity-30 leading-none text-[length:var(--appkit-text-xs)] p-[var(--appkit-space-0)] min-h-0 h-auto rounded-none", "aria-label": "Move down", children: "\u25BC" })] }), _jsxs(Div, { className: "flex-1 min-w-0", children: [_jsxs(Text, { className: "truncate", color: "primary", size: "sm", weight: "medium", children: [item.parentId ? _jsx(Span, { className: "mr-1", color: "faint", children: "\u21B3" }) : null, item.label] }), _jsx(Text, { className: "truncate", color: "muted", size: "xs", children: item.href })] }), _jsx(Toggle, { checked: item.isVisible ?? true, onChange: (val) => onVisibilityChange(item.id, val), label: "" }), _jsx(RowActionMenu, { actions: [
16
16
  { label: ROW_ACTION_META[ROW_ACTION_ID.EDIT].label, onClick: () => onEdit(item) },
17
17
  { label: ROW_ACTION_META[ROW_ACTION_ID.DELETE].label, destructive: true, onClick: () => onDelete(item) },
18
18
  ] })] }));
@@ -10,5 +10,5 @@ export function AdminPageHeader({ title, subtitle, description, badge, breadcrum
10
10
  subtitleClass: "text-[length:var(--appkit-text-lg)] text-gray-700",
11
11
  spacingClass: "space-y-1",
12
12
  }, }) {
13
- return (_jsxs(Div, { className: `${themeConfig.gradient} ${__P.p6} ${className}`, children: [breadcrumb && breadcrumb.length > 0 && (_jsx(Nav, { "aria-label": "Breadcrumb", layout: "flex", gap: "xs", textSize: "sm", color: "muted", className: "mb-3", children: breadcrumb.map((crumb, index) => (_jsxs(Span, { layout: "flex", gap: "xs", children: [index > 0 && _jsx(ChevronRight, { className: "w-3 h-3 flex-shrink-0" }), crumb.href && themeConfig.TextLink ? (_jsx(themeConfig.TextLink, { href: crumb.href, className: "hover:text-zinc-700 hover:text-[var(--appkit-color-text-muted)] transition-colors", children: crumb.label })) : (_jsx(Span, { weight: "medium", color: "primary", children: crumb.label }))] }, index))) })), _jsxs(Stack, { direction: "sm-row", align: "center", justify: "between", gap: "md", children: [_jsxs(Div, { className: themeConfig.spacingClass, children: [_jsxs(Row, { gap: "sm", wrap: true, children: [_jsx(Heading, { level: 2, className: themeConfig.titleClass, children: title }), badge && _jsx(Span, { className: "flex-shrink-0", children: badge })] }), subtitle && (_jsx(Text, { className: themeConfig.subtitleClass, children: subtitle })), description && (_jsx(Text, { className: "mt-1", color: "muted", size: "sm", children: description }))] }), actionLabel && onAction && (_jsxs(Button, { variant: "primary", onClick: onAction, disabled: actionDisabled, className: "flex-shrink-0", children: [actionIcon, actionLabel] }))] })] }));
13
+ return (_jsxs(Div, { className: `${themeConfig.gradient} ${__P.p6} ${className}`, children: [breadcrumb && breadcrumb.length > 0 && (_jsx(Nav, { "aria-label": "Breadcrumb", layout: "flex", gap: "xs", textSize: "sm", color: "muted", className: "mb-3", children: breadcrumb.map((crumb, index) => (_jsxs(Span, { layout: "flex", gap: "xs", children: [index > 0 && _jsx(ChevronRight, { className: "w-3 h-3 flex-shrink-0" }), crumb.href && themeConfig.TextLink ? (_jsx(themeConfig.TextLink, { href: crumb.href, className: "hover:text-[var(--appkit-color-text)] transition-colors", children: crumb.label })) : (_jsx(Span, { weight: "medium", color: "primary", children: crumb.label }))] }, index))) })), _jsxs(Stack, { direction: "sm-row", align: "center", justify: "between", gap: "md", children: [_jsxs(Div, { className: themeConfig.spacingClass, children: [_jsxs(Row, { gap: "sm", wrap: true, children: [_jsx(Heading, { level: 2, className: themeConfig.titleClass, children: title }), badge && _jsx(Span, { className: "flex-shrink-0", children: badge })] }), subtitle && (_jsx(Text, { className: themeConfig.subtitleClass, children: subtitle })), description && (_jsx(Text, { className: "mt-1", color: "muted", size: "sm", children: description }))] }), actionLabel && onAction && (_jsxs(Button, { variant: "primary", onClick: onAction, disabled: actionDisabled, className: "flex-shrink-0", children: [actionIcon, actionLabel] }))] })] }));
14
14
  }
@@ -26,6 +26,7 @@ const adminProductFormSchema = z.object({
26
26
  import { apiClient } from "../../../http/index.js";
27
27
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints.js";
28
28
  import { ProductForm } from "../../products/components/ProductForm.js";
29
+ import { PriceGuidanceHint } from "../../categories/components/PriceGuidanceHint.js";
29
30
  import { normalizeListingType } from "../../products/utils/listing-type.js";
30
31
  import { ALL_LISTING_TYPES } from "../../../_internal/shared/listing-types/feature-flags.js";
31
32
  import { pluginFor } from "../../../_internal/shared/listing-types/_registry.js";
@@ -200,8 +201,22 @@ export function AdminProductEditorView({ productId, onSaved, onDeleted, embedded
200
201
  * determination — the seller forms deliberately omit it and
201
202
  * let `deriveTaxonomy` resolve it from the category.
202
203
  */
203
- canEditTax: true, renderGroupSettings: isEdit && productId
204
- ? (p) => (_jsx(GroupSettingsPanel, { productId: productId, productSlug: p.slug ?? productId, groupId: p.groupId, isGroupParent: p.isGroupParent, groupParentSlug: p.groupParentSlug, groupChildSlugs: p.groupChildSlugs, groupTitle: p.groupTitle, isAuction: modeFromProduct(p) === "auction", storeProductsEndpoint: ADMIN_ENDPOINTS.PRODUCTS, onGroupChanged: () => productQuery.refetch() }))
204
+ canEditTax: true, renderPriceGuidance: ({ categorySlug }) => categorySlug ? _jsx(PriceGuidanceHint, { categoryId: categorySlug }) : null, renderGroupSettings: isEdit && productId
205
+ ? (p) => (_jsx(GroupSettingsPanel, { productId: productId, productSlug: p.slug ?? productId, groupId: p.groupId, isGroupParent: p.isGroupParent, groupParentSlug: p.groupParentSlug, groupChildSlugs: p.groupChildSlugs, groupTitle: p.groupTitle,
206
+ /*
207
+ * Read straight off the product the editor is
208
+ * already showing — the rules live on the group
209
+ * PARENT and this panel is only mounted from the
210
+ * parent's own editor, so a second fetch would be a
211
+ * second source of truth for the same five fields.
212
+ */
213
+ groupRules: {
214
+ groupMinMembers: p.groupMinMembers,
215
+ groupMaxMembers: p.groupMaxMembers,
216
+ groupMaxUnitsPerMember: p.groupMaxUnitsPerMember,
217
+ groupRequiredMemberIds: p.groupRequiredMemberIds,
218
+ groupDiscountPercent: p.groupDiscountPercent,
219
+ }, isAuction: modeFromProduct(p) === "auction", storeProductsEndpoint: ADMIN_ENDPOINTS.PRODUCTS, onGroupChanged: () => productQuery.refetch() }))
205
220
  : undefined, renderGroupJoinField: ({ label, value, onChange, disabled }) => (_jsx(GroupInlineSelect, { scope: "admin", value: value ?? "", onChange: (id) => onChange(id || undefined), disabled: disabled, label: label, placeholder: "None (standalone product)", allowCreate: false })), renderCategorySelector: ({ label, value, onChange, disabled }) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "medium", color: "primary", children: label }), _jsx(PaginatedSelect, { value: value || null, onChange: (v) => onChange(v ?? ""), loadOptions: loadCategoryOptions, placeholder: "Search categories\u2026", searchPlaceholder: "Type category name\u2026", noResultsText: "No categories found", ariaLabel: label, disabled: disabled, createLabel: "Category", renderCreateForm: ({ onCreated, onCancel }) => (_jsx(CategoryQuickCreateForm, { onSaved: (id, name) => onCreated({ value: id, label: name }), onCancel: onCancel })) })] })), renderBrandSelector: (args) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "medium", color: "primary", children: args.label }), _jsx(PaginatedSelect, { value: args.multi ? null : (args.value || null), onChange: (v) => args.onValueChange(v ?? ""), loadOptions: loadBrandOptions, placeholder: "Search brands\u2026", searchPlaceholder: "Type brand name\u2026", noResultsText: "No brands found", ariaLabel: args.label, disabled: args.disabled, createLabel: "Brand", renderCreateForm: ({ onCreated, onCancel }) => (_jsx(BrandQuickCreateForm, { onSaved: (id, name) => onCreated({ value: id, label: name }), onCancel: onCancel })) })] })) })] })] }) })),
206
221
  },
207
222
  {
@@ -17,7 +17,7 @@ const __O = {
17
17
  function NavLink({ item, isActive, onClick }) {
18
18
  return (_jsxs(Link, { href: item.href, onClick: onClick, className: `flex items-center justify-end gap-[var(--appkit-space-2-5)] rounded-lg px-[var(--appkit-space-3)] py-[var(--appkit-space-2)] text-[0.8125rem] font-medium leading-tight transition-colors ${isActive
19
19
  ? "bg-[var(--appkit-color-surface)] bg-[var(--appkit-color-surface-elevated)] text-[var(--appkit-color-text)]"
20
- : "text-[var(--appkit-color-text-muted)] hover:bg-surface-hover hover:text-zinc-800 hover:text-[var(--appkit-color-text-muted)]"}`, children: [item.icon && _jsx(Span, { size: "base", className: "shrink-0 opacity-60", children: item.icon }), _jsx(Span, { className: "truncate", children: item.label })] }));
20
+ : "text-[var(--appkit-color-text-muted)] hover:bg-surface-hover hover:text-[var(--appkit-color-text)]"}`, children: [item.icon && _jsx(Span, { size: "base", className: "shrink-0 opacity-60", children: item.icon }), _jsx(Span, { className: "truncate", children: item.label })] }));
21
21
  }
22
22
  function GroupsContent({ groups, activePath, onItemClick, }) {
23
23
  // Accordion — only one group open at a time. Initial pick: the group