@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
@@ -72,10 +72,10 @@ function write(key, items) {
72
72
  return;
73
73
  try {
74
74
  localStorage.setItem(key, JSON.stringify(items));
75
+ // Quota exceeded or storage blocked. Losing pending ops costs a retry, never data: the cart is canonical in Firestore.
75
76
  }
76
77
  catch (_err) {
77
78
  void normalizeError(_err);
78
- // storage quota exceeded — best effort
79
79
  }
80
80
  }
81
81
  function writeCartOps(items) {
@@ -1,3 +1,25 @@
1
+ /**
2
+ * Add or edit an item in a user's personal catalogue.
3
+ *
4
+ * Fields come from `createCatalogueItemSchema`'s annotations. Three need a
5
+ * `renderers` entry: the photo list (a real uploader, not the generator's
6
+ * disabled placeholder), and the two taxonomy selects, which are searchable
7
+ * because 47 categories is well past the 5-option threshold.
8
+ *
9
+ * ## `categorySlugs` and `brandSlug` were declared, read, and never collected
10
+ *
11
+ * Both are inherited from `ProductDraftFields` and both are read by
12
+ * `product-from-item.ts`, which builds the marketplace listing when an item is
13
+ * promoted. The hand-rolled form had no control for either, so every promoted
14
+ * listing carried `categorySlugs: []` — and per the Category Tree rules a
15
+ * product with an empty chain is invisible on every category and brand page it
16
+ * should appear under. A schema field with a reader and no control is the
17
+ * inverse of a dead control, and just as silent.
18
+ *
19
+ * `mainImage` is `t1-derive` — the first photo, not a field anyone types. It
20
+ * renders as a read-only preview rather than a text box that could be desynced
21
+ * from the gallery it is supposed to mirror.
22
+ */
1
23
  import React from "react";
2
24
  import type { CatalogueItemDocument } from "../schemas/firestore";
3
25
  export interface CatalogueItemEditorViewProps {
@@ -1,60 +1,120 @@
1
1
  "use client";
2
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * Add or edit an item in a user's personal catalogue.
5
+ *
6
+ * Fields come from `createCatalogueItemSchema`'s annotations. Three need a
7
+ * `renderers` entry: the photo list (a real uploader, not the generator's
8
+ * disabled placeholder), and the two taxonomy selects, which are searchable
9
+ * because 47 categories is well past the 5-option threshold.
10
+ *
11
+ * ## `categorySlugs` and `brandSlug` were declared, read, and never collected
12
+ *
13
+ * Both are inherited from `ProductDraftFields` and both are read by
14
+ * `product-from-item.ts`, which builds the marketplace listing when an item is
15
+ * promoted. The hand-rolled form had no control for either, so every promoted
16
+ * listing carried `categorySlugs: []` — and per the Category Tree rules a
17
+ * product with an empty chain is invisible on every category and brand page it
18
+ * should appear under. A schema field with a reader and no control is the
19
+ * inverse of a dead control, and just as silent.
20
+ *
21
+ * `mainImage` is `t1-derive` — the first photo, not a field anyone types. It
22
+ * renders as a read-only preview rather than a text box that could be desynced
23
+ * from the gallery it is supposed to mirror.
24
+ */
3
25
  import React from "react";
4
26
  import { useQueryClient } from "@tanstack/react-query";
5
27
  import { useApiMutation } from "@mohasinac/appkit/client";
6
- import { Alert, Button, FieldInput, FieldSelect, FieldTextarea, Form, Grid, Row, Span, Stack, Toggle } from "../../../ui";
7
- import { FormErrorSummary } from "../../../ui/forms";
8
- import { MediaUploadList } from "../../media/upload/MediaUploadList";
9
- import { useMediaUpload } from "../../media";
28
+ import { ACCOUNT_ENDPOINTS, BRAND_ENDPOINTS, CATEGORY_ENDPOINTS } from "../../../constants/api-endpoints";
10
29
  import { apiClient } from "../../../http";
11
- import { ACCOUNT_ENDPOINTS } from "../../../constants/api-endpoints";
30
+ import { Alert, PaginatedSelect, Stack } from "../../../ui";
31
+ import { applyZodIssues } from "../../../ui/forms/apply-zod-issues";
32
+ import { FormErrorSummary } from "../../../ui/forms/FormErrorSummary";
33
+ import { FormShellContext, useFormShellState } from "../../../ui/forms/FormShell";
34
+ import { buildSectionsFromSchema } from "../../shell/build-sections";
35
+ import { SectionForm, useSectionFormNav } from "../../shell/SectionForm";
36
+ import { useMediaUpload } from "../../media";
37
+ import { MediaUploadList } from "../../media/upload/MediaUploadList";
12
38
  import { createCatalogueItemSchema } from "../schemas/validation";
13
- const CONDITION_OPTIONS = [
14
- { label: "New", value: "new" },
15
- { label: "Like new", value: "like_new" },
16
- { label: "Good", value: "good" },
17
- { label: "Fair", value: "fair" },
18
- { label: "Poor", value: "poor" },
19
- { label: "Used", value: "used" },
20
- { label: "Refurbished", value: "refurbished" },
21
- ];
39
+ /** PUBLIC endpoints — this is a buyer surface; the admin ones would 403. */
40
+ async function loadOptionsFrom(endpoint, query, page) {
41
+ const params = new URLSearchParams({ page: String(page), pageSize: "25" });
42
+ if (query)
43
+ params.set("q", query);
44
+ const res = await apiClient.get(`${endpoint}?${params.toString()}`);
45
+ const data = res ?? {};
46
+ return {
47
+ items: (data.items ?? []).map((c) => ({ value: c.id, label: c.name })),
48
+ hasMore: data.hasMore ?? false,
49
+ };
50
+ }
51
+ const loadCategoryOptions = (q, p) => loadOptionsFrom(CATEGORY_ENDPOINTS.LIST, q, p);
52
+ const loadBrandOptions = (q, p) => loadOptionsFrom(BRAND_ENDPOINTS.LIST, q, p);
22
53
  export function CatalogueItemEditorView({ item, onSaved }) {
23
54
  const isCreate = !item;
24
55
  const queryClient = useQueryClient();
25
56
  const { upload } = useMediaUpload();
26
57
  const uploadIndexRef = React.useRef(0);
27
- const [title, setTitle] = React.useState(item?.title ?? "");
28
- const [description, setDescription] = React.useState(item?.description ?? "");
29
- const [condition, setCondition] = React.useState(item?.condition ?? "");
30
- const [price, setPrice] = React.useState(item?.price ? String(item.price) : "0");
31
- const [quantity, setQuantity] = React.useState(String(item?.quantity ?? 1));
32
- const [visibility, setVisibility] = React.useState(item?.visibility ?? "public");
33
- const [images, setImages] = React.useState(item?.images ?? []);
34
- const galleryFields = images.map((url) => ({ url, type: "image" }));
35
- const handleUpload = async (file) => {
58
+ const [form, setForm] = React.useState({
59
+ title: item?.title ?? "",
60
+ description: item?.description ?? "",
61
+ condition: item?.condition ?? "",
62
+ quantity: item?.quantity ?? 1,
63
+ price: item?.price ?? 0,
64
+ images: item?.images ?? [],
65
+ mainImage: item?.mainImage ?? item?.images?.[0] ?? "",
66
+ categorySlugs: item?.categorySlugs ?? [],
67
+ brandSlug: item?.brandSlug ?? "",
68
+ visibility: item?.visibility ?? "public",
69
+ });
70
+ const handleUpload = React.useCallback(async (file) => {
36
71
  uploadIndexRef.current += 1;
37
72
  return upload(file, "catalogue", true, {
38
73
  type: "catalogue-image",
39
- item: title || "item",
74
+ item: form.title || "item",
40
75
  index: uploadIndexRef.current,
41
76
  });
42
- };
77
+ }, [upload, form.title]);
78
+ const sections = React.useMemo(() => buildSectionsFromSchema(createCatalogueItemSchema, {
79
+ renderers: {
80
+ images: ({ values, onChange }) => (_jsx(MediaUploadList, { label: "Photos", value: values.images.map((url) => ({ url, type: "image" })), onChange: (fields) => {
81
+ const urls = fields.map((f) => f.url);
82
+ // `mainImage` is derived, so it moves with the gallery rather
83
+ // than pointing at a photo the user has since removed.
84
+ onChange({ images: urls, mainImage: urls[0] ?? "" });
85
+ }, onUpload: handleUpload, accept: "image/*", maxItems: 8, helperText: "Photos older than 30 days must be refreshed before this item can be listed." })),
86
+ categorySlugs: ({ values, onChange }) => (
87
+ // Explicit `<string>`: with `multiple`, `value` is `V[]`, so an
88
+ // inferred V reads the array itself as the option type.
89
+ _jsx(PaginatedSelect, { multiple: true, value: values.categorySlugs, onChange: (v) => onChange({ categorySlugs: v ?? [] }), loadOptions: loadCategoryOptions, placeholder: "Search categories\u2026", searchPlaceholder: "Type a category name\u2026", noResultsText: "No categories found", ariaLabel: "Categories" })),
90
+ brandSlug: ({ values, onChange }) => (_jsx(PaginatedSelect, { value: values.brandSlug || null, onChange: (v) => onChange({ brandSlug: v ?? "" }), loadOptions: loadBrandOptions, placeholder: "Search brands\u2026", searchPlaceholder: "Type a brand name\u2026", noResultsText: "No brands found", ariaLabel: "Brand" })),
91
+ },
92
+ }), [handleUpload]);
93
+ const nav = useSectionFormNav(sections, form, { scope: "user:catalogue-item" });
94
+ const { shellCtx, setFieldError, clearErrors } = useFormShellState(createCatalogueItemSchema, {
95
+ sections: nav.sectionMeta,
96
+ onGoToSection: nav.goToSection,
97
+ fieldToSectionIndex: nav.fieldToSectionIndex,
98
+ });
43
99
  const saveMutation = useApiMutation({
44
100
  successMessage: isCreate ? "Added to your catalogue" : "Catalogue item updated",
101
+ errorMessage: isCreate ? "Could not add this item." : "Could not save your changes.",
45
102
  mutationFn: async () => {
46
103
  const payload = {
47
- title,
48
- description: description || undefined,
49
- condition: condition || undefined,
50
- price: Math.round(Number(price) * 100) / 100,
51
- quantity: Number(quantity),
52
- visibility,
53
- images,
54
- mainImage: images[0],
104
+ title: form.title,
105
+ description: form.description || undefined,
106
+ condition: form.condition || undefined,
107
+ price: Math.round(Number(form.price) * 100) / 100,
108
+ quantity: Number(form.quantity),
109
+ visibility: form.visibility,
110
+ images: form.images,
111
+ mainImage: form.images[0],
112
+ categorySlugs: form.categorySlugs,
113
+ brandSlug: form.brandSlug || undefined,
55
114
  };
56
- if (isCreate)
115
+ if (isCreate) {
57
116
  return apiClient.post(ACCOUNT_ENDPOINTS.CATALOGUE, payload);
117
+ }
58
118
  return apiClient.patch(ACCOUNT_ENDPOINTS.CATALOGUE_BY_ID(item.id), payload);
59
119
  },
60
120
  onSuccess: (saved) => {
@@ -62,21 +122,21 @@ export function CatalogueItemEditorView({ item, onSaved }) {
62
122
  onSaved?.(saved.id);
63
123
  },
64
124
  });
65
- return (_jsx(Form, { schema: createCatalogueItemSchema, spacing: "md", children: ({ setFieldError, markSubmitAttempted }) => (_jsxs(Stack, { gap: "md", children: [item?.listingStatus && item.listingStatus !== "not_listed" && (_jsxs(Alert, { variant: "info", children: ["This item is ", item.listingStatus.replace(/_/g, " "), item.listingStatus === "rejected" && item.rejectionReason ? `: ${item.rejectionReason}` : "."] })), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(FieldInput, { name: "title", label: "Title", required: true, value: title, onChange: setTitle }), _jsx(FieldSelect, { name: "condition", label: "Condition", value: condition, onChange: setCondition, options: CONDITION_OPTIONS }), _jsx(FieldInput, { name: "price", label: "Estimated resale price (\u20B9)", type: "number", min: "0", value: price, onChange: setPrice }), _jsx(FieldInput, { name: "quantity", label: "Quantity", type: "number", min: "1", value: quantity, onChange: setQuantity })] }), _jsx(FieldTextarea, { name: "description", label: "Description", value: description, onChange: setDescription, rows: 3 }), _jsx(MediaUploadList, { label: "Photos", value: galleryFields, onChange: (fields) => setImages(fields.map((f) => f.url)), onUpload: handleUpload, accept: "image/*", maxItems: 8, helperText: "Photos older than 30 days must be refreshed before this item can be listed." }), _jsxs(Row, { gap: "sm", align: "center", children: [_jsx(Toggle, { checked: visibility === "public", onChange: (checked) => setVisibility(checked ? "public" : "private"), size: "sm" }), _jsx(Span, { children: visibility === "public" ? "Public — visible on your profile" : "Private — only you can see it" })] }), _jsx(FormErrorSummary, {}), _jsx(Button, { type: "button", isLoading: saveMutation.isPending, onClick: () => {
66
- // type="button" — no native submit, so unhide the summary here.
67
- markSubmitAttempted();
68
- const parsed = createCatalogueItemSchema.safeParse({
69
- title,
70
- images,
71
- price: Math.round(Number(price) * 100) / 100,
72
- quantity: Number(quantity),
73
- visibility,
74
- });
75
- if (!parsed.success) {
76
- for (const issue of parsed.error.issues)
77
- setFieldError(String(issue.path[0]), issue.message);
78
- return;
79
- }
80
- saveMutation.mutate();
81
- }, children: isCreate ? "Add to Catalogue" : "Save Changes" })] })) }));
125
+ const onSubmit = () => {
126
+ clearErrors();
127
+ const parsed = createCatalogueItemSchema.safeParse({
128
+ ...form,
129
+ price: Math.round(Number(form.price) * 100) / 100,
130
+ quantity: Number(form.quantity),
131
+ brandSlug: form.brandSlug || undefined,
132
+ });
133
+ if (!parsed.success) {
134
+ applyZodIssues(parsed.error.issues, setFieldError);
135
+ return;
136
+ }
137
+ saveMutation.mutate();
138
+ };
139
+ return (_jsxs(Stack, { gap: "md", children: [item?.listingStatus && item.listingStatus !== "not_listed" && (_jsxs(Alert, { variant: "info", children: ["This item is ", item.listingStatus.replace(/_/g, " "), item.listingStatus === "rejected" && item.rejectionReason
140
+ ? `: ${item.rejectionReason}`
141
+ : "."] })), _jsxs(FormShellContext.Provider, { value: shellCtx, children: [_jsx(FormErrorSummary, {}), _jsx(SectionForm, { sections: sections, values: form, onChange: (partial) => setForm((prev) => Object.assign({}, prev, partial)), onSubmit: onSubmit, schema: createCatalogueItemSchema, openIds: nav.openIds, onOpenChange: nav.setOpenIds, isLoading: saveMutation.isPending, submitLabel: isCreate ? "Add to Catalogue" : "Save Changes" })] })] }));
82
142
  }
@@ -2,13 +2,13 @@ import { z } from "zod";
2
2
  export declare const createCatalogueItemSchema: z.ZodObject<{
3
3
  title: z.ZodString;
4
4
  description: z.ZodOptional<z.ZodString>;
5
+ condition: z.ZodOptional<z.ZodEnum<["new", "like_new", "good", "fair", "poor", "used", "refurbished", "broken", "graded"]>>;
6
+ quantity: z.ZodDefault<z.ZodNumber>;
5
7
  images: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
6
8
  mainImage: z.ZodOptional<z.ZodString>;
7
- condition: z.ZodOptional<z.ZodEnum<["new", "like_new", "good", "fair", "poor", "used", "refurbished", "broken", "graded"]>>;
8
9
  categorySlugs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
9
10
  brandSlug: z.ZodOptional<z.ZodString>;
10
11
  price: z.ZodOptional<z.ZodNumber>;
11
- quantity: z.ZodDefault<z.ZodNumber>;
12
12
  visibility: z.ZodDefault<z.ZodEnum<["public", "private"]>>;
13
13
  }, "strip", z.ZodTypeAny, {
14
14
  title: string;
@@ -36,13 +36,13 @@ export declare const createCatalogueItemSchema: z.ZodObject<{
36
36
  export declare const updateCatalogueItemSchema: z.ZodObject<{
37
37
  title: z.ZodOptional<z.ZodString>;
38
38
  description: z.ZodOptional<z.ZodOptional<z.ZodString>>;
39
+ condition: z.ZodOptional<z.ZodOptional<z.ZodEnum<["new", "like_new", "good", "fair", "poor", "used", "refurbished", "broken", "graded"]>>>;
40
+ quantity: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
39
41
  images: z.ZodOptional<z.ZodDefault<z.ZodArray<z.ZodString, "many">>>;
40
42
  mainImage: z.ZodOptional<z.ZodOptional<z.ZodString>>;
41
- condition: z.ZodOptional<z.ZodOptional<z.ZodEnum<["new", "like_new", "good", "fair", "poor", "used", "refurbished", "broken", "graded"]>>>;
42
43
  categorySlugs: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
43
44
  brandSlug: z.ZodOptional<z.ZodOptional<z.ZodString>>;
44
45
  price: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
45
- quantity: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
46
46
  visibility: z.ZodOptional<z.ZodDefault<z.ZodEnum<["public", "private"]>>>;
47
47
  }, "strip", z.ZodTypeAny, {
48
48
  title?: string | undefined;
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { annotate } from "../../shell/field-ui-meta";
2
3
  const productConditionSchema = z.enum([
3
4
  "new",
4
5
  "like_new",
@@ -11,15 +12,51 @@ const productConditionSchema = z.enum([
11
12
  "graded",
12
13
  ]);
13
14
  export const createCatalogueItemSchema = z.object({
14
- title: z.string().min(1, "Title is required"),
15
- description: z.string().optional(),
16
- images: z.array(z.string()).default([]),
17
- mainImage: z.string().optional(),
18
- condition: productConditionSchema.optional(),
19
- categorySlugs: z.array(z.string()).optional(),
20
- brandSlug: z.string().optional(),
21
- price: z.number().min(0).optional(),
22
- quantity: z.number().int().min(1).default(1),
23
- visibility: z.enum(["public", "private"]).default("public"),
15
+ title: annotate(z.string().min(1, "Title is required"), {
16
+ section: "basics", sectionLabel: "Item", sectionRequired: true,
17
+ order: 1, row: "full", label: "Title",
18
+ }),
19
+ description: annotate(z.string().optional(), {
20
+ section: "basics", order: 2, row: "full", kind: "textarea", label: "Description",
21
+ }),
22
+ condition: annotate(productConditionSchema.optional(), {
23
+ section: "basics", order: 3, row: "pair", kind: "select", label: "Condition",
24
+ }),
25
+ quantity: annotate(z.number().int().min(1).default(1), {
26
+ section: "basics", order: 4, row: "pair", kind: "number", label: "Quantity",
27
+ }),
28
+ /*
29
+ * `kind: "media"` is inferred from the field NAME (field-ui-meta.ts:336),
30
+ * which also sets `sectionKeepMounted` — mandatory here, because a collapsed
31
+ * section unmounts and would discard an in-flight upload. Declared anyway so
32
+ * the section id and order are not left to inference.
33
+ */
34
+ images: annotate(z.array(z.string()).default([]), {
35
+ section: "media", sectionLabel: "Photos", order: 1, row: "full", kind: "media",
36
+ sectionKeepMounted: true, label: "Photos",
37
+ }),
38
+ /*
39
+ * Derived from `images[0]`, never typed. Rendering it as an editable box
40
+ * lets a user point it at a photo they have since removed from the gallery —
41
+ * the field would then name an image that does not exist on the item.
42
+ */
43
+ mainImage: annotate(z.string().optional(), {
44
+ section: "media", order: 2, row: "full", kind: "media", label: "Main photo",
45
+ derived: true, tier: "t1-derive", help: "The first photo in the gallery.",
46
+ }),
47
+ categorySlugs: annotate(z.array(z.string()).optional(), {
48
+ section: "classification", sectionLabel: "Filing", order: 1, row: "pair",
49
+ label: "Categories",
50
+ }),
51
+ brandSlug: annotate(z.string().optional(), {
52
+ section: "classification", order: 2, row: "pair", kind: "select", label: "Brand",
53
+ }),
54
+ price: annotate(z.number().min(0).optional(), {
55
+ section: "pricing", sectionLabel: "Value", order: 1, row: "pair", kind: "number",
56
+ label: "Estimated value (₹)",
57
+ }),
58
+ visibility: annotate(z.enum(["public", "private"]).default("public"), {
59
+ section: "visibility", order: 1, row: "pair", kind: "select", label: "Visibility",
60
+ }),
24
61
  });
25
62
  export const updateCatalogueItemSchema = createCatalogueItemSchema.partial();
@@ -16,24 +16,25 @@ import { listingTabCounts, } from "../../../_internal/server/features/products/l
16
16
  import { CATEGORY_PAGE_TABS } from "../../products/constants/listing-tabs";
17
17
  import { enabledCategoryTypes, enabledListingTypes } from "../../../_internal/shared/listing-types/feature-flags";
18
18
  import { siteSettingsRepository } from "../../../repositories";
19
+ import { safeRead } from "../../../errors/safe-read";
19
20
  const __O = {
20
21
  hidden: "overflow-hidden",
21
22
  };
22
23
  export async function BrandDetailPageView({ slug, initialBrand }) {
24
+ // The brand IS this page's subject — a read failure must surface rather than
25
+ // render an anonymous, empty brand page. `undefined` still means "no such
26
+ // brand slug".
23
27
  const brand = (initialBrand ?? (await categoriesRepository
24
- .getCategoryBySlug(slug)
25
- .catch(() => undefined)));
28
+ .getCategoryBySlug(slug)) ?? undefined);
26
29
  const brandName = brand?.name;
27
30
  const [productsResult, tabCounts, allBundles, activeBrands, groupedListings, settings] = await Promise.all([
28
31
  brandName
29
- ? productRepository
30
- .list({
32
+ ? safeRead(() => productRepository.list({
31
33
  filters: sieveAnd(sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("brand", SIEVE_OP.EQ, brandName), sieveFilter("listingType", SIEVE_OP.EQ, "standard")),
32
34
  sorts: sortBy("createdAt", "DESC"),
33
35
  page: 1,
34
36
  pageSize: 24,
35
- })
36
- .catch(() => null)
37
+ }), { route: "/brands/[slug]", key: "brand.products", fallback: null })
37
38
  : Promise.resolve(null),
38
39
  // One count per tab, derived from CATEGORY_PAGE_TABS. Four of the nine tabs
39
40
  // (classifieds, digital codes, live, art) had no count at all and could
@@ -47,16 +48,31 @@ export async function BrandDetailPageView({ slug, initialBrand }) {
47
48
  // We pull all bundle categories and filter client-side by brandSlug —
48
49
  // no dedicated repository query needed at this catalog's bundle volume.
49
50
  brand?.slug
50
- ? categoriesRepository
51
- .listByType("bundle", { activeOnly: true, limit: 50 })
52
- .catch(() => [])
51
+ ? safeRead(() => categoriesRepository.listByType("bundle", { activeOnly: true, limit: 50 }), { route: "/brands/[slug]", key: "brand.bundles", fallback: [] })
53
52
  : Promise.resolve([]),
54
53
  // Related brands — every other active brand row, excluding this one.
55
- categoriesRepository.findActiveBrands().catch(() => []),
56
- brand?.slug ? getGroupsForBrand(brand.slug).catch(() => []) : Promise.resolve([]),
54
+ // `as unknown` is load-bearing only because CategoryDocument.createdAt is a
55
+ // Date while CategoryItem.createdAt is a string — a pre-existing mismatch
56
+ // the old `.catch(() => [])` union happened to paper over.
57
+ safeRead(() => categoriesRepository.findActiveBrands(), {
58
+ route: "/brands/[slug]",
59
+ key: "brand.relatedBrands",
60
+ fallback: [],
61
+ }),
62
+ brand?.slug
63
+ ? safeRead(() => getGroupsForBrand(brand.slug), {
64
+ route: "/brands/[slug]",
65
+ key: "brand.groupedListings",
66
+ fallback: [],
67
+ })
68
+ : Promise.resolve([]),
57
69
  // Feature flags — accepted by BrandDetailTabs all along but never passed,
58
70
  // so a disabled listing type still showed its tab here.
59
- siteSettingsRepository.findById("global").catch(() => null),
71
+ safeRead(() => siteSettingsRepository.findById("global"), {
72
+ route: "/brands/[slug]",
73
+ key: "brand.siteSettings",
74
+ fallback: null,
75
+ }),
60
76
  ]);
61
77
  const brandBundles = brand?.slug
62
78
  ? allBundles.filter((b) => b.brandSlug === brand.slug)
@@ -15,14 +15,17 @@ import { listingTabCounts, } from "../../../_internal/server/features/products/l
15
15
  import { CATEGORY_PAGE_TABS } from "../../products/constants/listing-tabs";
16
16
  import { enabledCategoryTypes, enabledListingTypes } from "../../../_internal/shared/listing-types/feature-flags";
17
17
  import { siteSettingsRepository } from "../../../repositories";
18
+ import { safeRead } from "../../../errors/safe-read";
18
19
  const __O = {
19
20
  hidden: "overflow-hidden",
20
21
  xAuto: "overflow-x-auto",
21
22
  };
22
23
  export async function CategoryDetailPageView({ slug }) {
23
- const category = await categoriesRepository
24
- .getCategoryBySlug(slug)
25
- .catch(() => undefined);
24
+ // The category IS this page's subject — a read failure must surface rather
25
+ // than render an anonymous, empty category page. `undefined` still means
26
+ // "no such category slug".
27
+ const category = ((await categoriesRepository
28
+ .getCategoryBySlug(slug)) ?? undefined);
26
29
  // Products carry their FULL ancestor chain in `categorySlugs`, so matching on
27
30
  // this category's own id already returns the whole subtree — no descendant
28
31
  // expansion needed. Expanding it was also a latent outage: `categoriesIn` is
@@ -33,14 +36,12 @@ export async function CategoryDetailPageView({ slug }) {
33
36
  const categoriesIn = category?.id ? [category.id] : null;
34
37
  const [productsResult, tabCounts, bundlesResult, childCategories, rootSiblingCategories, groupedListings, settings] = await Promise.all([
35
38
  categoriesIn
36
- ? productRepository
37
- .list({
39
+ ? safeRead(() => productRepository.list({
38
40
  filters: sieveAnd(sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("listingType", SIEVE_OP.EQ, "standard")),
39
41
  sorts: sortBy("createdAt", "DESC"),
40
42
  page: 1,
41
43
  pageSize: 24,
42
- }, { categoriesIn })
43
- .catch(() => null)
44
+ }, { categoriesIn }), { route: "/categories/[slug]", key: "category.products", fallback: null })
44
45
  : Promise.resolve(null),
45
46
  // One count per tab, derived from CATEGORY_PAGE_TABS itself — so every
46
47
  // listing type is counted and a type with nothing in this category hides.
@@ -51,24 +52,40 @@ export async function CategoryDetailPageView({ slug }) {
51
52
  // SB-UNI-D — bundles fetched from the categories collection. We pull
52
53
  // all active bundle rows; the carousel filters by category affinity.
53
54
  categoriesIn
54
- ? categoriesRepository
55
- .listByType("bundle", { activeOnly: true, limit: 50 })
56
- .catch(() => [])
55
+ ? safeRead(() => categoriesRepository.listByType("bundle", { activeOnly: true, limit: 50 }), { route: "/categories/[slug]", key: "category.bundles", fallback: [] })
57
56
  : Promise.resolve([]),
58
57
  category?.id
59
- ? categoriesRepository.getChildren(category.id).catch(() => [])
58
+ ? safeRead(() => categoriesRepository.getChildren(category.id), {
59
+ route: "/categories/[slug]",
60
+ key: "category.children",
61
+ fallback: [],
62
+ })
60
63
  : Promise.resolve([]),
61
64
  // Related categories — every other category sharing this category's root
62
65
  // (siblings + cousins across the tree, up to the tier-0/1/2 depth the
63
66
  // catalog actually uses), not just direct children.
64
67
  category?.rootId
65
- ? categoriesRepository.getCategoriesByRootId(category.rootId).catch(() => [])
68
+ ? safeRead(() => categoriesRepository.getCategoriesByRootId(category.rootId), {
69
+ route: "/categories/[slug]",
70
+ key: "category.rootSiblings",
71
+ fallback: [],
72
+ })
73
+ : Promise.resolve([]),
74
+ category?.slug
75
+ ? safeRead(() => getGroupsForCategory(category.slug), {
76
+ route: "/categories/[slug]",
77
+ key: "category.groupedListings",
78
+ fallback: [],
79
+ })
66
80
  : Promise.resolve([]),
67
- category?.slug ? getGroupsForCategory(category.slug).catch(() => []) : Promise.resolve([]),
68
81
  // Listing/category-type feature flags. This page accepted the props all
69
82
  // along but never passed them, so an admin disabling a listing type still
70
83
  // saw its tab here while the store page correctly hid it.
71
- siteSettingsRepository.findById("global").catch(() => null),
84
+ safeRead(() => siteSettingsRepository.findById("global"), {
85
+ route: "/categories/[slug]",
86
+ key: "category.siteSettings",
87
+ fallback: null,
88
+ }),
72
89
  ]);
73
90
  const relatedCategories = rootSiblingCategories.filter((c) => c.id !== category?.id && (!c.categoryType || c.categoryType === "category"));
74
91
  // Stores tab — stores whose storeCategory is this category or ANY descendant.
@@ -82,18 +99,18 @@ export async function CategoryDetailPageView({ slug }) {
82
99
  // which caps at 30 values, hence the chunking.
83
100
  const storeCategorySlugs = [
84
101
  slug,
85
- ...(await categoriesRepository
86
- .getDescendantIds(category?.id ?? "")
87
- .catch(() => [])),
102
+ ...(await safeRead(() => categoriesRepository.getDescendantIds(category?.id ?? ""), {
103
+ route: "/categories/[slug]",
104
+ key: "category.descendantIds",
105
+ fallback: [],
106
+ })),
88
107
  ].filter(Boolean);
89
108
  const SLUG_CHUNK = 30;
90
109
  const slugChunks = [];
91
110
  for (let i = 0; i < storeCategorySlugs.length; i += SLUG_CHUNK) {
92
111
  slugChunks.push(storeCategorySlugs.slice(i, i + SLUG_CHUNK));
93
112
  }
94
- const storeResults = await Promise.all(slugChunks.map((chunk) => storeRepository
95
- .listStores({ filters: sieveFilter("storeCategory", SIEVE_OP.EQ, chunk.join("|")), page: 1, pageSize: 50 }, true)
96
- .catch(() => null)));
113
+ const storeResults = await Promise.all(slugChunks.map((chunk) => safeRead(() => storeRepository.listStores({ filters: sieveFilter("storeCategory", SIEVE_OP.EQ, chunk.join("|")), page: 1, pageSize: 50 }, true), { route: "/categories/[slug]", key: "category.stores", fallback: null })));
97
114
  const seen = new Set();
98
115
  const categoryStores = storeResults
99
116
  .flatMap((r) => r?.items ?? [])
@@ -480,10 +480,12 @@ export class CategoriesRepository extends BaseRepository {
480
480
  .collection(this.collection)
481
481
  .doc(categoryId)
482
482
  .update({ [CATEGORY_FIELDS.VIEW_COUNT]: increment(1) });
483
+ // Fire-and-forget analytics: a lost view increment changes nothing that
484
+ // renders, so it must never break the category read path it rides along
485
+ // with — the count is approximate by design.
483
486
  }
484
487
  catch (_err) {
485
488
  void normalizeError(_err);
486
- // View analytics must not break category read path.
487
489
  }
488
490
  }
489
491
  generateSublistingId(name) {