@mohasinac/appkit 2.7.27 → 2.7.31

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 (397) hide show
  1. package/dist/_internal/client/features/filters/filter-load-options.d.ts +29 -0
  2. package/dist/_internal/client/features/filters/filter-load-options.js +98 -0
  3. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +1 -1
  4. package/dist/_internal/server/features/checkout/actions.js +42 -35
  5. package/dist/_internal/server/features/classified/adapters.d.ts +21 -0
  6. package/dist/_internal/server/features/classified/adapters.js +24 -0
  7. package/dist/_internal/server/features/classified/index.d.ts +3 -0
  8. package/dist/_internal/server/features/classified/index.js +3 -0
  9. package/dist/_internal/server/features/classified/metadata.d.ts +8 -0
  10. package/dist/_internal/server/features/classified/metadata.js +43 -0
  11. package/dist/_internal/server/features/classified/og.d.ts +30 -0
  12. package/dist/_internal/server/features/classified/og.js +76 -0
  13. package/dist/_internal/server/features/digital-code/adapters.d.ts +21 -0
  14. package/dist/_internal/server/features/digital-code/adapters.js +29 -0
  15. package/dist/_internal/server/features/digital-code/index.d.ts +3 -0
  16. package/dist/_internal/server/features/digital-code/index.js +3 -0
  17. package/dist/_internal/server/features/digital-code/metadata.d.ts +8 -0
  18. package/dist/_internal/server/features/digital-code/metadata.js +36 -0
  19. package/dist/_internal/server/features/digital-code/og.d.ts +27 -0
  20. package/dist/_internal/server/features/digital-code/og.js +77 -0
  21. package/dist/_internal/server/features/live/adapters.d.ts +21 -0
  22. package/dist/_internal/server/features/live/adapters.js +34 -0
  23. package/dist/_internal/server/features/live/index.d.ts +3 -0
  24. package/dist/_internal/server/features/live/index.js +3 -0
  25. package/dist/_internal/server/features/live/metadata.d.ts +8 -0
  26. package/dist/_internal/server/features/live/metadata.js +39 -0
  27. package/dist/_internal/server/features/live/og.d.ts +27 -0
  28. package/dist/_internal/server/features/live/og.js +72 -0
  29. package/dist/_internal/server/features/promotions/actions.js +4 -3
  30. package/dist/_internal/server/jobs/core/onOrderCreate.js +19 -16
  31. package/dist/_internal/server/jobs/core/onOrderStatusChange.js +25 -22
  32. package/dist/_internal/server/jobs/core/onProductWrite.js +48 -58
  33. package/dist/_internal/shared/actions/action-registry.js +504 -9
  34. package/dist/_internal/shared/features/blog/schema.d.ts +4 -4
  35. package/dist/_internal/shared/features/brands/schema.d.ts +5 -5
  36. package/dist/_internal/shared/features/cart/schema.d.ts +18 -18
  37. package/dist/_internal/shared/features/categories/bundle-copy.d.ts +1 -1
  38. package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +38 -38
  39. package/dist/_internal/shared/features/events/schema.d.ts +8 -8
  40. package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
  41. package/dist/_internal/shared/features/products/schema.d.ts +42 -42
  42. package/dist/_internal/shared/features/promotions/schema.d.ts +4 -4
  43. package/dist/_internal/shared/features/reviews/schema.d.ts +1 -1
  44. package/dist/_internal/shared/media/limits.js +4 -3
  45. package/dist/client.d.ts +4 -0
  46. package/dist/client.js +2 -0
  47. package/dist/configs/next.js +4 -0
  48. package/dist/constants/api-endpoints.d.ts +6 -0
  49. package/dist/constants/api-endpoints.js +2 -0
  50. package/dist/constants/field-names.d.ts +1 -0
  51. package/dist/constants/field-names.js +1 -0
  52. package/dist/constants/table-keys.d.ts +6 -0
  53. package/dist/constants/table-keys.js +9 -0
  54. package/dist/core/hooks/useSyncManager.js +9 -8
  55. package/dist/features/about/components/FeesView.js +10 -7
  56. package/dist/features/about/components/HelpPageView.js +10 -1
  57. package/dist/features/about/components/HowAuctionsWorkView.js +10 -1
  58. package/dist/features/about/components/HowCheckoutWorksView.js +10 -1
  59. package/dist/features/about/components/HowOffersWorkView.js +10 -1
  60. package/dist/features/about/components/HowOrdersWorkView.js +10 -1
  61. package/dist/features/about/components/HowPayoutsWorkView.js +10 -1
  62. package/dist/features/about/components/HowPreOrdersWorkView.js +10 -1
  63. package/dist/features/about/components/HowReviewsWorkView.js +10 -1
  64. package/dist/features/about/components/PublicProfileView.js +46 -16
  65. package/dist/features/about/components/SecurityPrivacyView.js +7 -1
  66. package/dist/features/account/components/AddressesIndexListing.js +2 -2
  67. package/dist/features/account/components/NotificationBell.js +27 -16
  68. package/dist/features/account/components/NotificationPreferencesPanel.d.ts +9 -0
  69. package/dist/features/account/components/NotificationPreferencesPanel.js +91 -0
  70. package/dist/features/account/components/UserSidebar.js +4 -4
  71. package/dist/features/account/components/UserSupportView.js +16 -6
  72. package/dist/features/account/components/index.d.ts +2 -0
  73. package/dist/features/account/components/index.js +1 -0
  74. package/dist/features/account/schemas/index.d.ts +4 -4
  75. package/dist/features/account/types/index.d.ts +34 -0
  76. package/dist/features/admin/actions/admin-actions.js +4 -3
  77. package/dist/features/admin/actions/notification-actions.d.ts +24 -22
  78. package/dist/features/admin/actions/notification-actions.js +122 -22
  79. package/dist/features/admin/components/AdminAdEditorView.js +29 -15
  80. package/dist/features/admin/components/AdminAddressEditorView.d.ts +7 -0
  81. package/dist/features/admin/components/AdminAddressEditorView.js +117 -0
  82. package/dist/features/admin/components/AdminAdsView.js +22 -28
  83. package/dist/features/admin/components/AdminAllEventEntriesView.js +6 -1
  84. package/dist/features/admin/components/AdminBidsView.js +10 -3
  85. package/dist/features/admin/components/AdminBlogEditorView.js +2 -2
  86. package/dist/features/admin/components/AdminBlogView.js +8 -3
  87. package/dist/features/admin/components/AdminBrandsView.js +7 -2
  88. package/dist/features/admin/components/AdminBundleEditorView.js +5 -2
  89. package/dist/features/admin/components/AdminCarouselEditorView.js +6 -3
  90. package/dist/features/admin/components/AdminCarouselView.js +13 -7
  91. package/dist/features/admin/components/AdminCategoriesView.js +8 -3
  92. package/dist/features/admin/components/AdminCategoryEditorView.js +12 -9
  93. package/dist/features/admin/components/AdminContactView.js +6 -1
  94. package/dist/features/admin/components/AdminCouponEditorView.js +8 -2
  95. package/dist/features/admin/components/AdminCouponsView.js +6 -1
  96. package/dist/features/admin/components/AdminEmployeeEditorView.js +12 -9
  97. package/dist/features/admin/components/AdminFaqEditorView.js +2 -2
  98. package/dist/features/admin/components/AdminFaqsView.js +7 -2
  99. package/dist/features/admin/components/AdminFeatureFlagsView.js +58 -13
  100. package/dist/features/admin/components/AdminFeaturesView.js +4 -3
  101. package/dist/features/admin/components/AdminMediaView.js +9 -8
  102. package/dist/features/admin/components/AdminNavigationView.js +10 -17
  103. package/dist/features/admin/components/AdminNewsletterView.js +6 -1
  104. package/dist/features/admin/components/AdminNotificationsView.js +11 -3
  105. package/dist/features/admin/components/AdminOrdersView.js +6 -1
  106. package/dist/features/admin/components/AdminPayoutsView.js +10 -3
  107. package/dist/features/admin/components/AdminPrizeDrawsView.js +10 -3
  108. package/dist/features/admin/components/AdminProductEditorView.d.ts +3 -1
  109. package/dist/features/admin/components/AdminProductEditorView.js +12 -9
  110. package/dist/features/admin/components/AdminProductsView.js +18 -12
  111. package/dist/features/admin/components/AdminReturnRequestsView.js +5 -4
  112. package/dist/features/admin/components/AdminReviewsView.js +36 -26
  113. package/dist/features/admin/components/AdminScammerEditorView.js +3 -2
  114. package/dist/features/admin/components/AdminScammersView.js +28 -26
  115. package/dist/features/admin/components/AdminSectionsView.js +112 -99
  116. package/dist/features/admin/components/AdminSessionsView.js +10 -3
  117. package/dist/features/admin/components/AdminSidebar.js +4 -4
  118. package/dist/features/admin/components/AdminSiteSettingsView.js +45 -4
  119. package/dist/features/admin/components/AdminStoresView.js +6 -1
  120. package/dist/features/admin/components/AdminSublistingCategoriesView.js +0 -1
  121. package/dist/features/admin/components/AdminSupportTicketDetailView.js +1 -1
  122. package/dist/features/admin/components/AdminSupportTicketsView.js +32 -34
  123. package/dist/features/admin/components/AdminTeamView.js +6 -1
  124. package/dist/features/admin/components/AdminUserEditorView.js +8 -15
  125. package/dist/features/admin/components/AdminUsersView.js +6 -1
  126. package/dist/features/admin/components/AdminViewCards.js +4 -3
  127. package/dist/features/admin/components/DashboardStats.js +2 -2
  128. package/dist/features/admin/components/DataTable.js +2 -2
  129. package/dist/features/admin/components/index.d.ts +2 -0
  130. package/dist/features/admin/components/index.js +1 -0
  131. package/dist/features/admin/components/sections/adminSectionsTypes.js +4 -3
  132. package/dist/features/admin/repository/chat.repository.js +8 -8
  133. package/dist/features/admin/repository/site-settings.repository.d.ts +1 -0
  134. package/dist/features/admin/repository/site-settings.repository.js +11 -9
  135. package/dist/features/admin/schemas/firestore.d.ts +38 -0
  136. package/dist/features/admin/schemas/firestore.js +15 -0
  137. package/dist/features/auctions/components/AuctionBidsTable.d.ts +13 -0
  138. package/dist/features/auctions/components/AuctionBidsTable.js +62 -0
  139. package/dist/features/auctions/components/AuctionDetailPageView.js +15 -21
  140. package/dist/features/auctions/components/AuctionFilters.d.ts +7 -1
  141. package/dist/features/auctions/components/AuctionFilters.js +3 -2
  142. package/dist/features/auctions/components/MarketplaceAuctionCard.js +18 -9
  143. package/dist/features/auctions/components/MarketplaceAuctionGrid.js +3 -2
  144. package/dist/features/auctions/components/index.d.ts +2 -1
  145. package/dist/features/auctions/components/index.js +1 -1
  146. package/dist/features/auctions/schemas/index.d.ts +14 -14
  147. package/dist/features/auth/actions/realtime-token-actions.js +19 -4
  148. package/dist/features/auth/components/RegisterForm.js +8 -4
  149. package/dist/features/auth/consent-otp.d.ts +2 -0
  150. package/dist/features/auth/consent-otp.js +8 -0
  151. package/dist/features/auth/schemas/firestore.d.ts +2 -0
  152. package/dist/features/auth/schemas/firestore.js +18 -25
  153. package/dist/features/auth/schemas/index.d.ts +2 -2
  154. package/dist/features/before-after/api/[id]/route.js +8 -6
  155. package/dist/features/before-after/schemas/index.d.ts +2 -2
  156. package/dist/features/blog/actions/blog-actions.d.ts +3 -3
  157. package/dist/features/blog/components/BlogIndexListing.js +21 -2
  158. package/dist/features/blog/components/BlogPostForm.js +11 -5
  159. package/dist/features/blog/components/BlogPostView.js +10 -2
  160. package/dist/features/blog/schemas/index.d.ts +18 -18
  161. package/dist/features/cart/components/CartDrawer.js +3 -2
  162. package/dist/features/cart/components/CartView.js +2 -1
  163. package/dist/features/cart/components/CheckoutView.js +2 -1
  164. package/dist/features/cart/repository/cart.repository.js +4 -3
  165. package/dist/features/cart/utils/pending-ops.d.ts +1 -1
  166. package/dist/features/categories/api/[id]/route.js +4 -3
  167. package/dist/features/categories/api/route.js +4 -3
  168. package/dist/features/categories/components/BrandDetailPageView.js +2 -2
  169. package/dist/features/categories/components/BrandDetailTabs.d.ts +5 -1
  170. package/dist/features/categories/components/BrandDetailTabs.js +30 -16
  171. package/dist/features/categories/components/BundleCollage.d.ts +8 -0
  172. package/dist/features/categories/components/BundleCollage.js +50 -0
  173. package/dist/features/categories/components/BundleDetailView.js +2 -10
  174. package/dist/features/categories/components/BundleItemsPicker.js +20 -13
  175. package/dist/features/categories/components/CategoriesIndexListing.js +28 -9
  176. package/dist/features/categories/components/CategoryDetailPageView.js +2 -2
  177. package/dist/features/categories/components/CategoryDetailTabs.d.ts +5 -1
  178. package/dist/features/categories/components/CategoryDetailTabs.js +31 -16
  179. package/dist/features/categories/components/CategoryProductsListing.js +52 -13
  180. package/dist/features/categories/components/index.d.ts +2 -0
  181. package/dist/features/categories/components/index.js +1 -0
  182. package/dist/features/categories/schemas/index.d.ts +6 -6
  183. package/dist/features/checkout/actions/checkout-actions.js +4 -3
  184. package/dist/features/checkout/hooks/usePaymentCheckout.js +31 -22
  185. package/dist/features/classified/components/ClassifiedFilters.d.ts +12 -0
  186. package/dist/features/classified/components/ClassifiedFilters.js +20 -0
  187. package/dist/features/classified/components/ClassifiedIndexListing.d.ts +4 -0
  188. package/dist/features/classified/components/ClassifiedIndexListing.js +110 -0
  189. package/dist/features/classified/components/ClassifiedListView.d.ts +6 -0
  190. package/dist/features/classified/components/ClassifiedListView.js +43 -0
  191. package/dist/features/classified/components/index.d.ts +6 -0
  192. package/dist/features/classified/components/index.js +3 -0
  193. package/dist/features/collections/api/[slug]/route.js +16 -12
  194. package/dist/features/collections/schemas/index.d.ts +5 -5
  195. package/dist/features/consultation/api/[id]/route.js +12 -9
  196. package/dist/features/consultation/components/ConsultationForm.js +3 -2
  197. package/dist/features/consultation/schemas/index.d.ts +6 -6
  198. package/dist/features/contact/email.js +77 -116
  199. package/dist/features/copilot/components/AdminCopilotView.js +12 -2
  200. package/dist/features/corporate/api/[id]/route.js +12 -9
  201. package/dist/features/corporate/components/CorporateInquiryForm.js +2 -1
  202. package/dist/features/digital-codes/components/DigitalCodeFilters.d.ts +12 -0
  203. package/dist/features/digital-codes/components/DigitalCodeFilters.js +17 -0
  204. package/dist/features/digital-codes/components/DigitalCodesIndexListing.d.ts +4 -0
  205. package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +107 -0
  206. package/dist/features/digital-codes/components/DigitalCodesListView.d.ts +6 -0
  207. package/dist/features/digital-codes/components/DigitalCodesListView.js +37 -0
  208. package/dist/features/digital-codes/components/index.d.ts +6 -0
  209. package/dist/features/digital-codes/components/index.js +3 -0
  210. package/dist/features/events/actions/event-actions.js +4 -3
  211. package/dist/features/events/components/AdminEventEditorView.js +3 -2
  212. package/dist/features/events/components/AdminEventsView.js +4 -2
  213. package/dist/features/events/components/EventPollWidget.js +5 -5
  214. package/dist/features/events/components/EventsIndexListing.js +2 -2
  215. package/dist/features/events/repository/event-entry.repository.d.ts +1 -0
  216. package/dist/features/events/repository/event-entry.repository.js +5 -0
  217. package/dist/features/events/schemas/index.d.ts +20 -20
  218. package/dist/features/faq/actions/faq-actions.d.ts +8 -8
  219. package/dist/features/faq/components/ContactCTA.js +3 -1
  220. package/dist/features/faq/components/FAQAccordion.js +1 -1
  221. package/dist/features/faq/schemas/index.d.ts +4 -4
  222. package/dist/features/filters/AsyncFacetSection.d.ts +18 -0
  223. package/dist/features/filters/AsyncFacetSection.js +65 -0
  224. package/dist/features/filters/index.d.ts +2 -0
  225. package/dist/features/filters/index.js +1 -0
  226. package/dist/features/forms/Checkbox.js +2 -2
  227. package/dist/features/forms/Input.js +2 -2
  228. package/dist/features/forms/Radio.js +5 -5
  229. package/dist/features/forms/Select.js +2 -2
  230. package/dist/features/forms/Slider.js +2 -2
  231. package/dist/features/forms/Textarea.js +2 -2
  232. package/dist/features/homepage/api/[id]/route.js +4 -3
  233. package/dist/features/homepage/api/sections/[id]/route.js +12 -9
  234. package/dist/features/homepage/components/AdSlot.js +2 -1
  235. package/dist/features/homepage/components/AdvertisementBanner.js +5 -3
  236. package/dist/features/homepage/components/BrandsSection.js +2 -2
  237. package/dist/features/homepage/components/CTABannerSection.js +2 -2
  238. package/dist/features/homepage/components/CharacterHotspot.d.ts +2 -2
  239. package/dist/features/homepage/components/CharacterHotspot.js +119 -157
  240. package/dist/features/homepage/components/CharacterHotspotForm.js +25 -20
  241. package/dist/features/homepage/components/CustomCardsSection.js +8 -6
  242. package/dist/features/homepage/components/FeaturedProductsSection.js +2 -2
  243. package/dist/features/homepage/components/GoogleReviewsSection.js +3 -3
  244. package/dist/features/homepage/components/HeroBanner.js +5 -4
  245. package/dist/features/homepage/components/HeroCarousel.js +13 -26
  246. package/dist/features/homepage/components/HowItWorksSection.js +4 -2
  247. package/dist/features/homepage/components/SocialFeedSection.js +2 -2
  248. package/dist/features/homepage/components/SocialPostCard.js +3 -2
  249. package/dist/features/homepage/lib/social-feed-fetcher.js +6 -3
  250. package/dist/features/layout/AppLayoutShell.d.ts +8 -2
  251. package/dist/features/layout/AppLayoutShell.js +54 -78
  252. package/dist/features/layout/BottomActions.js +43 -48
  253. package/dist/features/live/components/LiveItemFilters.d.ts +12 -0
  254. package/dist/features/live/components/LiveItemFilters.js +24 -0
  255. package/dist/features/live/components/LiveItemsIndexListing.d.ts +4 -0
  256. package/dist/features/live/components/LiveItemsIndexListing.js +108 -0
  257. package/dist/features/live/components/LiveItemsListView.d.ts +6 -0
  258. package/dist/features/live/components/LiveItemsListView.js +43 -0
  259. package/dist/features/live/components/index.d.ts +6 -0
  260. package/dist/features/live/components/index.js +3 -0
  261. package/dist/features/media/MediaLightbox.js +8 -14
  262. package/dist/features/media/types/index.d.ts +2 -2
  263. package/dist/features/media/upload/CameraCapture.js +2 -2
  264. package/dist/features/media/upload/ImageUpload.js +4 -2
  265. package/dist/features/media/upload/MediaUploadField.js +24 -8
  266. package/dist/features/media/upload/MediaUploadList.js +1 -1
  267. package/dist/features/orders/actions/order-actions.js +4 -3
  268. package/dist/features/orders/components/MarketplaceOrderCard.js +2 -1
  269. package/dist/features/orders/components/OrderFilters.js +12 -9
  270. package/dist/features/orders/schemas/index.d.ts +6 -6
  271. package/dist/features/pre-orders/api/[id]/route.js +12 -9
  272. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +5 -4
  273. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +29 -22
  274. package/dist/features/pre-orders/components/PreOrderFilters.d.ts +7 -1
  275. package/dist/features/pre-orders/components/PreOrderFilters.js +3 -2
  276. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +17 -52
  277. package/dist/features/pre-orders/components/PreorderCard.d.ts +0 -9
  278. package/dist/features/pre-orders/components/PreorderCard.js +2 -13
  279. package/dist/features/pre-orders/components/index.d.ts +1 -1
  280. package/dist/features/pre-orders/components/index.js +1 -1
  281. package/dist/features/pre-orders/schemas/index.d.ts +10 -10
  282. package/dist/features/products/api/[id]/route.js +9 -7
  283. package/dist/features/products/api/route.js +1 -1
  284. package/dist/features/products/columns/productTableColumns.js +3 -3
  285. package/dist/features/products/components/AuctionsIndexListing.js +15 -51
  286. package/dist/features/products/components/BidHistory.js +2 -2
  287. package/dist/features/products/components/CompareOverlay.d.ts +2 -0
  288. package/dist/features/products/components/CompareOverlay.js +3 -2
  289. package/dist/features/products/components/MakeOfferButton.js +20 -14
  290. package/dist/features/products/components/MarketplacePrizeDrawCard.js +2 -1
  291. package/dist/features/products/components/PrizeDrawCollage.d.ts +1 -15
  292. package/dist/features/products/components/PrizeDrawCollage.js +54 -14
  293. package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -1
  294. package/dist/features/products/components/PrizeDrawEntryActions.js +2 -1
  295. package/dist/features/products/components/PrizeDrawItemsEditor.js +9 -7
  296. package/dist/features/products/components/PrizeDrawsIndexListing.js +18 -51
  297. package/dist/features/products/components/PrizeRevealModal.js +24 -14
  298. package/dist/features/products/components/ProductDetailPageView.js +2 -1
  299. package/dist/features/products/components/ProductFilters.d.ts +7 -1
  300. package/dist/features/products/components/ProductFilters.js +11 -8
  301. package/dist/features/products/components/ProductForm.js +18 -16
  302. package/dist/features/products/components/ProductGalleryClient.js +2 -1
  303. package/dist/features/products/components/ProductGrid.js +12 -15
  304. package/dist/features/products/components/ProductsIndexListing.js +16 -52
  305. package/dist/features/products/components/ProductsIndexPageView.js +2 -2
  306. package/dist/features/products/repository/products.repository.d.ts +4 -0
  307. package/dist/features/products/repository/products.repository.js +22 -3
  308. package/dist/features/products/schemas/firestore.d.ts +7 -1
  309. package/dist/features/products/schemas/index.d.ts +56 -56
  310. package/dist/features/products/schemas/product-features.validators.d.ts +14 -14
  311. package/dist/features/products/types/index.d.ts +4 -0
  312. package/dist/features/promotions/components/CouponsIndexListing.js +1 -1
  313. package/dist/features/promotions/schemas/index.d.ts +6 -6
  314. package/dist/features/reviews/actions/review-actions.js +6 -5
  315. package/dist/features/reviews/api/[id]/route.js +4 -3
  316. package/dist/features/reviews/components/ReviewDetailPageView.js +2 -2
  317. package/dist/features/reviews/components/ReviewDetailShell.js +6 -3
  318. package/dist/features/reviews/components/ReviewsIndexListing.js +2 -2
  319. package/dist/features/reviews/schemas/index.d.ts +6 -6
  320. package/dist/features/scams/components/ScamProfileView.js +19 -10
  321. package/dist/features/scams/components/ScamRegistryView.js +2 -1
  322. package/dist/features/search/components/Search.d.ts +1 -1
  323. package/dist/features/search/components/Search.js +56 -49
  324. package/dist/features/search/schemas/index.d.ts +5 -5
  325. package/dist/features/seller/actions/offer-actions.js +11 -9
  326. package/dist/features/seller/components/SellerAddressesView.js +6 -4
  327. package/dist/features/seller/components/SellerBidsView.js +2 -2
  328. package/dist/features/seller/components/SellerCouponsView.js +1 -1
  329. package/dist/features/seller/components/SellerOffersPanel.js +6 -1
  330. package/dist/features/seller/components/SellerOrdersView.js +1 -1
  331. package/dist/features/seller/components/SellerPayoutSettingsView.js +3 -3
  332. package/dist/features/seller/components/SellerPreOrdersView.js +5 -4
  333. package/dist/features/seller/components/SellerPrizeDrawsView.js +5 -4
  334. package/dist/features/seller/components/SellerProductShell.d.ts +19 -1
  335. package/dist/features/seller/components/SellerProductShell.js +75 -9
  336. package/dist/features/seller/components/SellerProductsView.js +10 -11
  337. package/dist/features/seller/components/SellerShippingView.js +3 -3
  338. package/dist/features/seller/components/SellerSidebar.js +10 -7
  339. package/dist/features/seller/components/SellerStorefrontView.js +3 -3
  340. package/dist/features/seller/schemas/index.d.ts +4 -4
  341. package/dist/features/shell/FormShell.js +2 -1
  342. package/dist/features/shell/QuickFormDrawer.js +4 -3
  343. package/dist/features/shell/StepForm.js +4 -3
  344. package/dist/features/stores/actions/store-query-actions.js +4 -3
  345. package/dist/features/stores/components/StoreAboutView.js +2 -1
  346. package/dist/features/stores/components/StoreAuctionsListing.js +43 -64
  347. package/dist/features/stores/components/StoreDetailLayoutView.js +18 -4
  348. package/dist/features/stores/components/StorePreOrdersListing.js +33 -57
  349. package/dist/features/stores/components/StoreProductsListing.js +16 -49
  350. package/dist/features/stores/components/StoresIndexListing.js +2 -2
  351. package/dist/features/stores/schemas/index.d.ts +2 -2
  352. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +8 -7
  353. package/dist/features/wishlist/hooks/useGuestWishlist.d.ts +5 -5
  354. package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +6 -6
  355. package/dist/features/wishlist/utils/guest-wishlist.d.ts +5 -5
  356. package/dist/index.d.ts +27 -3
  357. package/dist/index.js +1743 -1725
  358. package/dist/monitoring/server-logger.js +5 -9
  359. package/dist/next/api/apiHandler.js +56 -37
  360. package/dist/next/components/GlobalError.js +2 -1
  361. package/dist/next/routing/route-map.d.ts +41 -0
  362. package/dist/next/routing/route-map.js +17 -0
  363. package/dist/react/ErrorBoundary.js +2 -1
  364. package/dist/react/contexts/SessionContext.js +38 -28
  365. package/dist/react/hooks/useCamera.d.ts +1 -1
  366. package/dist/react/hooks/useCamera.js +8 -7
  367. package/dist/seed/products-auctions-seed-data.js +40 -40
  368. package/dist/seed/products-preorders-seed-data.js +16 -16
  369. package/dist/seed/products-prize-draws-seed-data.js +4 -4
  370. package/dist/seed/products-standard-seed-data.js +202 -202
  371. package/dist/seed/site-settings-seed-data.js +6 -0
  372. package/dist/server-entry.d.ts +3 -0
  373. package/dist/server-entry.js +3 -0
  374. package/dist/server.d.ts +12 -0
  375. package/dist/server.js +15 -0
  376. package/dist/tailwind-utilities.css +1 -1
  377. package/dist/ui/DataTable.js +28 -7
  378. package/dist/ui/components/Button.d.ts +8 -1
  379. package/dist/ui/components/Button.js +47 -8
  380. package/dist/ui/components/CollageLightbox.d.ts +18 -0
  381. package/dist/ui/components/CollageLightbox.js +41 -0
  382. package/dist/ui/components/Dropdown.js +7 -6
  383. package/dist/ui/components/ImageLightbox.d.ts +7 -1
  384. package/dist/ui/components/ImageLightbox.js +15 -5
  385. package/dist/ui/components/PageLoader.js +4 -3
  386. package/dist/ui/components/PaginatedMultiSelect.d.ts +28 -0
  387. package/dist/ui/components/PaginatedMultiSelect.js +141 -0
  388. package/dist/ui/components/PaginatedMultiSelect.style.css +272 -0
  389. package/dist/ui/components/Semantic.js +1 -1
  390. package/dist/ui/components/SideDrawer.js +17 -15
  391. package/dist/ui/components/index.style.css +1 -0
  392. package/dist/ui/index.d.ts +2 -0
  393. package/dist/ui/index.js +1 -0
  394. package/dist/utils/number.formatter.js +5 -13
  395. package/dist/utils/string.formatter.js +21 -18
  396. package/dist/validation/schemas.d.ts +2 -2
  397. package/package.json +1 -1
@@ -115,13 +115,14 @@ export declare const categoryItemSchema: z.ZodObject<{
115
115
  updatedAt: z.ZodOptional<z.ZodString>;
116
116
  }, "strip", z.ZodTypeAny, {
117
117
  id: string;
118
- name: string;
119
118
  slug: string;
119
+ name: string;
120
120
  tier: number;
121
121
  createdAt?: string | undefined;
122
122
  updatedAt?: string | undefined;
123
123
  path?: string | undefined;
124
124
  type?: "category" | "brand" | "collection" | "concern" | undefined;
125
+ description?: string | undefined;
125
126
  display?: {
126
127
  icon?: string | undefined;
127
128
  showInMenu?: boolean | undefined;
@@ -129,7 +130,6 @@ export declare const categoryItemSchema: z.ZodObject<{
129
130
  } | undefined;
130
131
  order?: number | undefined;
131
132
  isFeatured?: boolean | undefined;
132
- description?: string | undefined;
133
133
  seo?: {
134
134
  title?: string | undefined;
135
135
  description?: string | undefined;
@@ -148,13 +148,14 @@ export declare const categoryItemSchema: z.ZodObject<{
148
148
  } | undefined;
149
149
  }, {
150
150
  id: string;
151
- name: string;
152
151
  slug: string;
152
+ name: string;
153
153
  tier: number;
154
154
  createdAt?: string | undefined;
155
155
  updatedAt?: string | undefined;
156
156
  path?: string | undefined;
157
157
  type?: "category" | "brand" | "collection" | "concern" | undefined;
158
+ description?: string | undefined;
158
159
  display?: {
159
160
  icon?: string | undefined;
160
161
  showInMenu?: boolean | undefined;
@@ -162,7 +163,6 @@ export declare const categoryItemSchema: z.ZodObject<{
162
163
  } | undefined;
163
164
  order?: number | undefined;
164
165
  isFeatured?: boolean | undefined;
165
- description?: string | undefined;
166
166
  seo?: {
167
167
  title?: string | undefined;
168
168
  description?: string | undefined;
@@ -192,16 +192,16 @@ export declare const categoryListParamsSchema: z.ZodObject<{
192
192
  perPage?: number | undefined;
193
193
  type?: "category" | "brand" | "collection" | "concern" | undefined;
194
194
  q?: string | undefined;
195
- page?: number | undefined;
196
195
  featured?: boolean | undefined;
196
+ page?: number | undefined;
197
197
  tier?: number | undefined;
198
198
  parentId?: string | undefined;
199
199
  }, {
200
200
  perPage?: number | undefined;
201
201
  type?: "category" | "brand" | "collection" | "concern" | undefined;
202
202
  q?: string | undefined;
203
- page?: number | undefined;
204
203
  featured?: boolean | undefined;
204
+ page?: number | undefined;
205
205
  tier?: number | undefined;
206
206
  parentId?: string | undefined;
207
207
  }>;
@@ -11,6 +11,7 @@ import { serverLogger } from "../../../monitoring";
11
11
  import { sendEmail } from "../../contact/email";
12
12
  import { CONSENT_OTP_EXPIRY_MS, CONSENT_OTP_MAX_ATTEMPTS, hashOtp, maskEmail, generateOtpCode, buildConsentOtpEmail, enforceConsentOtpRateLimit, saveConsentOtp, readConsentOtp, patchConsentOtp, } from "../../auth/consent-otp";
13
13
  import { addressesRepository } from "../../addresses/repository/addresses.repository";
14
+ const ERR_ADDRESS_NOT_FOUND = "Address not found.";
14
15
  async function findUserAddress(userId, addressId) {
15
16
  const address = await addressesRepository.findById(addressId);
16
17
  if (!address || address.ownerType !== "user" || address.ownerId !== userId) {
@@ -24,7 +25,7 @@ import { resolveDate } from "../../../utils";
24
25
  export async function sendCheckoutConsentOtp(userId, userEmail, addressId) {
25
26
  const address = await findUserAddress(userId, addressId);
26
27
  if (!address)
27
- throw new ValidationError("Address not found.");
28
+ throw new ValidationError(ERR_ADDRESS_NOT_FOUND);
28
29
  await enforceConsentOtpRateLimit(userId);
29
30
  const code = generateOtpCode();
30
31
  const codeHash = hashOtp(code);
@@ -78,7 +79,7 @@ export async function grantCheckoutConsentViaSms(userId, userPhone, addressId) {
78
79
  throw new ValidationError("No phone number registered on your account.");
79
80
  const address = await findUserAddress(userId, addressId);
80
81
  if (!address)
81
- throw new ValidationError("Address not found.");
82
+ throw new ValidationError(ERR_ADDRESS_NOT_FOUND);
82
83
  const normalizePhone = (s) => s.replace(/[^0-9]/g, "").slice(-10);
83
84
  if (normalizePhone(address.phone) !== normalizePhone(userPhone)) {
84
85
  throw new ValidationError("Phone number does not match the shipping address. Please use email verification for this address.");
@@ -107,7 +108,7 @@ export async function grantCheckoutConsentViaSms(userId, userPhone, addressId) {
107
108
  export async function grantAdminCheckoutBypass(userId, addressId, bypassingAdminUid) {
108
109
  const address = await findUserAddress(userId, addressId);
109
110
  if (!address)
110
- throw new ValidationError("Address not found.");
111
+ throw new ValidationError(ERR_ADDRESS_NOT_FOUND);
111
112
  await saveConsentOtp(userId, addressId, {
112
113
  codeHash: "",
113
114
  expiresAt: new Date(Date.now() + CONSENT_OTP_EXPIRY_MS),
@@ -3,6 +3,29 @@ import { useCallback, useRef, useState } from "react";
3
3
  import { getClientPaymentGateway } from "../../../contracts/client-payment-gateway";
4
4
  import { useCheckout as useCheckoutApi } from "../hooks/useCheckoutApi";
5
5
  import { usePaymentEvent, } from "../../payments/hooks/usePaymentEvent";
6
+ // --- Helpers ---------------------------------------------------------------
7
+ async function openGatewayStep(adapter, orderResponse, params) {
8
+ try {
9
+ await adapter.loadScript();
10
+ const response = await adapter.openPayment({
11
+ gatewayOrderId: orderResponse.gatewayOrderId,
12
+ publicKey: orderResponse.keyId,
13
+ amount: orderResponse.amount,
14
+ currency: orderResponse.currency,
15
+ merchantName: params.merchantName,
16
+ logoUrl: params.logoUrl,
17
+ prefill: params.prefill,
18
+ theme: params.themeColor ? { color: params.themeColor } : undefined,
19
+ });
20
+ return { response, cancelled: false, error: null };
21
+ }
22
+ catch (err) {
23
+ if (err instanceof Error && err.message.toLowerCase().includes("cancel")) {
24
+ return { response: null, cancelled: true, error: null };
25
+ }
26
+ return { response: null, cancelled: false, error: err instanceof Error ? err : new Error("Payment gateway error") };
27
+ }
28
+ }
6
29
  // --- Hook ------------------------------------------------------------------
7
30
  const INITIAL_STATE = {
8
31
  step: "idle",
@@ -101,31 +124,17 @@ export function usePaymentCheckout(options) {
101
124
  return null;
102
125
  // Step 2: Open gateway modal
103
126
  setState((s) => ({ ...s, step: "awaiting_payment" }));
104
- let gatewayResponse;
105
- try {
106
- const adapter = getAdapter();
107
- await adapter.loadScript();
108
- gatewayResponse = await adapter.openPayment({
109
- gatewayOrderId: orderResponse.gatewayOrderId,
110
- publicKey: orderResponse.keyId,
111
- amount: orderResponse.amount,
112
- currency: orderResponse.currency,
113
- merchantName,
114
- logoUrl,
115
- prefill: params.prefill,
116
- theme: themeColor ? { color: themeColor } : undefined,
117
- });
127
+ const gatewayResult = await openGatewayStep(getAdapter(), orderResponse, { prefill: params.prefill, merchantName, logoUrl, themeColor });
128
+ if (gatewayResult.cancelled) {
129
+ setState((s) => ({ ...s, step: "cancelled", error: null }));
130
+ onCancel?.();
131
+ return null;
118
132
  }
119
- catch (err) {
120
- if (err instanceof Error &&
121
- err.message.toLowerCase().includes("cancel")) {
122
- setState((s) => ({ ...s, step: "cancelled", error: null }));
123
- onCancel?.();
124
- return null;
125
- }
126
- setError(err instanceof Error ? err : new Error("Payment gateway error"));
133
+ if (gatewayResult.error || !gatewayResult.response) {
134
+ setError(gatewayResult.error ?? new Error("Payment gateway error"));
127
135
  return null;
128
136
  }
137
+ const gatewayResponse = gatewayResult.response;
129
138
  if (abortRef.current)
130
139
  return null;
131
140
  // Step 3: Verify payment on server
@@ -0,0 +1,12 @@
1
+ import type { FacetOption } from "../../filters/FilterFacetSection";
2
+ import type { UrlTable } from "../../filters/FilterPanel";
3
+ import type { AsyncFacetSectionProps } from "../../filters/AsyncFacetSection";
4
+ type LoadOptionsFn = AsyncFacetSectionProps["loadOptions"];
5
+ export interface ClassifiedFiltersProps {
6
+ table: UrlTable;
7
+ categoryOptions?: FacetOption[];
8
+ loadCategoryOptions?: LoadOptionsFn;
9
+ currencyPrefix?: string;
10
+ }
11
+ export declare function ClassifiedFilters({ table, categoryOptions, loadCategoryOptions, currencyPrefix, }: ClassifiedFiltersProps): import("react/jsx-runtime").JSX.Element;
12
+ export {};
@@ -0,0 +1,20 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { FilterFacetSection } from "../../filters/FilterFacetSection";
4
+ import { AsyncFacetSection } from "../../filters/AsyncFacetSection";
5
+ import { RangeFilter } from "../../filters/RangeFilter";
6
+ import { Div } from "../../../ui";
7
+ const NEGOTIABLE_OPTIONS = [
8
+ { value: "true", label: "Negotiable only" },
9
+ ];
10
+ const SHIPPING_OPTIONS = [
11
+ { value: "true", label: "Accepts shipping" },
12
+ ];
13
+ export function ClassifiedFilters({ table, categoryOptions = [], loadCategoryOptions, currencyPrefix = "₹", }) {
14
+ const selectedCategories = table.get("category")
15
+ ? table.get("category").split("|").filter(Boolean)
16
+ : [];
17
+ const selectedNegotiable = table.get("negotiable") ? [table.get("negotiable")] : [];
18
+ const selectedShipping = table.get("acceptsShipping") ? [table.get("acceptsShipping")] : [];
19
+ return (_jsxs(Div, { children: [loadCategoryOptions ? (_jsx(AsyncFacetSection, { title: "Category", loadOptions: loadCategoryOptions, selected: selectedCategories, onChange: (vals) => table.set("category", vals.join("|")), defaultCollapsed: false })) : categoryOptions.length > 0 ? (_jsx(FilterFacetSection, { title: "Category", options: categoryOptions, selected: selectedCategories, onChange: (vals) => table.set("category", vals.join("|")), searchable: true, defaultCollapsed: categoryOptions.length > 6 })) : null, _jsxs("div", { className: "border-t border-[var(--appkit-color-border)] pt-4 mt-4", children: [_jsx("label", { className: "block text-sm font-medium text-[var(--appkit-color-text)] mb-2", children: "City / Area" }), _jsx("input", { type: "text", value: table.get("city") || "", onChange: (e) => table.set("city", e.target.value), placeholder: "e.g. Mumbai", className: "w-full rounded-lg border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-3 py-2 text-sm text-[var(--appkit-color-text)] placeholder-[var(--appkit-color-text-faint)] focus:outline-none focus:ring-2 focus:ring-[var(--appkit-color-primary)]" })] }), _jsx(FilterFacetSection, { title: "Negotiable", options: NEGOTIABLE_OPTIONS, selected: selectedNegotiable, onChange: (vals) => table.set("negotiable", vals[0] ?? ""), searchable: false, selectionMode: "single", defaultCollapsed: false }), _jsx(FilterFacetSection, { title: "Shipping", options: SHIPPING_OPTIONS, selected: selectedShipping, onChange: (vals) => table.set("acceptsShipping", vals[0] ?? ""), searchable: false, selectionMode: "single", defaultCollapsed: false }), _jsx(RangeFilter, { title: "Asking Price", minValue: table.get("minPrice"), maxValue: table.get("maxPrice"), onMinChange: (v) => table.set("minPrice", v), onMaxChange: (v) => table.set("maxPrice", v), prefix: currencyPrefix, showSlider: true, minBound: 0, maxBound: 500000, step: 100, minPlaceholder: "Min price", maxPlaceholder: "Max price", defaultCollapsed: false })] }));
20
+ }
@@ -0,0 +1,4 @@
1
+ export interface ClassifiedIndexListingProps {
2
+ initialData?: any;
3
+ }
4
+ export declare function ClassifiedIndexListing({ initialData }: ClassifiedIndexListingProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,110 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState, useCallback } from "react";
4
+ import { useUrlTable } from "../../../react/hooks/useUrlTable";
5
+ import { useProducts } from "../../products/hooks/useProducts";
6
+ import { BulkActionBar, FilterDrawer, ListingToolbar, LoginRequiredModal, Pagination, Text } from "../../../ui";
7
+ import { usePendingTable } from "../../../react/hooks/usePendingTable";
8
+ import { useAuthGate } from "../../../react/hooks/useAuthGate";
9
+ import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
10
+ import { useGuestWishlist } from "../../wishlist/hooks/useGuestWishlist";
11
+ import { pushWishlistOp } from "../../cart/utils/pending-ops";
12
+ import { useCategoryTree, categoriesToFacetOptions } from "../../categories/hooks/useCategoryTree";
13
+ import { TABLE_KEYS, VIEW_MODE } from "../../../constants/table-keys";
14
+ import { sortBy } from "../../../constants/sort";
15
+ import { PRODUCT_FIELDS } from "../../../constants/field-names";
16
+ import { ROUTES } from "../../../next";
17
+ import { InteractiveProductCard } from "../../products/components/InteractiveProductCard";
18
+ import { ClassifiedFilters } from "./ClassifiedFilters";
19
+ import { ACTION_ID } from "../../products/constants/action-defs";
20
+ import { useToast } from "../../../ui";
21
+ const DEFAULT_SORT = sortBy(PRODUCT_FIELDS.CREATED_AT);
22
+ const SORT_OPTIONS = [
23
+ { value: sortBy(PRODUCT_FIELDS.CREATED_AT), label: "Newest First" },
24
+ { value: sortBy(PRODUCT_FIELDS.CREATED_AT, "ASC"), label: "Oldest First" },
25
+ { value: sortBy(PRODUCT_FIELDS.PRICE, "ASC"), label: "Price: Low to High" },
26
+ { value: sortBy(PRODUCT_FIELDS.PRICE), label: "Price: High to Low" },
27
+ ];
28
+ const FILTER_KEYS = [
29
+ TABLE_KEYS.CATEGORY,
30
+ TABLE_KEYS.CITY,
31
+ TABLE_KEYS.MIN_PRICE,
32
+ TABLE_KEYS.MAX_PRICE,
33
+ TABLE_KEYS.NEGOTIABLE,
34
+ TABLE_KEYS.ACCEPTS_SHIPPING,
35
+ ];
36
+ export function ClassifiedIndexListing({ initialData }) {
37
+ const table = useUrlTable({ defaults: { pageSize: "24", sort: DEFAULT_SORT } });
38
+ const { showToast } = useToast();
39
+ const { requireAuth, modalOpen, modalMessage, closeModal } = useAuthGate();
40
+ const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
41
+ const [filterOpen, setFilterOpen] = useState(false);
42
+ const [view, setView] = useState(table.get(TABLE_KEYS.VIEW) || VIEW_MODE.GRID);
43
+ const localWishlist = useGuestWishlist();
44
+ const { categories } = useCategoryTree();
45
+ const categoryOptions = categoriesToFacetOptions(categories);
46
+ const wishlistedIds = new Set(localWishlist.items.filter((i) => i.type === "classified").map((i) => i.itemId));
47
+ const { pendingTable, filterActiveCount, onFilterApply, onFilterClear, onFilterReset } = usePendingTable(table, FILTER_KEYS);
48
+ const openFilters = useCallback(() => {
49
+ onFilterReset();
50
+ setFilterOpen(true);
51
+ }, [onFilterReset]);
52
+ const applyFilters = useCallback(() => {
53
+ onFilterApply();
54
+ setFilterOpen(false);
55
+ }, [onFilterApply]);
56
+ const resetAll = useCallback(() => {
57
+ table.setMany({ [TABLE_KEYS.QUERY]: "", [TABLE_KEYS.SORT]: "" });
58
+ onFilterClear();
59
+ setSearchInput("");
60
+ }, [table, onFilterClear]);
61
+ const hasActiveState = !!table.get(TABLE_KEYS.QUERY) ||
62
+ table.get(TABLE_KEYS.SORT) !== DEFAULT_SORT ||
63
+ filterActiveCount > 0;
64
+ const params = {
65
+ q: table.get(TABLE_KEYS.QUERY) || undefined,
66
+ category: table.get(TABLE_KEYS.CATEGORY) || undefined,
67
+ minPrice: table.get(TABLE_KEYS.MIN_PRICE) ? Number(table.get(TABLE_KEYS.MIN_PRICE)) : undefined,
68
+ maxPrice: table.get(TABLE_KEYS.MAX_PRICE) ? Number(table.get(TABLE_KEYS.MAX_PRICE)) : undefined,
69
+ sort: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT,
70
+ page: table.getNumber(TABLE_KEYS.PAGE, 1),
71
+ perPage: table.getNumber(TABLE_KEYS.PAGE_SIZE, 24),
72
+ listingType: "classified",
73
+ };
74
+ const { products, totalPages, page, isLoading } = useProducts(params, { initialData });
75
+ const commitSearch = useCallback(() => {
76
+ table.set(TABLE_KEYS.QUERY, searchInput.trim());
77
+ }, [searchInput, table]);
78
+ const selection = useBulkSelection({ items: products, keyExtractor: (p) => p.id });
79
+ const gridClass = "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4";
80
+ const wishlistActions = {
81
+ addToWishlist: (productId) => {
82
+ requireAuth(ACTION_ID.ADD_TO_WISHLIST, () => {
83
+ localWishlist.add(productId, "classified");
84
+ pushWishlistOp({ op: "add", itemId: productId, type: "classified" });
85
+ showToast("Added to wishlist", "success");
86
+ });
87
+ return Promise.resolve();
88
+ },
89
+ removeFromWishlist: (productId) => {
90
+ requireAuth(ACTION_ID.REMOVE_FROM_WISHLIST, () => {
91
+ localWishlist.remove(productId, "classified");
92
+ pushWishlistOp({ op: "remove", itemId: productId, type: "classified" });
93
+ showToast("Removed from wishlist", "info");
94
+ });
95
+ return Promise.resolve();
96
+ },
97
+ isWishlisted: (productId) => wishlistedIds.has(productId),
98
+ };
99
+ function handleToggleWishlist(id) {
100
+ if (wishlistActions.isWishlisted(id)) {
101
+ wishlistActions.removeFromWishlist(id);
102
+ }
103
+ else {
104
+ wishlistActions.addToWishlist(id);
105
+ }
106
+ }
107
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search classified listings\u2026", onSearchChange: setSearchInput, onSearchCommit: commitSearch, onSearchKeyDown: (e) => { if (e.key === "Enter")
108
+ commitSearch(); }, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, view: view, onViewChange: (v) => { if (v !== "table")
109
+ setView(v); }, onResetAll: resetAll, hasActiveState: hasActiveState, bulkMode: selection.isSelecting, bulkSelectedCount: selection.selectedCount, bulkTotalCount: products.length, onBulkSelectAll: selection.toggleAll, onBulkClear: selection.clearSelection }), _jsx(BulkActionBar, { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [] }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsx("div", { className: "py-6", children: isLoading ? (_jsx("div", { className: gridClass, children: Array.from({ length: 10 }).map((_, i) => (_jsxs("div", { className: "rounded-xl border border-zinc-100 dark:border-slate-700 overflow-hidden animate-pulse", children: [_jsx("div", { className: "aspect-square bg-zinc-200 dark:bg-slate-700" }), _jsxs("div", { className: "p-3 space-y-2", children: [_jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-3/4" }), _jsx("div", { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-1/3" })] })] }, i))) })) : products.length === 0 ? (_jsx(Text, { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: "No classified listings found." })) : (_jsx("div", { className: view === "list" ? "flex flex-col divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800" : gridClass, children: products.map((product) => (_jsx(InteractiveProductCard, { product: product, href: String(ROUTES.PUBLIC.CLASSIFIED_DETAIL(product.id)), variant: view === "list" ? "list" : "grid", isWishlisted: wishlistActions.isWishlisted(product.id), onToggleWishlist: handleToggleWishlist, selectable: selection.isSelecting, isSelected: selection.isSelected(product.id), onSelect: (id) => selection.toggle(id) }, product.id))) })) }), _jsx(FilterDrawer, { open: filterOpen, onOpen: openFilters, onClose: () => setFilterOpen(false), onApply: applyFilters, onReset: onFilterClear, activeCount: filterActiveCount, hideTrigger: true, children: _jsx(ClassifiedFilters, { table: pendingTable, categoryOptions: categoryOptions }) }), _jsx(LoginRequiredModal, { isOpen: modalOpen, onClose: closeModal, message: modalMessage })] }));
110
+ }
@@ -0,0 +1,6 @@
1
+ type SearchParams = Record<string, string | string[]>;
2
+ export interface ClassifiedListViewProps {
3
+ searchParams?: SearchParams;
4
+ }
5
+ export declare function ClassifiedListView({ searchParams }: ClassifiedListViewProps): Promise<import("react/jsx-runtime").JSX.Element>;
6
+ export {};
@@ -0,0 +1,43 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { productRepository } from "../../../repositories";
3
+ import { Container, Heading, Main, Section } from "../../../ui";
4
+ import { AdSlot } from "../../homepage/components/AdSlot";
5
+ import { parseListingSearchParams } from "../../../utils/listing-params";
6
+ import { ClassifiedIndexListing } from "./ClassifiedIndexListing";
7
+ const DEFAULT_PAGE = 1;
8
+ const DEFAULT_PAGE_SIZE = 24;
9
+ const DEFAULT_SORT = "-createdAt";
10
+ function sp(params, key) {
11
+ const v = params[key];
12
+ return Array.isArray(v) ? v[0] ?? "" : v ?? "";
13
+ }
14
+ function buildClassifiedFilters(params) {
15
+ const parts = ["status==published", "listingType==classified"];
16
+ const minPrice = sp(params, "minPrice");
17
+ const maxPrice = sp(params, "maxPrice");
18
+ if (minPrice)
19
+ parts.push(`price>=${minPrice}`);
20
+ if (maxPrice)
21
+ parts.push(`price<=${maxPrice}`);
22
+ const city = sp(params, "city");
23
+ if (city)
24
+ parts.push(`classifiedCity==${city}`);
25
+ const negotiable = sp(params, "negotiable");
26
+ if (negotiable === "true")
27
+ parts.push(`classifiedNegotiable==true`);
28
+ const acceptsShipping = sp(params, "acceptsShipping");
29
+ if (acceptsShipping === "true")
30
+ parts.push(`classifiedAcceptsShipping==true`);
31
+ return parts.join(",");
32
+ }
33
+ export async function ClassifiedListView({ searchParams = {} }) {
34
+ const std = parseListingSearchParams(searchParams);
35
+ const sort = std.sorts ?? DEFAULT_SORT;
36
+ const page = std.page ?? DEFAULT_PAGE;
37
+ const pageSize = std.pageSize ?? DEFAULT_PAGE_SIZE;
38
+ const filters = buildClassifiedFilters(searchParams);
39
+ const result = await productRepository
40
+ .list({ filters, sorts: sort, page, pageSize })
41
+ .catch(() => null);
42
+ return (_jsx(Main, { children: _jsx(Section, { className: "py-10", children: _jsxs(Container, { size: "xl", children: [_jsx(Heading, { level: 1, className: "mb-8 text-3xl font-semibold text-zinc-900", children: "Classifieds" }), _jsx(AdSlot, { id: "listing-sidebar-top", className: "mb-6" }), _jsx(ClassifiedIndexListing, { initialData: result ?? undefined }), _jsx(AdSlot, { id: "listing-sidebar-bottom", className: "mt-8" })] }) }) }));
43
+ }
@@ -0,0 +1,6 @@
1
+ export { ClassifiedListView } from "./ClassifiedListView";
2
+ export type { ClassifiedListViewProps } from "./ClassifiedListView";
3
+ export { ClassifiedIndexListing } from "./ClassifiedIndexListing";
4
+ export type { ClassifiedIndexListingProps } from "./ClassifiedIndexListing";
5
+ export { ClassifiedFilters } from "./ClassifiedFilters";
6
+ export type { ClassifiedFiltersProps } from "./ClassifiedFilters";
@@ -0,0 +1,3 @@
1
+ export { ClassifiedListView } from "./ClassifiedListView";
2
+ export { ClassifiedIndexListing } from "./ClassifiedIndexListing";
3
+ export { ClassifiedFilters } from "./ClassifiedFilters";
@@ -10,22 +10,26 @@
10
10
  */
11
11
  import { NextResponse } from "next/server.js";
12
12
  import { getProviders } from "../../../../contracts";
13
+ const ERR_COLLECTION_SLUG_REQUIRED = "Collection slug is required";
14
+ const ERR_DB_NOT_CONFIGURED = "Database provider not configured";
15
+ const ERR_COLLECTION_NOT_FOUND = "Collection not found";
16
+ const ERR_INTERNAL_SERVER_ERROR = "Internal server error";
13
17
  export async function GET(request, { params }) {
14
18
  try {
15
19
  const { slug } = await params;
16
20
  if (!slug) {
17
- return NextResponse.json({ success: false, error: "Collection slug required" }, { status: 400 });
21
+ return NextResponse.json({ success: false, error: ERR_COLLECTION_SLUG_REQUIRED }, { status: 400 });
18
22
  }
19
23
  const { db } = getProviders();
20
24
  if (!db)
21
- return NextResponse.json({ success: false, error: "DB not configured" }, { status: 503 });
25
+ return NextResponse.json({ success: false, error: ERR_DB_NOT_CONFIGURED }, { status: 503 });
22
26
  const repo = db.getRepository("collections");
23
27
  const result = await repo.findAll({
24
28
  filters: `slug==${slug}`,
25
29
  perPage: 1,
26
30
  });
27
31
  if (!result.data[0]) {
28
- return NextResponse.json({ success: false, error: "Collection not found" }, { status: 404 });
32
+ return NextResponse.json({ success: false, error: ERR_COLLECTION_NOT_FOUND }, { status: 404 });
29
33
  }
30
34
  return NextResponse.json({
31
35
  success: true,
@@ -35,7 +39,7 @@ export async function GET(request, { params }) {
35
39
  catch (error) {
36
40
  return NextResponse.json({
37
41
  success: false,
38
- error: error instanceof Error ? error.message : "Internal server error",
42
+ error: error instanceof Error ? error.message : ERR_INTERNAL_SERVER_ERROR,
39
43
  }, { status: 500 });
40
44
  }
41
45
  }
@@ -43,19 +47,19 @@ export async function PATCH(request, { params }) {
43
47
  try {
44
48
  const { slug } = await params;
45
49
  if (!slug) {
46
- return NextResponse.json({ success: false, error: "Collection slug required" }, { status: 400 });
50
+ return NextResponse.json({ success: false, error: ERR_COLLECTION_SLUG_REQUIRED }, { status: 400 });
47
51
  }
48
52
  const body = await request.json();
49
53
  const { db } = getProviders();
50
54
  if (!db)
51
- return NextResponse.json({ success: false, error: "DB not configured" }, { status: 503 });
55
+ return NextResponse.json({ success: false, error: ERR_DB_NOT_CONFIGURED }, { status: 503 });
52
56
  const repo = db.getRepository("collections");
53
57
  const result = await repo.findAll({
54
58
  filters: `slug==${slug}`,
55
59
  perPage: 1,
56
60
  });
57
61
  if (!result.data[0]) {
58
- return NextResponse.json({ success: false, error: "Collection not found" }, { status: 404 });
62
+ return NextResponse.json({ success: false, error: ERR_COLLECTION_NOT_FOUND }, { status: 404 });
59
63
  }
60
64
  const updated = await repo.update(result.data[0].id, body);
61
65
  return NextResponse.json({
@@ -66,7 +70,7 @@ export async function PATCH(request, { params }) {
66
70
  catch (error) {
67
71
  return NextResponse.json({
68
72
  success: false,
69
- error: error instanceof Error ? error.message : "Internal server error",
73
+ error: error instanceof Error ? error.message : ERR_INTERNAL_SERVER_ERROR,
70
74
  }, { status: 500 });
71
75
  }
72
76
  }
@@ -74,18 +78,18 @@ export async function DELETE(request, { params }) {
74
78
  try {
75
79
  const { slug } = await params;
76
80
  if (!slug) {
77
- return NextResponse.json({ success: false, error: "Collection slug required" }, { status: 400 });
81
+ return NextResponse.json({ success: false, error: ERR_COLLECTION_SLUG_REQUIRED }, { status: 400 });
78
82
  }
79
83
  const { db } = getProviders();
80
84
  if (!db)
81
- return NextResponse.json({ success: false, error: "DB not configured" }, { status: 503 });
85
+ return NextResponse.json({ success: false, error: ERR_DB_NOT_CONFIGURED }, { status: 503 });
82
86
  const repo = db.getRepository("collections");
83
87
  const result = await repo.findAll({
84
88
  filters: `slug==${slug}`,
85
89
  perPage: 1,
86
90
  });
87
91
  if (!result.data[0]) {
88
- return NextResponse.json({ success: false, error: "Collection not found" }, { status: 404 });
92
+ return NextResponse.json({ success: false, error: ERR_COLLECTION_NOT_FOUND }, { status: 404 });
89
93
  }
90
94
  await repo.delete(result.data[0].id);
91
95
  return NextResponse.json({
@@ -96,7 +100,7 @@ export async function DELETE(request, { params }) {
96
100
  catch (error) {
97
101
  return NextResponse.json({
98
102
  success: false,
99
- error: error instanceof Error ? error.message : "Internal server error",
103
+ error: error instanceof Error ? error.message : ERR_INTERNAL_SERVER_ERROR,
100
104
  }, { status: 500 });
101
105
  }
102
106
  }
@@ -26,13 +26,13 @@ export declare const collectionItemSchema: z.ZodObject<{
26
26
  }, "strip", z.ZodTypeAny, {
27
27
  sortOrder: number;
28
28
  title: string;
29
- active: boolean;
30
29
  slug: string;
30
+ active: boolean;
31
31
  createdAt?: string | undefined;
32
32
  image?: string | undefined;
33
- subtitle?: string | undefined;
34
33
  description?: string | undefined;
35
34
  brandSlug?: string | undefined;
35
+ subtitle?: string | undefined;
36
36
  productCount?: number | undefined;
37
37
  bannerImage?: string | undefined;
38
38
  franchiseSlug?: string | undefined;
@@ -43,10 +43,10 @@ export declare const collectionItemSchema: z.ZodObject<{
43
43
  createdAt?: string | undefined;
44
44
  sortOrder?: number | undefined;
45
45
  image?: string | undefined;
46
- active?: boolean | undefined;
47
- subtitle?: string | undefined;
48
46
  description?: string | undefined;
49
47
  brandSlug?: string | undefined;
48
+ active?: boolean | undefined;
49
+ subtitle?: string | undefined;
50
50
  productCount?: number | undefined;
51
51
  bannerImage?: string | undefined;
52
52
  franchiseSlug?: string | undefined;
@@ -61,8 +61,8 @@ export declare const collectionListItemSchema: z.ZodObject<{
61
61
  active: z.ZodDefault<z.ZodBoolean>;
62
62
  }, "strip", z.ZodTypeAny, {
63
63
  title: string;
64
- active: boolean;
65
64
  slug: string;
65
+ active: boolean;
66
66
  image?: string | undefined;
67
67
  subtitle?: string | undefined;
68
68
  productCount?: number | undefined;
@@ -10,15 +10,18 @@
10
10
  */
11
11
  import { NextResponse } from "next/server.js";
12
12
  import { getProviders } from "../../../../contracts";
13
+ const ERR_CONSULTATION_ID_REQUIRED = "Consultation ID is required";
14
+ const ERR_DB_NOT_CONFIGURED = "Database provider not configured";
15
+ const ERR_INTERNAL_SERVER_ERROR = "Internal server error";
13
16
  export async function GET(request, { params }) {
14
17
  try {
15
18
  const { id } = await params;
16
19
  if (!id) {
17
- return NextResponse.json({ success: false, error: "Consultation ID required" }, { status: 400 });
20
+ return NextResponse.json({ success: false, error: ERR_CONSULTATION_ID_REQUIRED }, { status: 400 });
18
21
  }
19
22
  const { db } = getProviders();
20
23
  if (!db)
21
- return NextResponse.json({ success: false, error: "DB not configured" }, { status: 503 });
24
+ return NextResponse.json({ success: false, error: ERR_DB_NOT_CONFIGURED }, { status: 503 });
22
25
  const repo = db.getRepository("consultations");
23
26
  const consultation = await repo.findById(id);
24
27
  if (!consultation) {
@@ -32,7 +35,7 @@ export async function GET(request, { params }) {
32
35
  catch (error) {
33
36
  return NextResponse.json({
34
37
  success: false,
35
- error: error instanceof Error ? error.message : "Internal server error",
38
+ error: error instanceof Error ? error.message : ERR_INTERNAL_SERVER_ERROR,
36
39
  }, { status: 500 });
37
40
  }
38
41
  }
@@ -40,12 +43,12 @@ export async function PATCH(request, { params }) {
40
43
  try {
41
44
  const { id } = await params;
42
45
  if (!id) {
43
- return NextResponse.json({ success: false, error: "Consultation ID required" }, { status: 400 });
46
+ return NextResponse.json({ success: false, error: ERR_CONSULTATION_ID_REQUIRED }, { status: 400 });
44
47
  }
45
48
  const body = await request.json();
46
49
  const { db } = getProviders();
47
50
  if (!db)
48
- return NextResponse.json({ success: false, error: "DB not configured" }, { status: 503 });
51
+ return NextResponse.json({ success: false, error: ERR_DB_NOT_CONFIGURED }, { status: 503 });
49
52
  const repo = db.getRepository("consultations");
50
53
  const updated = await repo.update(id, body);
51
54
  if (!updated) {
@@ -59,7 +62,7 @@ export async function PATCH(request, { params }) {
59
62
  catch (error) {
60
63
  return NextResponse.json({
61
64
  success: false,
62
- error: error instanceof Error ? error.message : "Internal server error",
65
+ error: error instanceof Error ? error.message : ERR_INTERNAL_SERVER_ERROR,
63
66
  }, { status: 500 });
64
67
  }
65
68
  }
@@ -67,11 +70,11 @@ export async function DELETE(request, { params }) {
67
70
  try {
68
71
  const { id } = await params;
69
72
  if (!id) {
70
- return NextResponse.json({ success: false, error: "Consultation ID required" }, { status: 400 });
73
+ return NextResponse.json({ success: false, error: ERR_CONSULTATION_ID_REQUIRED }, { status: 400 });
71
74
  }
72
75
  const { db } = getProviders();
73
76
  if (!db)
74
- return NextResponse.json({ success: false, error: "DB not configured" }, { status: 503 });
77
+ return NextResponse.json({ success: false, error: ERR_DB_NOT_CONFIGURED }, { status: 503 });
75
78
  const repo = db.getRepository("consultations");
76
79
  await repo.delete(id);
77
80
  return NextResponse.json({
@@ -82,7 +85,7 @@ export async function DELETE(request, { params }) {
82
85
  catch (error) {
83
86
  return NextResponse.json({
84
87
  success: false,
85
- error: error instanceof Error ? error.message : "Internal server error",
88
+ error: error instanceof Error ? error.message : ERR_INTERNAL_SERVER_ERROR,
86
89
  }, { status: 500 });
87
90
  }
88
91
  }
@@ -2,6 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import React from "react";
4
4
  import { Button, Div, Input, Row, Select, Textarea } from "../../../ui";
5
+ const CLS_INPUT = "w-full rounded-md border border-neutral-300 px-3 py-2 text-sm";
5
6
  const TIME_SLOTS = [
6
7
  "9:00 AM",
7
8
  "10:00 AM",
@@ -42,10 +43,10 @@ export function ConsultationForm({ onSubmit, isPending, concerns = [], }) {
42
43
  e.preventDefault();
43
44
  await onSubmit(form);
44
45
  }
45
- return (_jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [_jsx(Input, { name: "name", type: "text", placeholder: "Full name", value: form.name, onChange: handleChange, required: true, className: "w-full rounded-md border border-neutral-300 px-3 py-2 text-sm" }), _jsx(Input, { name: "email", type: "email", placeholder: "Email address", value: form.email, onChange: handleChange, required: true, className: "w-full rounded-md border border-neutral-300 px-3 py-2 text-sm" }), _jsx(Input, { name: "phone", type: "tel", placeholder: "Phone number", value: form.phone, onChange: handleChange, required: true, className: "w-full rounded-md border border-neutral-300 px-3 py-2 text-sm" }), concerns.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", children: concerns.map((c) => (_jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => toggleConcern(c), className: `rounded-full border px-3 py-1 text-xs transition ${form.concern.includes(c)
46
+ return (_jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [_jsx(Input, { name: "name", type: "text", placeholder: "Full name", value: form.name, onChange: handleChange, required: true, className: CLS_INPUT }), _jsx(Input, { name: "email", type: "email", placeholder: "Email address", value: form.email, onChange: handleChange, required: true, className: CLS_INPUT }), _jsx(Input, { name: "phone", type: "tel", placeholder: "Phone number", value: form.phone, onChange: handleChange, required: true, className: CLS_INPUT }), concerns.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", children: concerns.map((c) => (_jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => toggleConcern(c), className: `rounded-full border px-3 py-1 text-xs transition ${form.concern.includes(c)
46
47
  ? "border-primary bg-primary text-white"
47
48
  : "border-neutral-300 text-neutral-700 hover:border-primary"}`, children: c }, c))) })), _jsxs(Div, { className: "flex gap-3", children: [_jsx(Input, { name: "preferredDate", type: "date", value: form.preferredDate, onChange: handleChange, required: true, className: "flex-1 rounded-md border border-neutral-300 px-3 py-2 text-sm" }), _jsx(Select, { value: form.preferredTime, onValueChange: (value) => handleValueChange("preferredTime", value), options: TIME_SLOTS.map((t) => ({ value: t, label: t })), className: "flex-1 rounded-md border border-neutral-300 px-3 py-2 text-sm" })] }), _jsx(Select, { value: form.mode, onValueChange: (value) => handleValueChange("mode", value), options: [
48
49
  { value: "remote", label: "Remote (Video Call)" },
49
50
  { value: "in-person", label: "In-Person" },
50
- ], className: "w-full rounded-md border border-neutral-300 px-3 py-2 text-sm" }), _jsx(Textarea, { name: "message", placeholder: "Any additional notes (optional)", value: form.message, onChange: handleChange, rows: 3, className: "w-full rounded-md border border-neutral-300 px-3 py-2 text-sm" }), _jsx(Button, { type: "submit", disabled: isPending, variant: "primary", className: "w-full rounded-md bg-primary px-4 py-2 text-sm font-medium text-white transition hover:bg-primary/90 disabled:opacity-60", children: isPending ? "Booking..." : "Book Consultation" })] }));
51
+ ], className: CLS_INPUT }), _jsx(Textarea, { name: "message", placeholder: "Any additional notes (optional)", value: form.message, onChange: handleChange, rows: 3, className: CLS_INPUT }), _jsx(Button, { type: "submit", disabled: isPending, variant: "primary", className: "w-full rounded-md bg-primary px-4 py-2 text-sm font-medium text-white transition hover:bg-primary/90 disabled:opacity-60", children: isPending ? "Booking..." : "Book Consultation" })] }));
51
52
  }