@mohasinac/appkit 4.30.18 → 4.31.0

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 (557) hide show
  1. package/dist/_internal/client/features/digital-code/CodeRevealPanel.js +5 -2
  2. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +3 -3
  3. package/dist/_internal/client/features/layout/useSidebarSearch.d.ts +21 -5
  4. package/dist/_internal/client/features/layout/useSidebarSearch.js +27 -6
  5. package/dist/_internal/client/features/lottery/LotteryAdminEditView.d.ts +23 -3
  6. package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +106 -86
  7. package/dist/_internal/client/features/lottery/LotteryPullForm.d.ts +16 -5
  8. package/dist/_internal/client/features/lottery/LotteryPullForm.js +65 -40
  9. package/dist/_internal/client/features/maintenance/views/AnalysisRunnerView.js +5 -2
  10. package/dist/_internal/client/features/maintenance/views/CloudLogsListView.js +11 -3
  11. package/dist/_internal/client/hand-mode/HandModeProvider.js +2 -0
  12. package/dist/_internal/server/features/auctions/actions.js +14 -3
  13. package/dist/_internal/server/features/auctions/service.js +1 -1
  14. package/dist/_internal/server/features/auth/permissions.d.ts +2 -0
  15. package/dist/_internal/server/features/auth/permissions.js +3 -2
  16. package/dist/_internal/server/features/blog/data.js +2 -2
  17. package/dist/_internal/server/features/blog/service.js +3 -3
  18. package/dist/_internal/server/features/brands/data.js +1 -1
  19. package/dist/_internal/server/features/brands/service.js +3 -3
  20. package/dist/_internal/server/features/bundles/actions.js +6 -1
  21. package/dist/_internal/server/features/bundles/data.js +21 -4
  22. package/dist/_internal/server/features/cart/data.js +3 -1
  23. package/dist/_internal/server/features/cart/service.js +13 -2
  24. package/dist/_internal/server/features/categories/data.js +26 -6
  25. package/dist/_internal/server/features/classified/index.d.ts +0 -1
  26. package/dist/_internal/server/features/classified/index.js +0 -1
  27. package/dist/_internal/server/features/digital-code/index.d.ts +0 -1
  28. package/dist/_internal/server/features/digital-code/index.js +0 -1
  29. package/dist/_internal/server/features/events/actions.js +17 -4
  30. package/dist/_internal/server/features/events/data.js +1 -1
  31. package/dist/_internal/server/features/events/service.js +1 -1
  32. package/dist/_internal/server/features/grouped/data.js +7 -2
  33. package/dist/_internal/server/features/item-requests/data.js +1 -1
  34. package/dist/_internal/server/features/live/index.d.ts +0 -1
  35. package/dist/_internal/server/features/live/index.js +0 -1
  36. package/dist/_internal/server/features/lottery/actions.js +2 -2
  37. package/dist/_internal/server/features/lottery/data.js +1 -1
  38. package/dist/_internal/server/features/orders/actions.js +7 -7
  39. package/dist/_internal/server/features/orders/data.d.ts +1 -1
  40. package/dist/_internal/server/features/orders/data.js +14 -2
  41. package/dist/_internal/server/features/orders/service.js +1 -1
  42. package/dist/_internal/server/features/pre-orders/service.js +1 -1
  43. package/dist/_internal/server/features/prize-draws/actions.js +1 -1
  44. package/dist/_internal/server/features/products/data.js +21 -6
  45. package/dist/_internal/server/features/products/list-public.d.ts +9 -0
  46. package/dist/_internal/server/features/products/list-public.js +95 -7
  47. package/dist/_internal/server/features/products/service.js +1 -1
  48. package/dist/_internal/server/features/promotions/actions.js +1 -1
  49. package/dist/_internal/server/features/promotions/data.js +1 -1
  50. package/dist/_internal/server/features/promotions/service.js +1 -1
  51. package/dist/_internal/server/features/reviews/data.d.ts +1 -1
  52. package/dist/_internal/server/features/reviews/data.js +6 -1
  53. package/dist/_internal/server/features/reviews/og-data.js +1 -1
  54. package/dist/_internal/server/features/shared/listing-data-factory.js +7 -2
  55. package/dist/_internal/server/features/site-settings/adapters.d.ts +2 -2
  56. package/dist/_internal/server/features/site-settings/adapters.js +8 -5
  57. package/dist/_internal/server/features/stores/data.js +1 -1
  58. package/dist/_internal/server/features/sublisting-categories/data.js +1 -1
  59. package/dist/_internal/server/features/tester/visibility.d.ts +2 -1
  60. package/dist/_internal/server/features/tester/visibility.js +2 -2
  61. package/dist/_internal/server/functions/scheduled.d.ts +3 -1
  62. package/dist/_internal/server/functions/scheduled.js +27 -1
  63. package/dist/_internal/server/jobs/core/auctionSettlement.js +6 -1
  64. package/dist/_internal/server/jobs/core/hardBanCascade.js +4 -0
  65. package/dist/_internal/server/jobs/core/index.d.ts +2 -0
  66. package/dist/_internal/server/jobs/core/index.js +2 -0
  67. package/dist/_internal/server/jobs/core/onOrderStatusChange.js +7 -15
  68. package/dist/_internal/server/jobs/core/pageViewPrune.d.ts +10 -0
  69. package/dist/_internal/server/jobs/core/pageViewPrune.js +44 -0
  70. package/dist/_internal/server/jobs/core/pageViewRollup.d.ts +2 -0
  71. package/dist/_internal/server/jobs/core/pageViewRollup.js +87 -0
  72. package/dist/_internal/server/jobs/core/revenueRollup.js +7 -1
  73. package/dist/_internal/server/jobs/handlers/index.d.ts +2 -0
  74. package/dist/_internal/server/jobs/handlers/index.js +2 -0
  75. package/dist/_internal/server/jobs/handlers/pageViewPrune.d.ts +2 -0
  76. package/dist/_internal/server/jobs/handlers/pageViewPrune.js +2 -0
  77. package/dist/_internal/server/jobs/handlers/pageViewRollup.d.ts +2 -0
  78. package/dist/_internal/server/jobs/handlers/pageViewRollup.js +2 -0
  79. package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
  80. package/dist/_internal/shared/actions/action-registry.js +69 -22
  81. package/dist/_internal/shared/checkout/rules/classified.rule.d.ts +9 -4
  82. package/dist/_internal/shared/checkout/rules/classified.rule.js +7 -2
  83. package/dist/_internal/shared/features/layout/matchesNavQuery.d.ts +14 -0
  84. package/dist/_internal/shared/features/layout/matchesNavQuery.js +72 -0
  85. package/dist/_internal/shared/features/layout/types.d.ts +37 -1
  86. package/dist/_internal/shared/features/layout/types.js +19 -1
  87. package/dist/_internal/shared/features/notifications/action-url.d.ts +9 -1
  88. package/dist/_internal/shared/features/notifications/action-url.js +47 -0
  89. package/dist/_internal/shared/features/offers/config.d.ts +65 -0
  90. package/dist/_internal/shared/features/offers/config.js +73 -2
  91. package/dist/_internal/shared/features/orders/schema.d.ts +19 -1
  92. package/dist/_internal/shared/features/orders/schema.js +22 -2
  93. package/dist/_internal/shared/features/site-settings/types.d.ts +12 -3
  94. package/dist/_internal/shared/listing-types/capabilities.d.ts +8 -2
  95. package/dist/_internal/shared/listing-types/capabilities.js +6 -1
  96. package/dist/_internal/shared/listing-types/classified/ctas.js +6 -1
  97. package/dist/_internal/shared/listing-types/feature-flags.d.ts +10 -5
  98. package/dist/_internal/shared/listing-types/feature-flags.js +11 -6
  99. package/dist/client/api/useApiQuery.js +17 -6
  100. package/dist/client.d.ts +38 -20
  101. package/dist/client.js +39 -14
  102. package/dist/configs/next.js +10 -2
  103. package/dist/constants/api-endpoints.d.ts +18 -54
  104. package/dist/constants/api-endpoints.js +6 -26
  105. package/dist/constants/field-names.d.ts +6 -24
  106. package/dist/constants/field-names.js +10 -27
  107. package/dist/constants/geo/countries.d.ts +50 -0
  108. package/dist/constants/geo/countries.js +129 -0
  109. package/dist/constants/geo/subdivisions.d.ts +13 -0
  110. package/dist/constants/geo/subdivisions.js +104 -0
  111. package/dist/constants/index.d.ts +2 -2
  112. package/dist/constants/index.js +2 -2
  113. package/dist/constants/table-keys.d.ts +24 -0
  114. package/dist/constants/table-keys.js +28 -0
  115. package/dist/contracts/client-realtime.d.ts +6 -0
  116. package/dist/contracts/extend.d.ts +0 -9
  117. package/dist/contracts/index.d.ts +1 -1
  118. package/dist/contracts/realtime-session.d.ts +12 -12
  119. package/dist/contracts/realtime-session.js +79 -77
  120. package/dist/core/browser.d.ts +1 -1
  121. package/dist/core/browser.js +1 -1
  122. package/dist/core/index.d.ts +1 -1
  123. package/dist/core/index.js +1 -1
  124. package/dist/core/site-config.d.ts +0 -3
  125. package/dist/core/site-config.js +0 -3
  126. package/dist/errors/index.d.ts +1 -1
  127. package/dist/errors/index.js +1 -1
  128. package/dist/errors/messages.d.ts +0 -8
  129. package/dist/errors/messages.js +0 -9
  130. package/dist/features/about/components/DeveloperView.js +7 -2
  131. package/dist/features/about/components/PolicyPageView.js +9 -1
  132. package/dist/features/about/components/PublicProfileView.js +23 -5
  133. package/dist/features/about/schemas/index.d.ts +8 -8
  134. package/dist/features/account/components/AddressFilters.js +32 -11
  135. package/dist/features/account/components/AddressForm.d.ts +26 -25
  136. package/dist/features/account/components/AddressForm.js +81 -103
  137. package/dist/features/account/components/AddressesIndexListing.js +8 -4
  138. package/dist/features/account/components/NotificationBell.js +4 -3
  139. package/dist/features/account/components/NotificationPreferencesPanel.js +1 -1
  140. package/dist/features/account/components/UserOffersPanel.js +1 -1
  141. package/dist/features/account/components/UserSidebar.d.ts +3 -4
  142. package/dist/features/account/components/UserSupportView.js +89 -58
  143. package/dist/features/account/components/index.d.ts +1 -7
  144. package/dist/features/account/components/index.js +0 -3
  145. package/dist/features/account/hooks/useAddresses.d.ts +4 -3
  146. package/dist/features/account/hooks/useAddresses.js +4 -6
  147. package/dist/features/account/hooks/useCollapsedSections.d.ts +51 -10
  148. package/dist/features/account/hooks/useCollapsedSections.js +211 -38
  149. package/dist/features/account/hooks/useProfile.d.ts +8 -0
  150. package/dist/features/account/index.d.ts +0 -3
  151. package/dist/features/account/index.js +0 -3
  152. package/dist/features/account/schemas/index.d.ts +0 -92
  153. package/dist/features/account/schemas/index.js +42 -20
  154. package/dist/features/addresses/components/AddressLocationFields.d.ts +13 -0
  155. package/dist/features/addresses/components/AddressLocationFields.js +41 -0
  156. package/dist/features/addresses/hooks/usePostalLookup.d.ts +17 -0
  157. package/dist/features/addresses/hooks/usePostalLookup.js +133 -0
  158. package/dist/features/addresses/schemas/address-form.d.ts +423 -0
  159. package/dist/features/addresses/schemas/address-form.js +212 -0
  160. package/dist/features/addresses/schemas/index.d.ts +1 -0
  161. package/dist/features/addresses/schemas/index.js +8 -0
  162. package/dist/features/admin/actions/admin-read-actions.d.ts +1 -1
  163. package/dist/features/admin/actions/index.d.ts +0 -1
  164. package/dist/features/admin/actions/index.js +0 -1
  165. package/dist/features/admin/actions/notification-actions.js +1 -41
  166. package/dist/features/admin/components/AdminActionIndexView.d.ts +32 -0
  167. package/dist/features/admin/components/AdminActionIndexView.js +128 -0
  168. package/dist/features/admin/components/AdminAdEditorView.js +159 -163
  169. package/dist/features/admin/components/AdminAddressEditorView.js +97 -55
  170. package/dist/features/admin/components/AdminBrandEditorView.d.ts +15 -0
  171. package/dist/features/admin/components/AdminBrandEditorView.js +113 -77
  172. package/dist/features/admin/components/AdminBundleEditorView.d.ts +19 -9
  173. package/dist/features/admin/components/AdminBundleEditorView.js +136 -168
  174. package/dist/features/admin/components/AdminCategoryEditorView.js +120 -43
  175. package/dist/features/admin/components/AdminCouponEditorView.js +145 -109
  176. package/dist/features/admin/components/AdminEmployeeEditorView.js +125 -56
  177. package/dist/features/admin/components/AdminFaqEditorView.js +112 -58
  178. package/dist/features/admin/components/AdminFeatureEditorView.js +108 -68
  179. package/dist/features/admin/components/AdminFulfillmentView.js +5 -2
  180. package/dist/features/admin/components/AdminMediaView.js +3 -3
  181. package/dist/features/admin/components/AdminNavEditorView.js +69 -44
  182. package/dist/features/admin/components/AdminOrderEditorView.js +47 -10
  183. package/dist/features/admin/components/AdminPrizeDrawsView.js +16 -2
  184. package/dist/features/admin/components/AdminSidebar.d.ts +11 -7
  185. package/dist/features/admin/components/AdminSiteSettingsView.js +37 -37
  186. package/dist/features/admin/components/AdminStoreEditorView.js +75 -52
  187. package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +71 -30
  188. package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +95 -65
  189. package/dist/features/admin/components/BrandQuickCreateForm.d.ts +10 -0
  190. package/dist/features/admin/components/BrandQuickCreateForm.js +49 -26
  191. package/dist/features/admin/components/CategoryQuickCreateForm.d.ts +11 -0
  192. package/dist/features/admin/components/CategoryQuickCreateForm.js +48 -26
  193. package/dist/features/admin/components/index.d.ts +2 -2
  194. package/dist/features/admin/components/index.js +1 -1
  195. package/dist/features/admin/constants/site-settings-tabs.d.ts +120 -0
  196. package/dist/features/admin/constants/site-settings-tabs.js +152 -0
  197. package/dist/features/admin/index.d.ts +0 -3
  198. package/dist/features/admin/index.js +0 -2
  199. package/dist/features/admin/repository/analytics-rollup.repository.d.ts +35 -0
  200. package/dist/features/admin/repository/analytics-rollup.repository.js +30 -0
  201. package/dist/features/admin/schemas/admin-editor-forms.d.ts +56 -57
  202. package/dist/features/admin/schemas/admin-editor-forms.js +97 -54
  203. package/dist/features/admin/schemas/admin-ops-forms.d.ts +57 -5
  204. package/dist/features/admin/schemas/admin-ops-forms.js +104 -20
  205. package/dist/features/admin/schemas/admin-user-form.js +7 -0
  206. package/dist/features/admin/schemas/firestore.d.ts +48 -95
  207. package/dist/features/admin/schemas/firestore.js +15 -151
  208. package/dist/features/admin/schemas/nav-item-form.js +9 -2
  209. package/dist/features/admin/server.d.ts +0 -4
  210. package/dist/features/admin/server.js +0 -2
  211. package/dist/features/admin/types/index.d.ts +0 -7
  212. package/dist/features/analytics/repository/page-views.repository.d.ts +14 -0
  213. package/dist/features/analytics/repository/page-views.repository.js +24 -0
  214. package/dist/features/analytics/types.d.ts +1 -1
  215. package/dist/features/analytics/types.js +13 -0
  216. package/dist/features/auctions/components/AuctionDetailPageView.js +6 -2
  217. package/dist/features/auctions/components/MarketplaceAuctionCard.js +3 -1
  218. package/dist/features/auth/actions/index.d.ts +0 -1
  219. package/dist/features/auth/actions/index.js +0 -1
  220. package/dist/features/auth/actions/profile-actions.js +4 -3
  221. package/dist/features/auth/actions/realtime-token-actions.js +1 -12
  222. package/dist/features/auth/auth-helpers.js +5 -7
  223. package/dist/features/auth/components/ForgotPasswordView.js +1 -1
  224. package/dist/features/auth/components/Guards.js +2 -1
  225. package/dist/features/auth/components/LoginForm.d.ts +0 -2
  226. package/dist/features/auth/components/LoginForm.js +2 -4
  227. package/dist/features/auth/components/RegisterForm.js +62 -19
  228. package/dist/features/auth/components/ResetPasswordView.js +1 -1
  229. package/dist/features/auth/hooks/useAuth.js +3 -0
  230. package/dist/features/auth/permissions/constants.d.ts +27 -1
  231. package/dist/features/auth/role-predicates.d.ts +75 -7
  232. package/dist/features/auth/role-predicates.js +28 -2
  233. package/dist/features/auth/schemas/firestore.d.ts +22 -0
  234. package/dist/features/auth/schemas/index.d.ts +1 -1
  235. package/dist/features/auth/schemas/index.js +44 -8
  236. package/dist/features/auth/types/index.d.ts +14 -1
  237. package/dist/features/blog/api/route.js +10 -2
  238. package/dist/features/blog/components/BlogIndexListing.js +1 -1
  239. package/dist/features/blog/hooks/useBlog.js +2 -2
  240. package/dist/features/blog/repository/blog.repository.js +3 -1
  241. package/dist/features/blog/schemas/index.d.ts +4 -0
  242. package/dist/features/blog/schemas/index.js +2 -0
  243. package/dist/features/blog/types/index.d.ts +1 -1
  244. package/dist/features/cart/actions/cart-actions.js +13 -4
  245. package/dist/features/cart/utils/pending-ops.js +1 -1
  246. package/dist/features/catalogue/components/CatalogueItemEditorView.d.ts +22 -0
  247. package/dist/features/catalogue/components/CatalogueItemEditorView.js +112 -52
  248. package/dist/features/catalogue/schemas/validation.d.ts +4 -4
  249. package/dist/features/catalogue/schemas/validation.js +47 -10
  250. package/dist/features/categories/components/BrandDetailPageView.js +28 -12
  251. package/dist/features/categories/components/CategoryDetailPageView.js +37 -20
  252. package/dist/features/categories/repository/categories.repository.js +3 -1
  253. package/dist/features/categories/schemas/bundle-form.d.ts +142 -0
  254. package/dist/features/categories/schemas/bundle-form.js +149 -0
  255. package/dist/features/checkout/actions/checkout-value-otp-actions.js +10 -1
  256. package/dist/features/classified/components/ClassifiedContactSellerPanel.js +1 -1
  257. package/dist/features/classified/components/ClassifiedDetailPageView.d.ts +5 -4
  258. package/dist/features/classified/components/ClassifiedDetailPageView.js +47 -18
  259. package/dist/features/consultation/components/ConsultationForm.js +1 -1
  260. package/dist/features/consultation/schemas/index.js +34 -10
  261. package/dist/features/corporate/schemas/index.js +36 -15
  262. package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +4 -1
  263. package/dist/features/events/components/EventBanner.js +5 -2
  264. package/dist/features/events/components/EventOfferCard.js +3 -1
  265. package/dist/features/events/components/EventPollWidget.js +1 -1
  266. package/dist/features/events/components/SpinWheelView.js +3 -2
  267. package/dist/features/filters/FilterPanel.js +3 -3
  268. package/dist/features/filters/RangeFilter.d.ts +10 -0
  269. package/dist/features/filters/RangeFilter.js +41 -4
  270. package/dist/features/grouped/components/GroupedListingEditorView.js +2 -1
  271. package/dist/features/history/hooks/useHistory.js +29 -27
  272. package/dist/features/homepage/components/AdSlot.js +3 -1
  273. package/dist/features/homepage/components/GoogleReviewsSection.js +8 -2
  274. package/dist/features/homepage/components/MarketplaceHomepageView.js +58 -15
  275. package/dist/features/homepage/components/SocialFeedSection.js +4 -1
  276. package/dist/features/homepage/hooks/useBlogArticles.js +1 -1
  277. package/dist/features/homepage/lib/live-stats.js +8 -1
  278. package/dist/features/homepage/repository/carousel.repository.js +2 -1
  279. package/dist/features/layout/BottomActions.js +84 -11
  280. package/dist/features/layout/BottomActionsContext.d.ts +1 -6
  281. package/dist/features/layout/BottomActionsContext.js +1 -1
  282. package/dist/features/layout/hooks/useBottomActions.js +2 -2
  283. package/dist/features/layout/hooks/useFormBottomActions.d.ts +12 -1
  284. package/dist/features/layout/hooks/useFormBottomActions.js +12 -6
  285. package/dist/features/live/components/LiveItemDetailPageView.js +4 -1
  286. package/dist/features/lottery/schemas/config-write.d.ts +9 -5
  287. package/dist/features/lottery/schemas/config-write.js +69 -9
  288. package/dist/features/media/finalize.js +3 -1
  289. package/dist/features/media/modals/ImageEditor.js +1 -1
  290. package/dist/features/media/modals/VideoThumbnailSelector.js +5 -2
  291. package/dist/features/media/modals/VideoTrimModal.js +5 -2
  292. package/dist/features/media/upload/MediaUploadField.js +2 -2
  293. package/dist/features/messages/hooks/useConversation.js +18 -4
  294. package/dist/features/messages/hooks/useConversations.js +25 -8
  295. package/dist/features/orders/components/RefundRequestView.js +5 -2
  296. package/dist/features/orders/schemas/buyer-forms.d.ts +6 -3
  297. package/dist/features/orders/schemas/buyer-forms.js +31 -3
  298. package/dist/features/orders/schemas/index.d.ts +2 -2
  299. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +3 -1
  300. package/dist/features/pre-orders/components/PreOrderActionsClient.js +1 -1
  301. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +4 -1
  302. package/dist/features/products/components/GroupSettingsPanel.js +3 -1
  303. package/dist/features/products/components/MakeOfferButton.d.ts +13 -2
  304. package/dist/features/products/components/MakeOfferButton.js +33 -11
  305. package/dist/features/products/components/PrizeDrawDetailPageView.js +4 -1
  306. package/dist/features/products/components/ProductDetailActions.js +0 -1
  307. package/dist/features/products/components/ProductDetailPageView.d.ts +7 -3
  308. package/dist/features/products/components/ProductDetailPageView.js +16 -7
  309. package/dist/features/products/components/ShareButton.js +3 -1
  310. package/dist/features/products/constants/action-defs.d.ts +1 -2
  311. package/dist/features/products/constants/action-defs.js +40 -43
  312. package/dist/features/products/repository/loadProductFeatures.js +10 -2
  313. package/dist/features/products/repository/products.repository.d.ts +5 -1
  314. package/dist/features/products/repository/products.repository.js +25 -2
  315. package/dist/features/products/schemas/firestore.d.ts +7 -3
  316. package/dist/features/products/schemas/product-features.validators.js +3 -0
  317. package/dist/features/promotions/components/CouponCard.js +11 -8
  318. package/dist/features/reviews/actions/review-actions.js +8 -1
  319. package/dist/features/reviews/components/ReviewDetailPageView.js +13 -3
  320. package/dist/features/reviews/components/ReviewDetailShell.js +3 -1
  321. package/dist/features/scams/actions/scam-actions.d.ts +9 -1
  322. package/dist/features/scams/actions/scam-actions.js +52 -12
  323. package/dist/features/scams/components/SellerTrustBadge.d.ts +1 -1
  324. package/dist/features/scams/components/SellerTrustBadge.js +13 -0
  325. package/dist/features/scams/repository/scammer.repository.js +2 -1
  326. package/dist/features/scams/schemas/firestore.d.ts +15 -1
  327. package/dist/features/scams/schemas/report-form.d.ts +5 -5
  328. package/dist/features/scams/schemas/report-form.js +18 -3
  329. package/dist/features/search/action-index/derive.d.ts +49 -0
  330. package/dist/features/search/action-index/derive.js +121 -0
  331. package/dist/features/search/action-index/repository.d.ts +42 -0
  332. package/dist/features/search/action-index/repository.js +100 -0
  333. package/dist/features/search/action-index/settings-entries.d.ts +41 -0
  334. package/dist/features/search/action-index/settings-entries.js +268 -0
  335. package/dist/features/search/action-index/types.d.ts +81 -0
  336. package/dist/features/search/action-index/types.js +102 -0
  337. package/dist/features/search/action-index/validate-entry.d.ts +34 -0
  338. package/dist/features/search/action-index/validate-entry.js +114 -0
  339. package/dist/features/search/hooks/useNavSuggestions.d.ts +5 -1
  340. package/dist/features/search/hooks/useNavSuggestions.js +23 -3
  341. package/dist/features/search/repository/search.repository.js +3 -1
  342. package/dist/features/seller/actions/offer-actions.js +43 -19
  343. package/dist/features/seller/actions/seller-actions.js +29 -5
  344. package/dist/features/seller/components/CategoryChipPicker.d.ts +9 -0
  345. package/dist/features/seller/components/CategoryChipPicker.js +12 -0
  346. package/dist/features/seller/components/FulfillmentView.js +5 -2
  347. package/dist/features/seller/components/PhysicalLocationModal.js +1 -1
  348. package/dist/features/seller/components/PrintCenterView.js +3 -1
  349. package/dist/features/seller/components/SellerAddressesView.js +5 -1
  350. package/dist/features/seller/components/SellerAnalyticsAlertsView.js +83 -43
  351. package/dist/features/seller/components/SellerArtView.d.ts +14 -7
  352. package/dist/features/seller/components/SellerArtView.js +4 -119
  353. package/dist/features/seller/components/SellerBidsView.js +1 -1
  354. package/dist/features/seller/components/SellerClassifiedView.d.ts +14 -7
  355. package/dist/features/seller/components/SellerClassifiedView.js +4 -124
  356. package/dist/features/seller/components/SellerCouponEditorView.d.ts +22 -1
  357. package/dist/features/seller/components/SellerCouponEditorView.js +91 -45
  358. package/dist/features/seller/components/SellerCouponsView.js +1 -1
  359. package/dist/features/seller/components/SellerDigitalCodesView.d.ts +14 -7
  360. package/dist/features/seller/components/SellerDigitalCodesView.js +4 -126
  361. package/dist/features/seller/components/SellerGoogleReviewsView.js +2 -2
  362. package/dist/features/seller/components/SellerListingTypeView.d.ts +66 -0
  363. package/dist/features/seller/components/SellerListingTypeView.js +277 -0
  364. package/dist/features/seller/components/SellerLiveView.d.ts +14 -7
  365. package/dist/features/seller/components/SellerLiveView.js +4 -126
  366. package/dist/features/seller/components/SellerOrdersView.js +3 -3
  367. package/dist/features/seller/components/SellerPayoutMethodsView.js +2 -2
  368. package/dist/features/seller/components/SellerProductShell.d.ts +5 -0
  369. package/dist/features/seller/components/SellerProductShell.js +15 -5
  370. package/dist/features/seller/components/SellerProductsView.js +24 -10
  371. package/dist/features/seller/components/SellerReviewsView.js +47 -16
  372. package/dist/features/seller/components/SellerShippingConfigsView.js +5 -4
  373. package/dist/features/seller/components/SellerSidebar.d.ts +3 -6
  374. package/dist/features/seller/components/SellerStickersView.d.ts +14 -7
  375. package/dist/features/seller/components/SellerStickersView.js +4 -119
  376. package/dist/features/seller/components/SellerStoreCategoriesView.js +3 -2
  377. package/dist/features/seller/components/SellerSupportView.d.ts +31 -0
  378. package/dist/features/seller/components/SellerSupportView.js +100 -0
  379. package/dist/features/seller/components/index.d.ts +4 -8
  380. package/dist/features/seller/components/index.js +2 -4
  381. package/dist/features/seller/index.d.ts +0 -1
  382. package/dist/features/seller/index.js +0 -1
  383. package/dist/features/seller/schemas/coupon-form.d.ts +214 -0
  384. package/dist/features/seller/schemas/coupon-form.js +155 -23
  385. package/dist/features/seller/schemas/offer-forms.d.ts +16 -7
  386. package/dist/features/seller/schemas/offer-forms.js +28 -12
  387. package/dist/features/shell/FormShell.js +2 -2
  388. package/dist/features/shell/QuickFormDrawer.js +2 -2
  389. package/dist/features/shell/SectionForm.d.ts +19 -1
  390. package/dist/features/shell/SectionForm.js +104 -17
  391. package/dist/features/shell/build-sections.d.ts +23 -0
  392. package/dist/features/shell/build-sections.js +106 -8
  393. package/dist/features/shell/field-ui-meta.d.ts +44 -0
  394. package/dist/features/shell/field-ui-meta.js +14 -7
  395. package/dist/features/shell/form-sections.d.ts +46 -0
  396. package/dist/features/shell/form-sections.js +114 -0
  397. package/dist/features/shipments/components/AdminShipmentEditorView.js +87 -64
  398. package/dist/features/shipments/schemas/validation.d.ts +2 -2
  399. package/dist/features/shipments/schemas/validation.js +44 -13
  400. package/dist/features/store-extensions/schemas/custom-role-form.js +6 -2
  401. package/dist/features/store-extensions/schemas/listing-template-form.d.ts +7 -7
  402. package/dist/features/store-extensions/schemas/payout-method-form.js +14 -0
  403. package/dist/features/stores/actions/store-query-actions.js +3 -2
  404. package/dist/features/stores/api/[storeSlug]/auctions/route.js +3 -1
  405. package/dist/features/stores/api/[storeSlug]/products/route.js +3 -1
  406. package/dist/features/stores/components/StoreDetailLayoutView.d.ts +1 -1
  407. package/dist/features/stores/components/StoreDetailLayoutView.js +12 -3
  408. package/dist/features/support/repository/support.repository.d.ts +21 -0
  409. package/dist/features/support/repository/support.repository.js +63 -0
  410. package/dist/features/support/schemas/firestore.d.ts +27 -2
  411. package/dist/features/support/schemas/firestore.js +2 -0
  412. package/dist/features/support/schemas/ticket-create-form.js +7 -0
  413. package/dist/features/tester/schemas/checklist-item-form.d.ts +43 -0
  414. package/dist/features/tester/schemas/checklist-item-form.js +109 -0
  415. package/dist/features/tester/seed-data/blog-tester-seed-data.js +2 -2
  416. package/dist/features/tester/seed-data/categories-tester-seed-data.js +2 -2
  417. package/dist/features/tester/seed-data/events-tester-seed-data.js +5 -5
  418. package/dist/features/tester/seed-data/orders-tester-seed-data.js +2 -2
  419. package/dist/features/tester/seed-data/products-tester-seed-data.js +48 -49
  420. package/dist/features/tester/seed-data/stores-tester-seed-data.js +3 -3
  421. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +291 -30
  422. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +51 -14
  423. package/dist/features/wishlist/hooks/useWishlistToggle.js +8 -1
  424. package/dist/http/api-handler.js +2 -1
  425. package/dist/index.d.ts +25 -104
  426. package/dist/index.js +38 -143
  427. package/dist/jobs.d.ts +1 -1
  428. package/dist/jobs.js +1 -1
  429. package/dist/monitoring/browser.d.ts +0 -2
  430. package/dist/monitoring/browser.js +12 -1
  431. package/dist/monitoring/index.d.ts +0 -2
  432. package/dist/monitoring/index.js +0 -1
  433. package/dist/next/api/routeHandler.js +9 -4
  434. package/dist/next/index.d.ts +1 -2
  435. package/dist/next/index.js +0 -1
  436. package/dist/next/middleware/index.d.ts +0 -2
  437. package/dist/next/middleware/index.js +0 -1
  438. package/dist/next/routing/route-map.d.ts +8 -7
  439. package/dist/next/routing/route-map.js +10 -3
  440. package/dist/providers/auth-firebase/session.js +3 -1
  441. package/dist/providers/db-firebase/admin-app-lite.js +8 -8
  442. package/dist/providers/db-firebase/admin.js +27 -13
  443. package/dist/providers/db-firebase/browser-stub.d.ts +1 -11
  444. package/dist/providers/db-firebase/browser-stub.js +6 -11
  445. package/dist/providers/db-firebase/index.d.ts +0 -1
  446. package/dist/providers/db-firebase/index.js +0 -1
  447. package/dist/providers/db-firebase/rtdb-paths.d.ts +15 -6
  448. package/dist/providers/db-firebase/rtdb-paths.js +15 -6
  449. package/dist/providers/db-firebase/rtdb-url.d.ts +27 -0
  450. package/dist/providers/db-firebase/rtdb-url.js +50 -0
  451. package/dist/providers/db-firebase/sieve.d.ts +22 -0
  452. package/dist/providers/firebase-client/realtime.d.ts +20 -0
  453. package/dist/providers/firebase-client/realtime.js +34 -1
  454. package/dist/providers.d.ts +1 -1
  455. package/dist/providers.js +1 -1
  456. package/dist/react/hooks/use-action-dispatch.js +8 -2
  457. package/dist/react/hooks/useFormStatePreservation.js +3 -1
  458. package/dist/react/hooks/useListingTypeFlags.d.ts +1 -1
  459. package/dist/react/hooks/useListingTypeFlags.js +1 -1
  460. package/dist/react/hooks/usePendingFilters.js +5 -3
  461. package/dist/react/hooks/usePendingTable.js +15 -3
  462. package/dist/react/hooks/useRealtimeEvent.js +20 -9
  463. package/dist/repositories/index.d.ts +0 -1
  464. package/dist/repositories/index.js +0 -1
  465. package/dist/schemas/registry.d.ts +197 -232
  466. package/dist/schemas/registry.js +5 -6
  467. package/dist/schemas/webhooks/razorpay.d.ts +50 -50
  468. package/dist/security/authorization.d.ts +9 -0
  469. package/dist/security/authorization.js +16 -2
  470. package/dist/security/browser.d.ts +1 -3
  471. package/dist/security/browser.js +5 -2
  472. package/dist/security/index.d.ts +1 -3
  473. package/dist/security/index.js +19 -2
  474. package/dist/security/pii-encrypt.js +16 -0
  475. package/dist/security/pii-schemas.d.ts +0 -14
  476. package/dist/security/pii-schemas.js +7 -15
  477. package/dist/seed/_helpers/category-forest.js +2 -2
  478. package/dist/seed/_helpers/media.d.ts +19 -0
  479. package/dist/seed/_helpers/media.js +75 -0
  480. package/dist/seed/blog-posts-seed-data.js +17 -17
  481. package/dist/seed/carousel-slides-seed-data.js +7 -7
  482. package/dist/seed/cart-seed-data.js +13 -13
  483. package/dist/seed/categories-seed-data.js +10 -10
  484. package/dist/seed/events-seed-data.js +24 -24
  485. package/dist/seed/factories/product.factory.js +4 -4
  486. package/dist/seed/factories/store.factory.js +3 -3
  487. package/dist/seed/factories/user.factory.js +2 -2
  488. package/dist/seed/grouped-listings-seed-data.js +11 -11
  489. package/dist/seed/homepage-sections-seed-data.js +2 -2
  490. package/dist/seed/index.d.ts +0 -1
  491. package/dist/seed/index.js +0 -1
  492. package/dist/seed/manifest.d.ts +1 -1
  493. package/dist/seed/manifest.js +0 -5
  494. package/dist/seed/notifications-seed-data.js +20 -1
  495. package/dist/seed/orders-seed-data.js +2 -2
  496. package/dist/seed/products-art-seed-data.js +16 -16
  497. package/dist/seed/products-auctions-seed-data.js +34 -34
  498. package/dist/seed/products-classifieds-seed-data.js +35 -37
  499. package/dist/seed/products-digital-codes-seed-data.js +20 -20
  500. package/dist/seed/products-live-items-seed-data.js +11 -11
  501. package/dist/seed/products-preorders-seed-data.js +13 -13
  502. package/dist/seed/products-prize-draws-seed-data.js +43 -43
  503. package/dist/seed/products-standard-seed-data.js +54 -54
  504. package/dist/seed/products-stickers-seed-data.js +15 -15
  505. package/dist/seed/reviews-seed-data.js +4 -4
  506. package/dist/seed/scammers-seed-data.js +3 -3
  507. package/dist/seed/site-settings-seed-data.js +11 -24
  508. package/dist/seed/store-extensions-seed-data.js +10 -10
  509. package/dist/seed/stores-seed-data.js +11 -11
  510. package/dist/seed/support-tickets-seed-data.d.ts +14 -0
  511. package/dist/seed/support-tickets-seed-data.js +20 -1
  512. package/dist/seed/users-seed-data.js +20 -20
  513. package/dist/server-entry.d.ts +0 -1
  514. package/dist/server-entry.js +0 -1
  515. package/dist/server.d.ts +9 -6
  516. package/dist/server.js +7 -13
  517. package/dist/styles.css +248 -68
  518. package/dist/tailwind-utilities.css +1 -1
  519. package/dist/tokens/themes/default-dark.js +2 -2
  520. package/dist/tokens/themes/default-light.js +2 -2
  521. package/dist/tokens/tokens.css +24 -4
  522. package/dist/ui/components/ActionRow.d.ts +50 -0
  523. package/dist/ui/components/ActionRow.js +53 -0
  524. package/dist/ui/components/ActionRow.style.css +145 -0
  525. package/dist/ui/components/Drawer.d.ts +10 -0
  526. package/dist/ui/components/Drawer.js +2 -1
  527. package/dist/ui/components/FilterDrawer.js +4 -1
  528. package/dist/ui/components/FilterDrawer.style.css +6 -12
  529. package/dist/ui/components/FormActionBar.js +14 -1
  530. package/dist/ui/components/FormActionBar.style.css +12 -11
  531. package/dist/ui/components/ListingLayout.js +8 -1
  532. package/dist/ui/components/ListingLayout.style.css +6 -13
  533. package/dist/ui/components/Modal.d.ts +15 -1
  534. package/dist/ui/components/Modal.js +17 -3
  535. package/dist/ui/components/QuickCreateModal.js +2 -2
  536. package/dist/ui/components/QuickCreateModal.style.css +78 -84
  537. package/dist/ui/components/RecordDetailModal.js +2 -2
  538. package/dist/ui/components/SideDrawer.d.ts +8 -0
  539. package/dist/ui/components/SideDrawer.js +2 -1
  540. package/dist/ui/components/SideDrawer.style.css +6 -3
  541. package/dist/ui/components/SideModal.d.ts +11 -1
  542. package/dist/ui/components/SideModal.js +3 -2
  543. package/dist/ui/components/SideModal.style.css +14 -0
  544. package/dist/ui/components/Typography.style.css +33 -24
  545. package/dist/ui/components/index.style.css +1 -0
  546. package/dist/ui/components/toolbar-collapse.js +1 -2
  547. package/dist/ui/forms/FormShell.style.css +260 -311
  548. package/dist/ui/index.d.ts +2 -0
  549. package/dist/ui/index.js +1 -0
  550. package/dist/utils/index.d.ts +0 -1
  551. package/dist/utils/index.js +0 -1
  552. package/dist/validation/index.d.ts +1 -1
  553. package/dist/validation/index.js +1 -1
  554. package/dist/validation/schemas.d.ts +0 -19
  555. package/dist/validation/schemas.js +8 -19
  556. package/package.json +1 -1
  557. package/scripts/seed-cli.mjs +3 -6
@@ -7,6 +7,7 @@ import { Badge } from "../../ui/components/Badge";
7
7
  import { Div, Row, Span, Stack } from "../../ui";
8
8
  import { FormShellContext } from "../../ui/forms/FormShell";
9
9
  import { useFormBottomActions } from "../layout/hooks/useFormBottomActions";
10
+ import { useSectionState } from "../account/hooks/useCollapsedSections";
10
11
  import { FormSchemaContext } from "./FormShell";
11
12
  /** Sections in render order: required first, original order preserved within each group. */
12
13
  export function orderSections(sections) {
@@ -25,36 +26,62 @@ export function buildFieldToSectionIndex(ordered) {
25
26
  * `fieldToSectionIndex` into `useFormShellState(schema, nav)` and `openIds`
26
27
  * back into `<SectionForm>`.
27
28
  */
28
- export function useSectionFormNav(sections, values) {
29
+ export function useSectionFormNav(sections, values, opts) {
29
30
  const ordered = useMemo(() => {
30
31
  const visible = values
31
32
  ? sections.filter((s) => (s.when ? s.when(values) : true))
32
33
  : sections;
33
34
  return orderSections(visible);
34
35
  }, [sections, values]);
35
- const [openIds, setOpenIds] = useState(() => orderSections(sections).filter((s) => s.required).map((s) => s.id));
36
+ const sectionIds = useMemo(() => ordered.map((s) => s.id), [ordered]);
37
+ const defaultOpen = useMemo(() => ordered.filter((s) => s.required).map((s) => s.id), [ordered]);
38
+ /*
39
+ * The open set is `useSectionState`, not a local `useState` — which is what
40
+ * makes "expand section 3, reload, find it still expanded" true. `scope: ""`
41
+ * (the default) is EPHEMERAL: identical in-memory behaviour to the previous
42
+ * `useState`, so the seven existing call sites are unchanged until each names
43
+ * a durable scope. Without that opt-out every unnamed form would share one
44
+ * `sectionState[""]` entry and fight over it.
45
+ */
46
+ const { openIds, setOpenIds, open } = useSectionState({
47
+ scope: opts?.scope ?? "",
48
+ sectionIds,
49
+ defaultOpen,
50
+ mode: "multi",
51
+ });
36
52
  const fieldToSectionIndex = useMemo(() => buildFieldToSectionIndex(ordered), [ordered]);
37
53
  const sectionMeta = useMemo(() => ordered.map((s) => ({ id: s.id, label: s.label, requiredFields: s.fields })), [ordered]);
38
54
  const goToSection = useCallback((index) => {
39
55
  const target = ordered[index];
40
56
  if (!target)
41
57
  return;
42
- setOpenIds((prev) => (prev.includes(target.id) ? prev : [...prev, target.id]));
43
- // The panel must MOUNT before it can be scrolled to — expanding is a state
44
- // update, so defer a frame. Without this the scroll lands on a zero-height
45
- // collapsed header and the offending field stays off-screen.
46
- requestAnimationFrame(() => {
47
- const el = document.getElementById(sectionAnchorId(target.id));
48
- el?.scrollIntoView({ behavior: "smooth", block: "start" });
49
- el?.querySelector("[aria-invalid='true']")?.focus();
50
- });
51
- }, [ordered]);
58
+ open(target.id);
59
+ scrollToSection(target.id);
60
+ }, [ordered, open]);
52
61
  return { ordered, openIds, setOpenIds, goToSection, fieldToSectionIndex, sectionMeta };
53
62
  }
54
63
  /** DOM id for a section panel — kept in one place so nav and render agree. */
55
64
  export function sectionAnchorId(id) {
56
65
  return `section-${id}`;
57
66
  }
67
+ /**
68
+ * Scroll a section into view and focus the first invalid control inside it.
69
+ *
70
+ * Deliberately module-level and shared by `goToSection` and `SectionForm`'s own
71
+ * submit handler: the deferred frame is the load-bearing part and is easy to
72
+ * drop when copying. The panel must MOUNT before it can be scrolled to —
73
+ * expanding is a state update, so without the deferral the scroll lands on a
74
+ * zero-height collapsed header and the offending field stays off-screen.
75
+ */
76
+ export function scrollToSection(id) {
77
+ if (typeof document === "undefined")
78
+ return;
79
+ requestAnimationFrame(() => {
80
+ const el = document.getElementById(sectionAnchorId(id));
81
+ el?.scrollIntoView({ behavior: "smooth", block: "start" });
82
+ el?.querySelector("[aria-invalid='true']")?.focus();
83
+ });
84
+ }
58
85
  export function SectionForm({ sections, values, onChange, onSubmit, submitLabel = "Save", isLoading = false, schema, openIds: controlledOpenIds, onOpenChange, expandMode = "multi", hideActions = false, destructiveAction, onValidationChange, onCancel, cancelLabel, bottomBar = true, }) {
59
86
  const inheritedSchema = useContext(FormSchemaContext);
60
87
  /*
@@ -66,6 +93,18 @@ export function SectionForm({ sections, values, onChange, onSubmit, submitLabel
66
93
  const shellCtx = useContext(FormShellContext);
67
94
  const [fieldErrors, setFieldErrors] = useState({});
68
95
  const [uncontrolledOpenIds, setUncontrolledOpenIds] = useState(() => orderSections(sections).filter((s) => s.required).map((s) => s.id));
96
+ /*
97
+ * Sections held open because they hold a validation error, kept SEPARATE
98
+ * from `openIds`.
99
+ *
100
+ * Under `expandMode: "single"` the open set is an accordion — opening any
101
+ * other section replaces it — so a section revealed by a failed submit would
102
+ * be collapsed again by the user's very next click, hiding the error they
103
+ * were sent to fix. This set is unioned into the rendered state and is pruned
104
+ * per-section as each one's errors clear (below), so it can never wedge a
105
+ * section open once it is valid.
106
+ */
107
+ const [forceOpenIds, setForceOpenIds] = useState([]);
69
108
  const ordered = useMemo(() => orderSections(sections.filter((s) => (s.when ? s.when(values) : true))), [sections, values]);
70
109
  const openIds = controlledOpenIds ?? uncontrolledOpenIds;
71
110
  const setOpenIds = useCallback((ids) => {
@@ -79,6 +118,15 @@ export function SectionForm({ sections, values, onChange, onSubmit, submitLabel
79
118
  // validator on every render and re-fire the effect below in a loop.
80
119
  const onValidationChangeRef = useRef(onValidationChange);
81
120
  onValidationChangeRef.current = onValidationChange;
121
+ /** Section ids holding at least one error, in render order. */
122
+ const erroringSectionIds = useCallback((errs) => {
123
+ const keys = Object.keys(errs);
124
+ if (keys.length === 0)
125
+ return [];
126
+ return ordered
127
+ .filter((s) => s.fields?.some((f) => keys.some((k) => k === f || k.startsWith(`${f}.`))))
128
+ .map((s) => s.id);
129
+ }, [ordered]);
82
130
  const runValidation = useCallback((nextValues) => {
83
131
  const activeSchema = schema ?? inheritedSchema;
84
132
  if (!activeSchema)
@@ -89,6 +137,7 @@ export function SectionForm({ sections, values, onChange, onSubmit, submitLabel
89
137
  const parsed = activeSchema.safeParse(nextValues);
90
138
  if (parsed.success) {
91
139
  setFieldErrors({});
140
+ setForceOpenIds([]);
92
141
  onValidationChangeRef.current?.({}, fieldToSectionIndex);
93
142
  return;
94
143
  }
@@ -99,8 +148,16 @@ export function SectionForm({ sections, values, onChange, onSubmit, submitLabel
99
148
  next[issue.path.map(String).join(".")] = issue.message;
100
149
  }
101
150
  setFieldErrors(next);
151
+ // Release a force-opened section as soon as ITS OWN errors clear, rather
152
+ // than waiting for the whole form to become valid — otherwise fixing
153
+ // section 1 leaves it pinned open while the user works through section 5.
154
+ const stillBad = new Set(erroringSectionIds(next));
155
+ setForceOpenIds((prev) => {
156
+ const kept = prev.filter((id) => stillBad.has(id));
157
+ return kept.length === prev.length ? prev : kept;
158
+ });
102
159
  onValidationChangeRef.current?.(next, fieldToSectionIndex);
103
- }, [schema, inheritedSchema, fieldToSectionIndex]);
160
+ }, [schema, inheritedSchema, fieldToSectionIndex, erroringSectionIds]);
104
161
  useEffect(() => {
105
162
  runValidation(values);
106
163
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -116,8 +173,27 @@ export function SectionForm({ sections, values, onChange, onSubmit, submitLabel
116
173
  */
117
174
  const handleSubmit = useCallback(() => {
118
175
  shellCtx?.markSubmitAttempted();
176
+ /*
177
+ * Reveal the FIRST offending section — only the first. Expanding all five
178
+ * at once loses the user's place, and the per-section error badge already
179
+ * points at the rest.
180
+ *
181
+ * This is additive: `onSubmit` still fires exactly as before, so a caller
182
+ * that does its own parse or lets the server decide is unaffected. Blocking
183
+ * here would change behaviour for all thirteen call sites, and `fieldErrors`
184
+ * is only ever populated when a schema is present — a schema-less form
185
+ * finds nothing to expand and falls straight through.
186
+ */
187
+ const [firstBadId] = erroringSectionIds(fieldErrors);
188
+ if (firstBadId) {
189
+ setForceOpenIds((prev) => (prev.includes(firstBadId) ? prev : [...prev, firstBadId]));
190
+ if (!openIds.includes(firstBadId)) {
191
+ setOpenIds(expandMode === "single" ? [firstBadId] : [...openIds, firstBadId]);
192
+ }
193
+ scrollToSection(firstBadId);
194
+ }
119
195
  void onSubmit();
120
- }, [shellCtx, onSubmit]);
196
+ }, [shellCtx, onSubmit, erroringSectionIds, fieldErrors, openIds, setOpenIds, expandMode]);
121
197
  useFormBottomActions({
122
198
  onSubmit: handleSubmit,
123
199
  onCancel,
@@ -128,13 +204,22 @@ export function SectionForm({ sections, values, onChange, onSubmit, submitLabel
128
204
  enabled: bottomBar && !hideActions,
129
205
  });
130
206
  const toggle = useCallback((id) => {
131
- const isOpen = openIds.includes(id);
207
+ /*
208
+ * A DIRECT click on the header always wins. `forceOpenIds` exists to
209
+ * survive an INDIRECT collapse — the accordion closing this section because
210
+ * a sibling was opened — not to make the header unresponsive. Leaving the
211
+ * id in the set here would mean clicking a section holding an error does
212
+ * visibly nothing, which reads as a broken control and is worse than the
213
+ * hidden error it was protecting against.
214
+ */
215
+ setForceOpenIds((prev) => (prev.includes(id) ? prev.filter((x) => x !== id) : prev));
216
+ const isOpen = openIds.includes(id) || forceOpenIds.includes(id);
132
217
  if (expandMode === "single") {
133
218
  setOpenIds(isOpen ? [] : [id]);
134
219
  return;
135
220
  }
136
221
  setOpenIds(isOpen ? openIds.filter((x) => x !== id) : [...openIds, id]);
137
- }, [openIds, expandMode, setOpenIds]);
222
+ }, [openIds, forceOpenIds, expandMode, setOpenIds]);
138
223
  const errorCountFor = useCallback((section) => {
139
224
  if (!section.fields?.length)
140
225
  return 0;
@@ -144,7 +229,9 @@ export function SectionForm({ sections, values, onChange, onSubmit, submitLabel
144
229
  const isRequired = section.required === true;
145
230
  // A required section is always open — it holds the fields without
146
231
  // which the record cannot be saved, so hiding it is never useful.
147
- const isCollapsed = isRequired ? false : !openIds.includes(section.id);
232
+ const isCollapsed = isRequired
233
+ ? false
234
+ : !(openIds.includes(section.id) || forceOpenIds.includes(section.id));
148
235
  const errorCount = errorCountFor(section);
149
236
  return (_jsx(CollapsibleSection, { id: sectionAnchorId(section.id), title: _jsxs(Row, { align: "center", gap: "xs", children: [_jsx(Span, { weight: "semibold", size: "sm", children: section.heading ?? section.label }), isRequired && _jsx(Span, { size: "xs", color: "muted", children: "Required" })] }), isCollapsed: isCollapsed, onToggle: () => { if (!isRequired)
150
237
  toggle(section.id); }, keepMounted: section.keepMounted, renderHeaderExtra: errorCount > 0
@@ -53,6 +53,29 @@ export declare function groupFieldsBySection(fields: ResolvedField[]): Map<strin
53
53
  * make a clean 2-up, a `pair` next to a `quarter` makes neither.
54
54
  */
55
55
  export declare function packRows(fields: ResolvedField[]): ResolvedField[][];
56
+ /**
57
+ * The draft, minus every field whose `when` predicate says it is not on screen.
58
+ *
59
+ * ## Why this exists, and why it is not optional
60
+ *
61
+ * A `when` predicate hides a CONTROL; it does not clear the value behind it.
62
+ * So a form that renders conditionally and submits `{...draft}` sends whatever
63
+ * the user typed before they switched the option away — the control is gone
64
+ * from the screen and its value is still in the payload.
65
+ *
66
+ * That is not hypothetical. Four of the twenty dead controls found in the W3c
67
+ * sweep were exactly this: a cap typed on a percentage coupon persisted after
68
+ * switching to free-shipping; a lottery slot price written under uniform
69
+ * pricing; an AdSense slot shipped with a manually-authored ad. Each looked
70
+ * right on screen and saved something else.
71
+ *
72
+ * Build the payload from THIS, not from the draft, and hidden-implies-not-sent
73
+ * holds by construction rather than by remembering.
74
+ *
75
+ * Fields with no `when` are always kept, so a schema with no conditionals gets
76
+ * its draft back unchanged and the call is free.
77
+ */
78
+ export declare function visibleValues<T extends object>(schema: ZodTypeAny, values: T): Partial<T>;
56
79
  /**
57
80
  * Build the `SectionDef[]` a `<SectionForm>` renders.
58
81
  *
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  /*
4
4
  * WHY: A `SectionDef[]` written by hand is a second source of truth that has to
5
5
  * stay aligned with the schema that validates it. Nothing enforces the
@@ -34,14 +34,18 @@ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
34
34
  * @tag consumers:SectionForm callsites
35
35
  * @tag sideEffects:none
36
36
  */
37
+ import { groupRank, resolveSectionGroup } from "./form-sections";
37
38
  import { Fragment } from "react";
38
39
  import { FormGroup } from "../../ui/components/Form";
40
+ import { PaginatedSelect } from "../../ui/components/PaginatedSelect";
41
+ import { Stack } from "../../ui/components/Layout";
42
+ import { Text } from "../../ui/components/Typography";
39
43
  import { FieldInput } from "../../ui/forms/FieldInput";
40
44
  import { FieldSelect } from "../../ui/forms/FieldSelect";
41
45
  import { FieldTextarea } from "../../ui/forms/FieldTextarea";
42
46
  import { FieldCheckbox } from "../../ui/forms/FieldCheckbox";
43
47
  import { humaniseFieldName } from "./entity-form";
44
- import { ROW_COLUMNS, inferFieldUiMeta, objectShape, schemaEnumOptions, schemaIsOptional, ui, } from "./field-ui-meta";
48
+ import { ROW_COLUMNS, inferFieldUiMeta, objectShape, schemaEnumOptions, schemaIsOptional, ui, PAGINATED_SELECT_THRESHOLD, } from "./field-ui-meta";
45
49
  /**
46
50
  * Enum members as `<FieldSelect>` options.
47
51
  *
@@ -80,8 +84,21 @@ export function resolveFields(schema) {
80
84
  export function groupFieldsBySection(fields) {
81
85
  const bySection = new Map();
82
86
  for (const field of fields) {
83
- if (field.meta.derived)
84
- continue; // server-owned — never an input
87
+ // A derived field is never a bare input, but "never an input" and "never
88
+ // shown" are different questions and the tier answers them differently:
89
+ //
90
+ // t2-server / t3-mirror / t4-aggregate — the client cannot know the value
91
+ // at edit time (an id, a timestamp, a rollup). Omitted entirely; a blank
92
+ // read-only box for a value that does not exist yet is noise.
93
+ // t1-derive — the client CAN compute it, live, from a field on this same
94
+ // form (slug from title). Kept, and rendered read-only by renderField,
95
+ // so the user can see what will be saved and cannot desync it from its
96
+ // source by typing.
97
+ //
98
+ // Absent `tier` keeps the original behaviour of dropping the field: that is
99
+ // what every existing `derived: true` annotation was written against.
100
+ if (field.meta.derived && field.meta.tier !== "t1-derive")
101
+ continue;
85
102
  const key = field.meta.section || "advanced";
86
103
  const bucket = bySection.get(key);
87
104
  if (bucket)
@@ -128,6 +145,42 @@ export function packRows(fields) {
128
145
  flush();
129
146
  return rows;
130
147
  }
148
+ /**
149
+ * The draft, minus every field whose `when` predicate says it is not on screen.
150
+ *
151
+ * ## Why this exists, and why it is not optional
152
+ *
153
+ * A `when` predicate hides a CONTROL; it does not clear the value behind it.
154
+ * So a form that renders conditionally and submits `{...draft}` sends whatever
155
+ * the user typed before they switched the option away — the control is gone
156
+ * from the screen and its value is still in the payload.
157
+ *
158
+ * That is not hypothetical. Four of the twenty dead controls found in the W3c
159
+ * sweep were exactly this: a cap typed on a percentage coupon persisted after
160
+ * switching to free-shipping; a lottery slot price written under uniform
161
+ * pricing; an AdSense slot shipped with a manually-authored ad. Each looked
162
+ * right on screen and saved something else.
163
+ *
164
+ * Build the payload from THIS, not from the draft, and hidden-implies-not-sent
165
+ * holds by construction rather than by remembering.
166
+ *
167
+ * Fields with no `when` are always kept, so a schema with no conditionals gets
168
+ * its draft back unchanged and the call is free.
169
+ */
170
+ export function visibleValues(schema, values) {
171
+ const fields = resolveFields(schema);
172
+ if (!fields.some((f) => f.meta.when))
173
+ return values;
174
+ const out = {};
175
+ for (const field of fields) {
176
+ if (field.meta.when && !field.meta.when(values))
177
+ continue;
178
+ const key = field.name;
179
+ if (key in values)
180
+ out[key] = values[key];
181
+ }
182
+ return out;
183
+ }
131
184
  /**
132
185
  * Build the `SectionDef[]` a `<SectionForm>` renders.
133
186
  *
@@ -140,12 +193,27 @@ export function buildSectionsFromSchema(schema, opts = {}) {
140
193
  const bySection = groupFieldsBySection(fields);
141
194
  const declarationOrder = [...bySection.keys()];
142
195
  const explicitOrder = opts.sectionOrder ?? [];
196
+ /**
197
+ * Order is: required first, then an explicit `sectionOrder` if the caller
198
+ * gave one, then the section's GROUP band, then declaration order.
199
+ *
200
+ * The group band is what makes "required → additional → … → least important
201
+ * last" hold without every form maintaining its own `sectionOrder`. It cannot
202
+ * come from the section id, because ids are free-form and form-specific —
203
+ * see the note on `FieldUiMeta.group`. An explicit `sectionOrder` still wins,
204
+ * so a form with a genuine bespoke sequence keeps it.
205
+ */
143
206
  const rank = (id) => {
144
207
  const bucket = bySection.get(id) ?? [];
145
208
  if (bucket.some((f) => f.meta.sectionRequired))
146
- return -1;
209
+ return -1000;
147
210
  const i = explicitOrder.indexOf(id);
148
- return i === -1 ? explicitOrder.length + declarationOrder.indexOf(id) : i;
211
+ if (i !== -1)
212
+ return i;
213
+ const group = resolveSectionGroup(id, bucket.find((f) => f.meta.group)?.meta.group);
214
+ // Band first, declaration order inside the band. The multiplier just has to
215
+ // exceed any plausible section count in one form.
216
+ return explicitOrder.length + groupRank(group) * 1000 + declarationOrder.indexOf(id);
149
217
  };
150
218
  return declarationOrder
151
219
  .slice()
@@ -189,6 +257,21 @@ function renderField(field, ctx, opts) {
189
257
  const label = meta.label ?? humaniseFieldName(name);
190
258
  const value = ctx.values[name];
191
259
  const set = (v) => ctx.onChange({ [name]: v });
260
+ /*
261
+ * A t1-derive field — a slug computed from a title — is a live PREVIEW of
262
+ * what will be saved, not an input.
263
+ *
264
+ * Read-only rather than merely discouraged, because the two are only equal
265
+ * while the user behaves: an editable slug beside its source lets them be
266
+ * desynced, and slug immutability after creation is this codebase's
267
+ * established convention (categories, brands, bundles — Root Cause #39).
268
+ * `required` is deliberately NOT passed on: the user cannot fill it, so
269
+ * marking it required would put a permanent asterisk on a field they are not
270
+ * allowed to touch, and the error summary would name it.
271
+ */
272
+ if (meta.derived) {
273
+ return (_jsx(FieldInput, { name: name, label: label, hint: meta.help ?? "Generated automatically — not editable.", readOnly: true, value: typeof value === "string" ? value : value == null ? "" : String(value), onChange: () => { } }, name));
274
+ }
192
275
  switch (meta.kind) {
193
276
  case "toggle":
194
277
  return (_jsx(FieldCheckbox, { name: name, label: label, hint: meta.help, checked: Boolean(value), onChange: set }, name));
@@ -196,7 +279,18 @@ function renderField(field, ctx, opts) {
196
279
  return (_jsx(FieldTextarea, { name: name, label: label, hint: meta.help, required: required, value: typeof value === "string" ? value : "", onChange: set }, name));
197
280
  case "select": {
198
281
  const options = opts.options?.[name] ?? selectOptions(field.schema) ?? [];
199
- return (_jsx(FieldSelect, { name: name, label: label, hint: meta.help === "paginated" ? undefined : meta.help, required: required, value: typeof value === "string" ? value : "", options: options, onChange: set }, name));
282
+ /*
283
+ * More than five options and a native dropdown is unscannable — the
284
+ * standing rule in CLAUDE.md § UI Primitive Rules. Decided here, by
285
+ * counting, so it holds for a caller-supplied `opts.options` list too:
286
+ * inference can only see a Zod enum, and the long lists (categories,
287
+ * brands, stores) all arrive through `opts.options`, which is exactly the
288
+ * case that most needs searching.
289
+ */
290
+ if (options.length > PAGINATED_SELECT_THRESHOLD) {
291
+ return (_jsxs(Stack, { gap: "xs", children: [_jsxs(Text, { size: "sm", weight: "medium", color: "muted", children: [label, required ? " *" : ""] }), _jsx(PaginatedSelect, { value: typeof value === "string" ? value : null, onChange: (v) => set(v ?? ""), options: options, ariaLabel: label, placeholder: `Select ${label.toLowerCase()}…` }), meta.help && _jsx(Text, { size: "xs", color: "muted", children: meta.help }), ctx.errors[name] && (_jsx(Text, { size: "xs", color: "error", role: "alert", children: ctx.errors[name] }))] }, name));
292
+ }
293
+ return (_jsx(FieldSelect, { name: name, label: label, hint: meta.help, required: required, value: typeof value === "string" ? value : "", options: options, onChange: set }, name));
200
294
  }
201
295
  case "number":
202
296
  return (_jsx(FieldInput, { name: name, type: "number", label: label, hint: meta.help, required: required, value: value == null ? "" : String(value), onChange: (v) => set(v === "" ? undefined : Number(v)) }, name));
@@ -211,6 +305,10 @@ function renderField(field, ctx, opts) {
211
305
  case "list":
212
306
  return (_jsx(FieldInput, { name: name, label: label, hint: meta.help ?? `Provide a renderer for "${name}" — this field needs a custom control.`, required: required, disabled: true, value: "" }, name));
213
307
  default:
214
- return (_jsx(FieldInput, { name: name, label: label, hint: meta.help, required: required, value: typeof value === "string" ? value : value == null ? "" : String(value), onChange: set }, name));
308
+ return (_jsx(FieldInput, { name: name,
309
+ // Defaults to "text". Without the passthrough a password field
310
+ // renders in PLAINTEXT, and an email field gets the wrong mobile
311
+ // keyboard and no autofill — see FieldUiMeta.inputType.
312
+ type: meta.inputType ?? "text", label: label, hint: meta.help, required: required, value: typeof value === "string" ? value : value == null ? "" : String(value), onChange: set }, name));
215
313
  }
216
314
  }
@@ -1,3 +1,4 @@
1
+ import type { FormSectionGroup } from "./form-sections";
1
2
  import type { ZodTypeAny } from "zod";
2
3
  import type { FormValues } from "../../schemas/types";
3
4
  /** How much of a row a field claims on desktop. Everything is 1-up on mobile. */
@@ -20,6 +21,22 @@ export interface FieldUiMeta {
20
21
  * handful of schemas and quietly mis-group the rest.
21
22
  */
22
23
  section: string;
24
+ /**
25
+ * Priority band this section belongs to — drives ORDER and default-open,
26
+ * never identity.
27
+ *
28
+ * Deliberately separate from `section`, which stays free-form. Collapsing the
29
+ * 58 section ids in use onto a closed 12-value set was measured first and
30
+ * would have MERGED sections in 7 files: the scam report's `who` + `what` +
31
+ * `declare` into one blob, coupons' `limits` + `validity`, blog's `content` +
32
+ * `seo`. The id is the rendered unit and supplies the visible heading (144 of
33
+ * 228 annotations have no `sectionLabel`, so `humaniseFieldName(id)` IS their
34
+ * heading); the group is only "how early does this appear".
35
+ *
36
+ * Omit it and `SECTION_GROUP_DEFAULTS` resolves one from the id. A brand-new
37
+ * id with no default must declare its own.
38
+ */
39
+ group?: FormSectionGroup;
23
40
  /** Human label for the section. The first field to declare it wins. */
24
41
  sectionLabel?: string;
25
42
  /** Marks its section required-first, open on mount, non-collapsible. */
@@ -64,6 +81,19 @@ export interface FieldUiMeta {
64
81
  tier?: CalculatedTier;
65
82
  label?: string;
66
83
  help?: string;
84
+ /**
85
+ * The native `<input type>` for a `kind: "text"` field.
86
+ *
87
+ * `FieldKind` deliberately stays a small set of CONTROL kinds — it picks
88
+ * which primitive renders, and `email`/`password`/`tel`/`url` all render the
89
+ * same `<FieldInput>`. What they change is the browser's keyboard, autofill
90
+ * and masking, which is a property of the field rather than of the control.
91
+ *
92
+ * 🛑 Without this the generator emits a bare `<FieldInput>` with no `type`,
93
+ * so a password field renders **in plaintext**. Any schema with a password,
94
+ * an email or a phone number must set it.
95
+ */
96
+ inputType?: "text" | "email" | "password" | "tel" | "url" | "search";
67
97
  }
68
98
  export declare const ui: {
69
99
  /** Attach metadata to a schema instance. Returns the SAME instance. */
@@ -126,6 +156,20 @@ export declare function objectShape(schema: ZodTypeAny): Record<string, ZodTypeA
126
156
  * `.register(ui, { section: "…" })` calls, not 13 full metadata objects.
127
157
  */
128
158
  export declare function inferFieldUiMeta(name: string, schema: ZodTypeAny): Partial<FieldUiMeta>;
159
+ /**
160
+ * Above this many options a select becomes a searchable `<PaginatedSelect>`.
161
+ * The standing UI rule (CLAUDE.md § UI Primitive Rules): more than five options
162
+ * and a plain dropdown is unscannable.
163
+ *
164
+ * 🛑 This is the WHOLE mechanism — there is deliberately no `paginated` flag on
165
+ * `FieldUiMeta`. It used to be smuggled through `help` as the literal string
166
+ * `"paginated"`, which broke in both directions: the assignment was
167
+ * `meta.help ?? "paginated"`, so a select that had real help text never became
168
+ * paginated; and the renderer had to blank `help` to avoid printing the
169
+ * sentinel, so one that DID become paginated could never show help. Counting
170
+ * the options at render time needs neither.
171
+ */
172
+ export declare const PAGINATED_SELECT_THRESHOLD = 5;
129
173
  /**
130
174
  * The field's final metadata: inference first, explicit registration on top.
131
175
  *
@@ -300,15 +300,22 @@ export function inferFieldUiMeta(name, schema) {
300
300
  meta.derived = true;
301
301
  meta.tier = meta.tier ?? "t2-server";
302
302
  }
303
- // >5 options is the standing PaginatedSelect threshold. Recorded as `help`
304
- // rather than a separate flag so the renderer can decide without a second
305
- // source of truth about what "many options" means.
306
- const options = enumOptions(inner);
307
- if (meta.kind === "select" && options != null && options.length > 5) {
308
- meta.help = meta.help ?? "paginated";
309
- }
310
303
  return meta;
311
304
  }
305
+ /**
306
+ * Above this many options a select becomes a searchable `<PaginatedSelect>`.
307
+ * The standing UI rule (CLAUDE.md § UI Primitive Rules): more than five options
308
+ * and a plain dropdown is unscannable.
309
+ *
310
+ * 🛑 This is the WHOLE mechanism — there is deliberately no `paginated` flag on
311
+ * `FieldUiMeta`. It used to be smuggled through `help` as the literal string
312
+ * `"paginated"`, which broke in both directions: the assignment was
313
+ * `meta.help ?? "paginated"`, so a select that had real help text never became
314
+ * paginated; and the renderer had to blank `help` to avoid printing the
315
+ * sentinel, so one that DID become paginated could never show help. Counting
316
+ * the options at render time needs neither.
317
+ */
318
+ export const PAGINATED_SELECT_THRESHOLD = 5;
312
319
  /**
313
320
  * The field's final metadata: inference first, explicit registration on top.
314
321
  *
@@ -0,0 +1,46 @@
1
+ /**
2
+ * The canonical section ORDER vocabulary.
3
+ *
4
+ * ## Why this is a `group`, not a rename of `section`
5
+ *
6
+ * The plan called for collapsing the 58 free-form section ids in use across 30
7
+ * schemas onto a closed 12-value set. Measured before doing it, that merges
8
+ * sections in 7 files and 8 places — the scam report's `who` + `what` +
9
+ * `declare` become one blob, coupons' `limits` + `validity` collapse together,
10
+ * blog's `content` + `seo` merge, and payout methods lose the split between
11
+ * `method` and `bank`.
12
+ *
13
+ * The mistake was treating one identifier as two things. A section id is the
14
+ * RENDERED UNIT — fine-grained, form-specific, and the thing whose heading the
15
+ * user reads (`build-sections` falls back to `humaniseFieldName(sectionId)`, so
16
+ * 144 of the 228 annotations get their visible heading straight from the id).
17
+ * What the ordering rule actually needs is a PRIORITY BAND: required first,
18
+ * danger last, everything else in a predictable middle.
19
+ *
20
+ * So the id stays free-form and every section declares a `group` from this
21
+ * closed union. Order and default-open derive from the group; identity and
22
+ * heading stay with the id. Nothing merges, and the audit still has a closed
23
+ * set to check against.
24
+ *
25
+ * ## Ordering
26
+ *
27
+ * Array order IS render order. `required` is index 0 and is the section left
28
+ * open by default; `danger` is always last. That gives "1. Required → 2.
29
+ * Additional → … → least important last" mechanically, with no per-form
30
+ * `sectionOrder` to maintain.
31
+ */
32
+ export declare const FORM_SECTION_GROUP: readonly ["required", "identity", "classification", "pricing", "inventory", "media", "logistics", "relationships", "schedule", "visibility", "advanced", "danger"];
33
+ export type FormSectionGroup = (typeof FORM_SECTION_GROUP)[number];
34
+ /** Position of a group in render order; unknown groups sort just before danger. */
35
+ export declare function groupRank(group: FormSectionGroup | undefined): number;
36
+ /**
37
+ * Default group for each section id currently in use, so 30 schemas do not each
38
+ * need a hand-written `group`. A section id absent here must declare its own —
39
+ * `audit-form-sectionised` fails otherwise, which is what stops a new id
40
+ * silently defaulting into the middle of the form.
41
+ *
42
+ * Derived from the 58 ids actually present, counted rather than guessed.
43
+ */
44
+ export declare const SECTION_GROUP_DEFAULTS: Record<string, FormSectionGroup>;
45
+ /** The group for a section id — its declared group, else the default, else advanced. */
46
+ export declare function resolveSectionGroup(sectionId: string, declared?: FormSectionGroup): FormSectionGroup;