@mohasinac/appkit 2.7.26 → 2.7.30

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 (363) hide show
  1. package/dist/_internal/client/features/classified/ClassifiedDetailView.js +2 -2
  2. package/dist/_internal/client/features/digital-code/CodeRevealPanel.js +2 -2
  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 +310 -8
  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 +2 -0
  46. package/dist/client.js +1 -0
  47. package/dist/configs/next.js +4 -0
  48. package/dist/constants/table-keys.d.ts +6 -0
  49. package/dist/constants/table-keys.js +9 -0
  50. package/dist/core/hooks/useSyncManager.js +9 -8
  51. package/dist/features/about/components/FeesView.js +10 -7
  52. package/dist/features/about/components/HelpPageView.js +10 -1
  53. package/dist/features/about/components/HowAuctionsWorkView.js +10 -1
  54. package/dist/features/about/components/HowCheckoutWorksView.js +10 -1
  55. package/dist/features/about/components/HowOffersWorkView.js +10 -1
  56. package/dist/features/about/components/HowOrdersWorkView.js +10 -1
  57. package/dist/features/about/components/HowPayoutsWorkView.js +10 -1
  58. package/dist/features/about/components/HowPreOrdersWorkView.js +10 -1
  59. package/dist/features/about/components/HowReviewsWorkView.js +10 -1
  60. package/dist/features/about/components/PublicProfileView.js +44 -14
  61. package/dist/features/about/components/SecurityPrivacyView.js +7 -1
  62. package/dist/features/account/components/AddressesIndexListing.js +2 -2
  63. package/dist/features/account/components/NotificationBell.js +27 -16
  64. package/dist/features/account/components/NotificationPreferencesPanel.d.ts +9 -0
  65. package/dist/features/account/components/NotificationPreferencesPanel.js +91 -0
  66. package/dist/features/account/components/UserSidebar.js +4 -4
  67. package/dist/features/account/components/UserSupportView.js +16 -6
  68. package/dist/features/account/components/index.d.ts +2 -0
  69. package/dist/features/account/components/index.js +1 -0
  70. package/dist/features/account/schemas/index.d.ts +4 -4
  71. package/dist/features/account/types/index.d.ts +34 -0
  72. package/dist/features/admin/actions/admin-actions.js +4 -3
  73. package/dist/features/admin/actions/notification-actions.d.ts +24 -22
  74. package/dist/features/admin/actions/notification-actions.js +122 -22
  75. package/dist/features/admin/components/AdminAdEditorView.js +29 -15
  76. package/dist/features/admin/components/AdminAdsView.js +22 -28
  77. package/dist/features/admin/components/AdminAllEventEntriesView.js +6 -1
  78. package/dist/features/admin/components/AdminBidsView.js +10 -3
  79. package/dist/features/admin/components/AdminBlogEditorView.js +2 -2
  80. package/dist/features/admin/components/AdminBlogView.js +8 -3
  81. package/dist/features/admin/components/AdminBrandsView.js +7 -2
  82. package/dist/features/admin/components/AdminBundleEditorView.js +5 -2
  83. package/dist/features/admin/components/AdminCarouselEditorView.js +6 -3
  84. package/dist/features/admin/components/AdminCarouselView.js +13 -7
  85. package/dist/features/admin/components/AdminCategoriesView.js +8 -3
  86. package/dist/features/admin/components/AdminCategoryEditorView.js +2 -2
  87. package/dist/features/admin/components/AdminContactView.js +6 -1
  88. package/dist/features/admin/components/AdminCouponEditorView.js +8 -2
  89. package/dist/features/admin/components/AdminCouponsView.js +6 -1
  90. package/dist/features/admin/components/AdminEmployeeEditorView.js +12 -9
  91. package/dist/features/admin/components/AdminFaqEditorView.js +2 -2
  92. package/dist/features/admin/components/AdminFaqsView.js +7 -2
  93. package/dist/features/admin/components/AdminFeaturesView.js +4 -3
  94. package/dist/features/admin/components/AdminMediaView.js +9 -8
  95. package/dist/features/admin/components/AdminNavigationView.js +10 -17
  96. package/dist/features/admin/components/AdminNewsletterView.js +6 -1
  97. package/dist/features/admin/components/AdminNotificationsView.js +11 -3
  98. package/dist/features/admin/components/AdminOrdersView.js +6 -1
  99. package/dist/features/admin/components/AdminPayoutsView.js +10 -3
  100. package/dist/features/admin/components/AdminPrizeDrawsView.js +10 -3
  101. package/dist/features/admin/components/AdminProductsView.js +18 -12
  102. package/dist/features/admin/components/AdminReviewsView.js +33 -24
  103. package/dist/features/admin/components/AdminScammerEditorView.js +3 -2
  104. package/dist/features/admin/components/AdminScammersView.js +28 -26
  105. package/dist/features/admin/components/AdminSectionsView.js +112 -99
  106. package/dist/features/admin/components/AdminSessionsView.js +10 -3
  107. package/dist/features/admin/components/AdminSidebar.js +4 -4
  108. package/dist/features/admin/components/AdminSiteSettingsView.js +45 -4
  109. package/dist/features/admin/components/AdminStoresView.js +6 -1
  110. package/dist/features/admin/components/AdminSublistingCategoriesView.js +0 -1
  111. package/dist/features/admin/components/AdminSupportTicketDetailView.js +1 -1
  112. package/dist/features/admin/components/AdminSupportTicketsView.js +32 -34
  113. package/dist/features/admin/components/AdminTeamView.js +6 -1
  114. package/dist/features/admin/components/AdminUserEditorView.js +8 -15
  115. package/dist/features/admin/components/AdminUsersView.js +6 -1
  116. package/dist/features/admin/components/AdminViewCards.js +4 -3
  117. package/dist/features/admin/components/DashboardStats.js +2 -2
  118. package/dist/features/admin/components/DataTable.js +2 -2
  119. package/dist/features/admin/components/sections/adminSectionsTypes.js +4 -3
  120. package/dist/features/admin/repository/chat.repository.js +8 -8
  121. package/dist/features/admin/repository/site-settings.repository.d.ts +1 -0
  122. package/dist/features/admin/repository/site-settings.repository.js +11 -9
  123. package/dist/features/admin/schemas/firestore.d.ts +38 -0
  124. package/dist/features/admin/schemas/firestore.js +15 -0
  125. package/dist/features/auctions/components/AuctionDetailPageView.js +13 -19
  126. package/dist/features/auctions/components/MarketplaceAuctionCard.js +18 -9
  127. package/dist/features/auctions/components/MarketplaceAuctionGrid.js +3 -2
  128. package/dist/features/auctions/components/index.d.ts +0 -1
  129. package/dist/features/auctions/components/index.js +0 -1
  130. package/dist/features/auctions/schemas/index.d.ts +14 -14
  131. package/dist/features/auth/actions/realtime-token-actions.js +19 -4
  132. package/dist/features/auth/components/RegisterForm.js +8 -4
  133. package/dist/features/auth/consent-otp.d.ts +2 -0
  134. package/dist/features/auth/consent-otp.js +8 -0
  135. package/dist/features/auth/schemas/firestore.d.ts +2 -0
  136. package/dist/features/auth/schemas/firestore.js +18 -25
  137. package/dist/features/auth/schemas/index.d.ts +2 -2
  138. package/dist/features/before-after/api/[id]/route.js +8 -6
  139. package/dist/features/before-after/schemas/index.d.ts +2 -2
  140. package/dist/features/blog/actions/blog-actions.d.ts +3 -3
  141. package/dist/features/blog/components/BlogIndexListing.js +21 -2
  142. package/dist/features/blog/components/BlogPostForm.js +11 -5
  143. package/dist/features/blog/components/BlogPostView.js +10 -2
  144. package/dist/features/blog/schemas/index.d.ts +18 -18
  145. package/dist/features/cart/components/CartDrawer.js +3 -2
  146. package/dist/features/cart/repository/cart.repository.js +4 -3
  147. package/dist/features/cart/utils/pending-ops.d.ts +1 -1
  148. package/dist/features/categories/api/[id]/route.js +4 -3
  149. package/dist/features/categories/api/route.js +4 -3
  150. package/dist/features/categories/components/BrandDetailPageView.js +2 -2
  151. package/dist/features/categories/components/BrandDetailTabs.js +2 -2
  152. package/dist/features/categories/components/BundleCollage.d.ts +8 -0
  153. package/dist/features/categories/components/BundleCollage.js +50 -0
  154. package/dist/features/categories/components/BundleDetailView.js +2 -10
  155. package/dist/features/categories/components/BundleItemsPicker.js +20 -13
  156. package/dist/features/categories/components/CategoriesIndexListing.js +28 -9
  157. package/dist/features/categories/components/CategoryDetailPageView.js +2 -2
  158. package/dist/features/categories/components/CategoryDetailTabs.js +2 -2
  159. package/dist/features/categories/components/CategoryProductsListing.js +52 -13
  160. package/dist/features/categories/components/index.d.ts +2 -0
  161. package/dist/features/categories/components/index.js +1 -0
  162. package/dist/features/categories/schemas/index.d.ts +6 -6
  163. package/dist/features/checkout/actions/checkout-actions.js +4 -3
  164. package/dist/features/checkout/hooks/usePaymentCheckout.js +31 -22
  165. package/dist/features/classified/components/ClassifiedFilters.d.ts +8 -0
  166. package/dist/features/classified/components/ClassifiedFilters.js +19 -0
  167. package/dist/features/classified/components/ClassifiedIndexListing.d.ts +4 -0
  168. package/dist/features/classified/components/ClassifiedIndexListing.js +110 -0
  169. package/dist/features/classified/components/ClassifiedListView.d.ts +6 -0
  170. package/dist/features/classified/components/ClassifiedListView.js +43 -0
  171. package/dist/features/classified/components/index.d.ts +6 -0
  172. package/dist/features/classified/components/index.js +3 -0
  173. package/dist/features/collections/api/[slug]/route.js +16 -12
  174. package/dist/features/collections/schemas/index.d.ts +5 -5
  175. package/dist/features/consultation/api/[id]/route.js +12 -9
  176. package/dist/features/consultation/components/ConsultationForm.js +3 -2
  177. package/dist/features/consultation/schemas/index.d.ts +6 -6
  178. package/dist/features/contact/email.js +77 -116
  179. package/dist/features/copilot/components/AdminCopilotView.js +12 -2
  180. package/dist/features/corporate/api/[id]/route.js +12 -9
  181. package/dist/features/corporate/components/CorporateInquiryForm.js +2 -1
  182. package/dist/features/digital-codes/components/DigitalCodeFilters.d.ts +8 -0
  183. package/dist/features/digital-codes/components/DigitalCodeFilters.js +16 -0
  184. package/dist/features/digital-codes/components/DigitalCodesIndexListing.d.ts +4 -0
  185. package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +107 -0
  186. package/dist/features/digital-codes/components/DigitalCodesListView.d.ts +6 -0
  187. package/dist/features/digital-codes/components/DigitalCodesListView.js +37 -0
  188. package/dist/features/digital-codes/components/index.d.ts +6 -0
  189. package/dist/features/digital-codes/components/index.js +3 -0
  190. package/dist/features/events/actions/event-actions.js +4 -3
  191. package/dist/features/events/components/AdminEventEditorView.js +3 -2
  192. package/dist/features/events/components/AdminEventsView.js +4 -2
  193. package/dist/features/events/components/EventPollWidget.js +5 -5
  194. package/dist/features/events/components/EventsIndexListing.js +2 -2
  195. package/dist/features/events/schemas/index.d.ts +20 -20
  196. package/dist/features/faq/actions/faq-actions.d.ts +8 -8
  197. package/dist/features/faq/components/ContactCTA.js +3 -1
  198. package/dist/features/faq/components/FAQAccordion.js +1 -1
  199. package/dist/features/faq/schemas/index.d.ts +4 -4
  200. package/dist/features/filters/AsyncFacetSection.d.ts +18 -0
  201. package/dist/features/filters/AsyncFacetSection.js +65 -0
  202. package/dist/features/forms/Checkbox.js +2 -2
  203. package/dist/features/forms/Input.js +2 -2
  204. package/dist/features/forms/Radio.js +5 -5
  205. package/dist/features/forms/Select.js +2 -2
  206. package/dist/features/forms/Slider.js +2 -2
  207. package/dist/features/forms/Textarea.js +2 -2
  208. package/dist/features/homepage/api/[id]/route.js +4 -3
  209. package/dist/features/homepage/api/sections/[id]/route.js +12 -9
  210. package/dist/features/homepage/components/AdSlot.js +2 -1
  211. package/dist/features/homepage/components/AdvertisementBanner.js +5 -3
  212. package/dist/features/homepage/components/BrandsSection.js +2 -2
  213. package/dist/features/homepage/components/CTABannerSection.js +2 -2
  214. package/dist/features/homepage/components/CharacterHotspot.d.ts +2 -2
  215. package/dist/features/homepage/components/CharacterHotspot.js +119 -157
  216. package/dist/features/homepage/components/CharacterHotspotForm.js +25 -20
  217. package/dist/features/homepage/components/CustomCardsSection.js +8 -6
  218. package/dist/features/homepage/components/FeaturedProductsSection.js +2 -2
  219. package/dist/features/homepage/components/GoogleReviewsSection.js +3 -3
  220. package/dist/features/homepage/components/HeroBanner.js +5 -4
  221. package/dist/features/homepage/components/HeroCarousel.js +13 -26
  222. package/dist/features/homepage/components/HowItWorksSection.js +4 -2
  223. package/dist/features/homepage/components/SocialFeedSection.js +2 -2
  224. package/dist/features/homepage/components/SocialPostCard.js +3 -2
  225. package/dist/features/homepage/lib/social-feed-fetcher.js +6 -3
  226. package/dist/features/layout/AppLayoutShell.d.ts +8 -2
  227. package/dist/features/layout/AppLayoutShell.js +55 -84
  228. package/dist/features/layout/BottomActions.js +43 -48
  229. package/dist/features/layout/NavbarWithSettings.d.ts +6 -0
  230. package/dist/features/layout/NavbarWithSettings.js +11 -0
  231. package/dist/features/live/components/LiveItemFilters.d.ts +8 -0
  232. package/dist/features/live/components/LiveItemFilters.js +23 -0
  233. package/dist/features/live/components/LiveItemsIndexListing.d.ts +4 -0
  234. package/dist/features/live/components/LiveItemsIndexListing.js +108 -0
  235. package/dist/features/live/components/LiveItemsListView.d.ts +6 -0
  236. package/dist/features/live/components/LiveItemsListView.js +43 -0
  237. package/dist/features/live/components/index.d.ts +6 -0
  238. package/dist/features/live/components/index.js +3 -0
  239. package/dist/features/media/MediaLightbox.js +8 -14
  240. package/dist/features/media/types/index.d.ts +2 -2
  241. package/dist/features/media/upload/CameraCapture.js +2 -2
  242. package/dist/features/media/upload/ImageUpload.js +4 -2
  243. package/dist/features/media/upload/MediaUploadField.js +24 -8
  244. package/dist/features/media/upload/MediaUploadList.js +1 -1
  245. package/dist/features/orders/actions/order-actions.js +4 -3
  246. package/dist/features/orders/components/MarketplaceOrderCard.js +2 -1
  247. package/dist/features/orders/components/OrderFilters.js +12 -9
  248. package/dist/features/orders/schemas/index.d.ts +6 -6
  249. package/dist/features/pre-orders/api/[id]/route.js +12 -9
  250. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +5 -4
  251. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +27 -20
  252. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +17 -52
  253. package/dist/features/pre-orders/components/PreorderCard.d.ts +0 -9
  254. package/dist/features/pre-orders/components/PreorderCard.js +2 -13
  255. package/dist/features/pre-orders/components/index.d.ts +1 -1
  256. package/dist/features/pre-orders/components/index.js +1 -1
  257. package/dist/features/pre-orders/schemas/index.d.ts +10 -10
  258. package/dist/features/products/api/[id]/route.js +9 -7
  259. package/dist/features/products/api/route.js +1 -1
  260. package/dist/features/products/columns/productTableColumns.js +2 -2
  261. package/dist/features/products/components/AuctionsIndexListing.js +15 -51
  262. package/dist/features/products/components/BidHistory.js +2 -2
  263. package/dist/features/products/components/CompareOverlay.js +3 -2
  264. package/dist/features/products/components/MakeOfferButton.js +20 -14
  265. package/dist/features/products/components/MarketplacePrizeDrawCard.js +2 -1
  266. package/dist/features/products/components/PrizeDrawCollage.d.ts +1 -15
  267. package/dist/features/products/components/PrizeDrawCollage.js +54 -14
  268. package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -1
  269. package/dist/features/products/components/PrizeDrawEntryActions.js +2 -1
  270. package/dist/features/products/components/PrizeDrawItemsEditor.js +9 -7
  271. package/dist/features/products/components/PrizeDrawsIndexListing.js +18 -51
  272. package/dist/features/products/components/PrizeRevealModal.js +24 -14
  273. package/dist/features/products/components/ProductDetailPageView.js +2 -1
  274. package/dist/features/products/components/ProductFilters.js +8 -6
  275. package/dist/features/products/components/ProductForm.js +12 -10
  276. package/dist/features/products/components/ProductGalleryClient.js +2 -1
  277. package/dist/features/products/components/ProductGrid.js +11 -14
  278. package/dist/features/products/components/ProductsIndexListing.js +16 -52
  279. package/dist/features/products/components/ProductsIndexPageView.js +2 -2
  280. package/dist/features/products/schemas/index.d.ts +56 -56
  281. package/dist/features/products/schemas/product-features.validators.d.ts +14 -14
  282. package/dist/features/promotions/components/CouponsIndexListing.js +1 -1
  283. package/dist/features/promotions/schemas/index.d.ts +6 -6
  284. package/dist/features/reviews/actions/review-actions.js +6 -5
  285. package/dist/features/reviews/api/[id]/route.js +4 -3
  286. package/dist/features/reviews/components/ReviewDetailPageView.js +2 -2
  287. package/dist/features/reviews/components/ReviewDetailShell.js +6 -3
  288. package/dist/features/reviews/components/ReviewsIndexListing.js +2 -2
  289. package/dist/features/reviews/schemas/index.d.ts +6 -6
  290. package/dist/features/scams/components/ScamProfileView.js +19 -10
  291. package/dist/features/scams/components/ScamRegistryView.js +2 -1
  292. package/dist/features/search/components/Search.d.ts +1 -1
  293. package/dist/features/search/components/Search.js +56 -49
  294. package/dist/features/search/schemas/index.d.ts +5 -5
  295. package/dist/features/seller/actions/offer-actions.js +11 -9
  296. package/dist/features/seller/components/SellerAddressesView.js +6 -4
  297. package/dist/features/seller/components/SellerBidsView.js +2 -2
  298. package/dist/features/seller/components/SellerCouponsView.js +1 -1
  299. package/dist/features/seller/components/SellerOffersPanel.js +6 -1
  300. package/dist/features/seller/components/SellerOrdersView.js +1 -1
  301. package/dist/features/seller/components/SellerPayoutSettingsView.js +3 -3
  302. package/dist/features/seller/components/SellerPreOrdersView.js +5 -4
  303. package/dist/features/seller/components/SellerPrizeDrawsView.js +5 -4
  304. package/dist/features/seller/components/SellerProductShell.d.ts +19 -1
  305. package/dist/features/seller/components/SellerProductShell.js +75 -9
  306. package/dist/features/seller/components/SellerProductsView.js +10 -11
  307. package/dist/features/seller/components/SellerShippingView.js +3 -3
  308. package/dist/features/seller/components/SellerSidebar.js +10 -7
  309. package/dist/features/seller/components/SellerStorefrontView.js +3 -3
  310. package/dist/features/seller/schemas/index.d.ts +4 -4
  311. package/dist/features/shell/FormShell.js +2 -1
  312. package/dist/features/shell/QuickFormDrawer.js +4 -3
  313. package/dist/features/shell/StepForm.js +4 -3
  314. package/dist/features/stores/actions/store-query-actions.js +4 -3
  315. package/dist/features/stores/components/StoreAboutView.js +2 -1
  316. package/dist/features/stores/components/StoreAuctionsListing.js +43 -64
  317. package/dist/features/stores/components/StoreDetailLayoutView.js +2 -2
  318. package/dist/features/stores/components/StorePreOrdersListing.js +33 -57
  319. package/dist/features/stores/components/StoreProductsListing.js +16 -49
  320. package/dist/features/stores/components/StoresIndexListing.js +2 -2
  321. package/dist/features/stores/schemas/index.d.ts +2 -2
  322. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +8 -7
  323. package/dist/features/wishlist/hooks/useGuestWishlist.d.ts +5 -5
  324. package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +6 -6
  325. package/dist/features/wishlist/utils/guest-wishlist.d.ts +5 -5
  326. package/dist/index.d.ts +21 -3
  327. package/dist/index.js +1737 -1725
  328. package/dist/monitoring/server-logger.js +5 -9
  329. package/dist/next/api/apiHandler.js +56 -37
  330. package/dist/next/components/GlobalError.js +2 -1
  331. package/dist/next/routing/route-map.d.ts +27 -0
  332. package/dist/next/routing/route-map.js +10 -0
  333. package/dist/react/ErrorBoundary.js +2 -1
  334. package/dist/react/contexts/SessionContext.js +38 -28
  335. package/dist/react/hooks/useCamera.d.ts +1 -1
  336. package/dist/react/hooks/useCamera.js +8 -7
  337. package/dist/seed/site-settings-seed-data.js +6 -0
  338. package/dist/server-entry.d.ts +3 -0
  339. package/dist/server-entry.js +3 -0
  340. package/dist/server.d.ts +12 -0
  341. package/dist/server.js +15 -0
  342. package/dist/tailwind-utilities.css +1 -1
  343. package/dist/ui/DataTable.js +28 -7
  344. package/dist/ui/components/Button.d.ts +8 -1
  345. package/dist/ui/components/Button.js +47 -8
  346. package/dist/ui/components/CollageLightbox.d.ts +18 -0
  347. package/dist/ui/components/CollageLightbox.js +41 -0
  348. package/dist/ui/components/Dropdown.js +7 -6
  349. package/dist/ui/components/ImageLightbox.d.ts +7 -1
  350. package/dist/ui/components/ImageLightbox.js +15 -5
  351. package/dist/ui/components/PageLoader.js +4 -3
  352. package/dist/ui/components/PaginatedMultiSelect.d.ts +28 -0
  353. package/dist/ui/components/PaginatedMultiSelect.js +141 -0
  354. package/dist/ui/components/PaginatedMultiSelect.style.css +272 -0
  355. package/dist/ui/components/Semantic.js +1 -1
  356. package/dist/ui/components/SideDrawer.js +17 -15
  357. package/dist/ui/components/index.style.css +1 -0
  358. package/dist/ui/index.d.ts +2 -0
  359. package/dist/ui/index.js +1 -0
  360. package/dist/utils/number.formatter.js +5 -13
  361. package/dist/utils/string.formatter.js +21 -18
  362. package/dist/validation/schemas.d.ts +2 -2
  363. package/package.json +2 -2
@@ -10,15 +10,18 @@
10
10
  */
11
11
  import { NextResponse } from "next/server.js";
12
12
  import { getProviders } from "../../../../contracts";
13
+ const ERR_INQUIRY_ID_REQUIRED = "Inquiry 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: "Inquiry ID required" }, { status: 400 });
20
+ return NextResponse.json({ success: false, error: ERR_INQUIRY_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("corporate_inquiries");
23
26
  const inquiry = await repo.findById(id);
24
27
  if (!inquiry) {
@@ -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: "Inquiry ID required" }, { status: 400 });
46
+ return NextResponse.json({ success: false, error: ERR_INQUIRY_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("corporate_inquiries");
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: "Inquiry ID required" }, { status: 400 });
73
+ return NextResponse.json({ success: false, error: ERR_INQUIRY_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("corporate_inquiries");
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, Text, Textarea } from "../../../ui";
5
+ const CLS_INPUT = "w-full rounded-md border border-neutral-300 px-3 py-2 text-sm";
5
6
  export function CorporateInquiryForm({ onSubmit, isPending, }) {
6
7
  const [form, setForm] = React.useState({
7
8
  companyName: "",
@@ -32,5 +33,5 @@ export function CorporateInquiryForm({ onSubmit, isPending, }) {
32
33
  e.preventDefault();
33
34
  await onSubmit(form);
34
35
  }
35
- return (_jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [_jsxs(Div, { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: [_jsx(Input, { name: "companyName", type: "text", placeholder: "Company name", value: form.companyName, onChange: handleChange, required: true, className: "w-full rounded-md border border-neutral-300 px-3 py-2 text-sm" }), _jsx(Input, { name: "contactPerson", type: "text", placeholder: "Contact person", value: form.contactPerson, onChange: handleChange, required: true, className: "w-full rounded-md border border-neutral-300 px-3 py-2 text-sm" }), _jsx(Input, { name: "designation", type: "text", placeholder: "Designation (optional)", value: form.designation ?? "", onChange: handleChange, className: "w-full rounded-md border border-neutral-300 px-3 py-2 text-sm" }), _jsx(Input, { name: "email", type: "email", placeholder: "Business email", 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" }), _jsx(Input, { name: "units", type: "number", placeholder: "Number of units", value: form.units, onChange: handleChange, min: 1, required: true, className: "w-full rounded-md border border-neutral-300 px-3 py-2 text-sm" }), _jsx(Input, { name: "budgetPerUnit", type: "number", placeholder: "Budget per unit (optional)", value: form.budgetPerUnit ?? "", onChange: handleChange, min: 0, className: "w-full rounded-md border border-neutral-300 px-3 py-2 text-sm" }), _jsx(Input, { name: "deliveryDateRequired", type: "date", placeholder: "Required by (optional)", value: form.deliveryDateRequired ?? "", onChange: handleChange, className: "w-full rounded-md border border-neutral-300 px-3 py-2 text-sm" })] }), _jsxs(Div, { className: "flex items-center gap-2 text-sm text-neutral-700", children: [_jsx("input", { name: "customBranding", type: "checkbox", checked: form.customBranding, onChange: handleChange, className: "h-4 w-4 rounded border-neutral-300" }), _jsx(Text, { className: "text-sm text-neutral-700", children: "Custom branding required" })] }), _jsx(Textarea, { name: "message", placeholder: "Additional requirements (optional)", value: form.message ?? "", onChange: handleChange, rows: 4, 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 ? "Submitting..." : "Submit Inquiry" })] }));
36
+ return (_jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [_jsxs(Div, { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: [_jsx(Input, { name: "companyName", type: "text", placeholder: "Company name", value: form.companyName, onChange: handleChange, required: true, className: CLS_INPUT }), _jsx(Input, { name: "contactPerson", type: "text", placeholder: "Contact person", value: form.contactPerson, onChange: handleChange, required: true, className: CLS_INPUT }), _jsx(Input, { name: "designation", type: "text", placeholder: "Designation (optional)", value: form.designation ?? "", onChange: handleChange, className: CLS_INPUT }), _jsx(Input, { name: "email", type: "email", placeholder: "Business email", 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 }), _jsx(Input, { name: "units", type: "number", placeholder: "Number of units", value: form.units, onChange: handleChange, min: 1, required: true, className: CLS_INPUT }), _jsx(Input, { name: "budgetPerUnit", type: "number", placeholder: "Budget per unit (optional)", value: form.budgetPerUnit ?? "", onChange: handleChange, min: 0, className: CLS_INPUT }), _jsx(Input, { name: "deliveryDateRequired", type: "date", placeholder: "Required by (optional)", value: form.deliveryDateRequired ?? "", onChange: handleChange, className: CLS_INPUT })] }), _jsxs(Div, { className: "flex items-center gap-2 text-sm text-neutral-700", children: [_jsx("input", { name: "customBranding", type: "checkbox", checked: form.customBranding, onChange: handleChange, className: "h-4 w-4 rounded border-neutral-300" }), _jsx(Text, { className: "text-sm text-neutral-700", children: "Custom branding required" })] }), _jsx(Textarea, { name: "message", placeholder: "Additional requirements (optional)", value: form.message ?? "", onChange: handleChange, rows: 4, 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 ? "Submitting..." : "Submit Inquiry" })] }));
36
37
  }
@@ -0,0 +1,8 @@
1
+ import type { FacetOption } from "../../filters/FilterFacetSection";
2
+ import type { UrlTable } from "../../filters/FilterPanel";
3
+ export interface DigitalCodeFiltersProps {
4
+ table: UrlTable;
5
+ categoryOptions?: FacetOption[];
6
+ currencyPrefix?: string;
7
+ }
8
+ export declare function DigitalCodeFilters({ table, categoryOptions, currencyPrefix, }: DigitalCodeFiltersProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,16 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { FilterFacetSection } from "../../filters/FilterFacetSection";
4
+ import { RangeFilter } from "../../filters/RangeFilter";
5
+ import { Div } from "../../../ui";
6
+ const DELIVERY_OPTIONS = [
7
+ { value: "auto-claim", label: "Instant (auto-claim)" },
8
+ { value: "manual-email", label: "Manual (sent by seller)" },
9
+ ];
10
+ export function DigitalCodeFilters({ table, categoryOptions = [], currencyPrefix = "₹", }) {
11
+ const selectedCategories = table.get("category")
12
+ ? table.get("category").split("|").filter(Boolean)
13
+ : [];
14
+ const selectedDelivery = table.get("deliveryMethod") ? [table.get("deliveryMethod")] : [];
15
+ return (_jsxs(Div, { children: [categoryOptions.length > 0 && (_jsx(FilterFacetSection, { title: "Category", options: categoryOptions, selected: selectedCategories, onChange: (vals) => table.set("category", vals.join("|")), searchable: true, defaultCollapsed: categoryOptions.length > 6 })), _jsx(FilterFacetSection, { title: "Delivery Method", options: DELIVERY_OPTIONS, selected: selectedDelivery, onChange: (vals) => table.set("deliveryMethod", vals[0] ?? ""), searchable: false, selectionMode: "single", defaultCollapsed: false }), _jsx(RangeFilter, { title: "Price per Code", 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: 50000, step: 50, minPlaceholder: "Min price", maxPlaceholder: "Max price", defaultCollapsed: false })] }));
16
+ }
@@ -0,0 +1,4 @@
1
+ export interface DigitalCodesIndexListingProps {
2
+ initialData?: any;
3
+ }
4
+ export declare function DigitalCodesIndexListing({ initialData }: DigitalCodesIndexListingProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,107 @@
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, useToast } 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 { DigitalCodeFilters } from "./DigitalCodeFilters";
19
+ import { ACTION_ID } from "../../products/constants/action-defs";
20
+ const DEFAULT_SORT = sortBy(PRODUCT_FIELDS.CREATED_AT);
21
+ const SORT_OPTIONS = [
22
+ { value: sortBy(PRODUCT_FIELDS.CREATED_AT), label: "Newest First" },
23
+ { value: sortBy(PRODUCT_FIELDS.CREATED_AT, "ASC"), label: "Oldest First" },
24
+ { value: sortBy(PRODUCT_FIELDS.PRICE, "ASC"), label: "Price: Low to High" },
25
+ { value: sortBy(PRODUCT_FIELDS.PRICE), label: "Price: High to Low" },
26
+ ];
27
+ const FILTER_KEYS = [
28
+ TABLE_KEYS.CATEGORY,
29
+ TABLE_KEYS.DELIVERY_METHOD,
30
+ TABLE_KEYS.MIN_PRICE,
31
+ TABLE_KEYS.MAX_PRICE,
32
+ ];
33
+ export function DigitalCodesIndexListing({ initialData }) {
34
+ const table = useUrlTable({ defaults: { pageSize: "24", sort: DEFAULT_SORT } });
35
+ const { showToast } = useToast();
36
+ const { requireAuth, modalOpen, modalMessage, closeModal } = useAuthGate();
37
+ const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
38
+ const [filterOpen, setFilterOpen] = useState(false);
39
+ const [view, setView] = useState(table.get(TABLE_KEYS.VIEW) || VIEW_MODE.GRID);
40
+ const localWishlist = useGuestWishlist();
41
+ const { categories } = useCategoryTree();
42
+ const categoryOptions = categoriesToFacetOptions(categories);
43
+ const wishlistedIds = new Set(localWishlist.items.filter((i) => i.type === "digital-code").map((i) => i.itemId));
44
+ const { pendingTable, filterActiveCount, onFilterApply, onFilterClear, onFilterReset } = usePendingTable(table, FILTER_KEYS);
45
+ const openFilters = useCallback(() => {
46
+ onFilterReset();
47
+ setFilterOpen(true);
48
+ }, [onFilterReset]);
49
+ const applyFilters = useCallback(() => {
50
+ onFilterApply();
51
+ setFilterOpen(false);
52
+ }, [onFilterApply]);
53
+ const resetAll = useCallback(() => {
54
+ table.setMany({ [TABLE_KEYS.QUERY]: "", [TABLE_KEYS.SORT]: "" });
55
+ onFilterClear();
56
+ setSearchInput("");
57
+ }, [table, onFilterClear]);
58
+ const hasActiveState = !!table.get(TABLE_KEYS.QUERY) ||
59
+ table.get(TABLE_KEYS.SORT) !== DEFAULT_SORT ||
60
+ filterActiveCount > 0;
61
+ const params = {
62
+ q: table.get(TABLE_KEYS.QUERY) || undefined,
63
+ category: table.get(TABLE_KEYS.CATEGORY) || undefined,
64
+ minPrice: table.get(TABLE_KEYS.MIN_PRICE) ? Number(table.get(TABLE_KEYS.MIN_PRICE)) : undefined,
65
+ maxPrice: table.get(TABLE_KEYS.MAX_PRICE) ? Number(table.get(TABLE_KEYS.MAX_PRICE)) : undefined,
66
+ sort: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT,
67
+ page: table.getNumber(TABLE_KEYS.PAGE, 1),
68
+ perPage: table.getNumber(TABLE_KEYS.PAGE_SIZE, 24),
69
+ listingType: "digital-code",
70
+ };
71
+ const { products, totalPages, page, isLoading } = useProducts(params, { initialData });
72
+ const commitSearch = useCallback(() => {
73
+ table.set(TABLE_KEYS.QUERY, searchInput.trim());
74
+ }, [searchInput, table]);
75
+ const selection = useBulkSelection({ items: products, keyExtractor: (p) => p.id });
76
+ const gridClass = "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4";
77
+ const wishlistActions = {
78
+ addToWishlist: (productId) => {
79
+ requireAuth(ACTION_ID.ADD_TO_WISHLIST, () => {
80
+ localWishlist.add(productId, "digital-code");
81
+ pushWishlistOp({ op: "add", itemId: productId, type: "digital-code" });
82
+ showToast("Added to wishlist", "success");
83
+ });
84
+ return Promise.resolve();
85
+ },
86
+ removeFromWishlist: (productId) => {
87
+ requireAuth(ACTION_ID.REMOVE_FROM_WISHLIST, () => {
88
+ localWishlist.remove(productId, "digital-code");
89
+ pushWishlistOp({ op: "remove", itemId: productId, type: "digital-code" });
90
+ showToast("Removed from wishlist", "info");
91
+ });
92
+ return Promise.resolve();
93
+ },
94
+ isWishlisted: (productId) => wishlistedIds.has(productId),
95
+ };
96
+ function handleToggleWishlist(id) {
97
+ if (wishlistActions.isWishlisted(id)) {
98
+ wishlistActions.removeFromWishlist(id);
99
+ }
100
+ else {
101
+ wishlistActions.addToWishlist(id);
102
+ }
103
+ }
104
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search digital codes\u2026", onSearchChange: setSearchInput, onSearchCommit: commitSearch, onSearchKeyDown: (e) => { if (e.key === "Enter")
105
+ 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")
106
+ 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 digital code 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.DIGITAL_CODE_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(DigitalCodeFilters, { table: pendingTable, categoryOptions: categoryOptions }) }), _jsx(LoginRequiredModal, { isOpen: modalOpen, onClose: closeModal, message: modalMessage })] }));
107
+ }
@@ -0,0 +1,6 @@
1
+ type SearchParams = Record<string, string | string[]>;
2
+ export interface DigitalCodesListViewProps {
3
+ searchParams?: SearchParams;
4
+ }
5
+ export declare function DigitalCodesListView({ searchParams }: DigitalCodesListViewProps): Promise<import("react/jsx-runtime").JSX.Element>;
6
+ export {};
@@ -0,0 +1,37 @@
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 { DigitalCodesIndexListing } from "./DigitalCodesIndexListing";
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 buildDigitalCodeFilters(params) {
15
+ const parts = ["status==published", "listingType==digital-code"];
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 deliveryMethod = sp(params, "deliveryMethod");
23
+ if (deliveryMethod)
24
+ parts.push(`digitalCodeDelivery==${deliveryMethod}`);
25
+ return parts.join(",");
26
+ }
27
+ export async function DigitalCodesListView({ searchParams = {} }) {
28
+ const std = parseListingSearchParams(searchParams);
29
+ const sort = std.sorts ?? DEFAULT_SORT;
30
+ const page = std.page ?? DEFAULT_PAGE;
31
+ const pageSize = std.pageSize ?? DEFAULT_PAGE_SIZE;
32
+ const filters = buildDigitalCodeFilters(searchParams);
33
+ const result = await productRepository
34
+ .list({ filters, sorts: sort, page, pageSize })
35
+ .catch(() => null);
36
+ 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: "Digital Codes" }), _jsx(AdSlot, { id: "listing-sidebar-top", className: "mb-6" }), _jsx(DigitalCodesIndexListing, { initialData: result ?? undefined }), _jsx(AdSlot, { id: "listing-sidebar-bottom", className: "mt-8" })] }) }) }));
37
+ }
@@ -0,0 +1,6 @@
1
+ export { DigitalCodesListView } from "./DigitalCodesListView";
2
+ export type { DigitalCodesListViewProps } from "./DigitalCodesListView";
3
+ export { DigitalCodesIndexListing } from "./DigitalCodesIndexListing";
4
+ export type { DigitalCodesIndexListingProps } from "./DigitalCodesIndexListing";
5
+ export { DigitalCodeFilters } from "./DigitalCodeFilters";
6
+ export type { DigitalCodeFiltersProps } from "./DigitalCodeFilters";
@@ -0,0 +1,3 @@
1
+ export { DigitalCodesListView } from "./DigitalCodesListView";
2
+ export { DigitalCodesIndexListing } from "./DigitalCodesIndexListing";
3
+ export { DigitalCodeFilters } from "./DigitalCodeFilters";
@@ -10,6 +10,7 @@ import { eventEntryRepository } from "../repository/event-entry.repository";
10
10
  import { maskPublicEventEntry } from "../../../security";
11
11
  import { ERROR_MESSAGES, AuthorizationError, ValidationError, NotFoundError, } from "../../../errors";
12
12
  import { resolveDate } from "../../../utils";
13
+ const ERR_EVENT_NOT_FOUND = "Event not found";
13
14
  import { coerceMediaField, getMediaUrl } from "../../../utils";
14
15
  import { finalizeStagedMediaField, finalizeStagedMediaObject, finalizeStagedMediaObjectArray, } from "../../media/finalize";
15
16
  // --- Admin: Create Event --------------------------------------------------
@@ -36,7 +37,7 @@ export async function createEvent(adminId, input) {
36
37
  export async function updateEvent(adminId, id, input) {
37
38
  const existing = await eventRepository.findById(id);
38
39
  if (!existing)
39
- throw new NotFoundError("Event not found");
40
+ throw new NotFoundError(ERR_EVENT_NOT_FOUND);
40
41
  const finalizedCoverUrl = await finalizeStagedMediaField(getMediaUrl(input.coverImage) ??
41
42
  input.coverImageUrl);
42
43
  const finalizedCoverImage = input.coverImageUrl === null
@@ -68,7 +69,7 @@ export async function updateEvent(adminId, id, input) {
68
69
  export async function deleteEvent(adminId, id) {
69
70
  const existing = await eventRepository.findById(id);
70
71
  if (!existing)
71
- throw new NotFoundError("Event not found");
72
+ throw new NotFoundError(ERR_EVENT_NOT_FOUND);
72
73
  await eventRepository.delete(id);
73
74
  serverLogger.info("deleteEvent", { adminId, eventId: id });
74
75
  }
@@ -76,7 +77,7 @@ export async function deleteEvent(adminId, id) {
76
77
  export async function changeEventStatus(adminId, id, status) {
77
78
  const existing = await eventRepository.findById(id);
78
79
  if (!existing)
79
- throw new NotFoundError("Event not found");
80
+ throw new NotFoundError(ERR_EVENT_NOT_FOUND);
80
81
  const updated = await eventRepository.changeStatus(id, status);
81
82
  serverLogger.info("changeEventStatus", { adminId, eventId: id, status });
82
83
  return updated;
@@ -1,10 +1,11 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import React from "react";
4
4
  import { useMutation, useQuery } from "@tanstack/react-query";
5
5
  import { Alert, Button, Form, FormActions, Input, RichTextEditor, Select, StackedViewShell, Text, Toggle, } from "../../../ui";
6
6
  import { apiClient } from "../../../http";
7
7
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
8
+ const CLS_PANEL_SM = "rounded-lg border border-zinc-200 dark:border-zinc-700 bg-zinc-50 dark:bg-zinc-800 p-3 space-y-2";
8
9
  function toLocalDatetime(iso) {
9
10
  if (!iso)
10
11
  return "";
@@ -292,7 +293,7 @@ export function AdminEventEditorView({ eventId, onSaved, embedded, ...rest }) {
292
293
  const formSection = (_jsxs(Form, { onSubmit: (e) => {
293
294
  e.preventDefault();
294
295
  saveMutation.mutate();
295
- }, className: "space-y-6", children: [!eventId && (_jsx(Select, { label: "Event type", value: type, options: EVENT_TYPE_OPTIONS, onChange: (e) => setType(e.target.value) })), _jsx(Input, { label: "Title", value: title, onChange: (e) => setTitle(e.target.value), placeholder: "Charizard Flash Sale 2026", required: true }), _jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1", children: "Description" }), _jsx(RichTextEditor, { value: description, onChange: setDescription, minHeightClassName: "min-h-[120px]", placeholder: "Describe this event\u2026" })] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [_jsx(Input, { label: "Starts at", type: "datetime-local", value: startsAt, onChange: (e) => setStartsAt(e.target.value), required: true }), _jsx(Input, { label: "Ends at", type: "datetime-local", value: endsAt, onChange: (e) => setEndsAt(e.target.value), required: true })] }), _jsx(Input, { label: "Cover image URL (optional)", value: coverImageUrl, onChange: (e) => setCoverImageUrl(e.target.value), placeholder: "https://\u2026" }), eventId && (_jsx(Select, { label: "Status", value: status, options: EVENT_STATUS_OPTIONS, onChange: (e) => setStatus(e.target.value) })), type === "sale" && (_jsxs("div", { className: "rounded-xl border border-zinc-200 dark:border-slate-700 p-4 space-y-3", children: [_jsx(Text, { className: "text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Sale configuration" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [_jsx(Input, { label: "Discount %", type: "number", value: discountPercent, onChange: (e) => setDiscountPercent(e.target.value), placeholder: "10" }), _jsx(Input, { label: "Banner text (optional)", value: saleBannerText, onChange: (e) => setSaleBannerText(e.target.value), placeholder: "Limited time \u2014 ends Sunday!" })] })] })), type === "offer" && (_jsxs("div", { className: "rounded-xl border border-zinc-200 dark:border-slate-700 p-4 space-y-3", children: [_jsx(Text, { className: "text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Offer configuration" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [_jsx(Input, { label: "Coupon ID", value: couponId, onChange: (e) => setCouponId(e.target.value), placeholder: "Firestore coupon document ID", required: true }), _jsx(Input, { label: "Display code", value: displayCode, onChange: (e) => setDisplayCode(e.target.value), placeholder: "CHARIZARD25", required: true })] }), _jsx(Input, { label: "Banner text (optional)", value: offerBannerText, onChange: (e) => setOfferBannerText(e.target.value), placeholder: "Use CHARIZARD25 at checkout" })] })), type === "poll" && (_jsxs("div", { className: "rounded-xl border border-zinc-200 dark:border-slate-700 p-4 space-y-4", children: [_jsx(Text, { className: "text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Poll configuration" }), _jsxs("div", { className: "space-y-2", children: [_jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Options (minimum 2)" }), pollOptions.map((opt, idx) => (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex-1", children: _jsx(Input, { value: opt.label, onChange: (e) => updatePollOption(opt.id, e.target.value), placeholder: `Option ${idx + 1}` }) }), pollOptions.length > 2 && (_jsx("button", { type: "button", onClick: () => removePollOption(opt.id), className: "text-zinc-400 hover:text-red-500 transition-colors px-2 py-1 text-lg leading-none", "aria-label": "Remove option", children: "\u00D7" }))] }, opt.id))), _jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: addPollOption, children: "+ Add option" })] }), _jsx(Select, { label: "Results visibility", value: resultsVisibility, options: POLL_VISIBILITY_OPTIONS, onChange: (e) => setResultsVisibility(e.target.value) }), _jsxs("div", { className: "space-y-3", children: [_jsx(Toggle, { checked: allowMultiSelect, onChange: setAllowMultiSelect, label: "Allow multi-select" }), _jsx(Toggle, { checked: allowComment, onChange: setAllowComment, label: "Allow comment with vote" })] })] })), type === "survey" && (_jsxs("div", { className: "rounded-xl border border-zinc-200 dark:border-slate-700 p-4 space-y-3", children: [_jsx(Text, { className: "text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Survey configuration" }), _jsx(Input, { label: "Max entries per user", type: "number", value: maxEntriesPerUser, onChange: (e) => setMaxEntriesPerUser(e.target.value), placeholder: "1" }), _jsx(Toggle, { checked: requireLogin, onChange: setRequireLogin, label: "Require login to participate" }), _jsx(Toggle, { checked: hasLeaderboard, onChange: setHasLeaderboard, label: "Show leaderboard" }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Form fields can be configured from the event detail page after saving." })] })), type === "feedback" && (_jsxs("div", { className: "rounded-xl border border-zinc-200 dark:border-slate-700 p-4 space-y-3", children: [_jsx(Text, { className: "text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Feedback configuration" }), _jsx(Toggle, { checked: anonymous, onChange: setAnonymous, label: "Allow anonymous submissions" }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Form fields can be configured from the event detail page after saving." })] })), _jsxs("div", { className: "rounded-xl border border-zinc-200 dark:border-slate-700 p-4 space-y-4", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx(Text, { className: "text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Raffle & spin wheel" }), type !== "raffle" && type !== "spin_wheel" && (_jsx(Toggle, { checked: hasRaffle, onChange: setHasRaffle, label: "Attach raffle" }))] }), (hasRaffle || type === "raffle" || type === "spin_wheel") && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [_jsx(Select, { label: "Raffle type", value: type === "spin_wheel" ? "spin_wheel" : raffleType, options: RAFFLE_TYPE_OPTIONS, onChange: (e) => setRaffleType(e.target.value), disabled: type === "spin_wheel" }), _jsx(Input, { label: "Top N (for top-N raffle types)", type: "number", value: raffleTopN, onChange: (e) => setRaffleTopN(e.target.value), placeholder: "10" })] }), _jsx(Input, { label: "Prize description", value: rafflePrize, onChange: (e) => setRafflePrize(e.target.value), placeholder: "\u20B92,000 store credit + exclusive Pikachu sticker" }), _jsx(Input, { label: "Coupon ID for winner (optional)", value: rafflePrizeCouponId, onChange: (e) => setRafflePrizeCouponId(e.target.value), placeholder: "coupon-vip-winner-2026" }), (raffleType === "spin_wheel" || type === "spin_wheel") && (_jsxs("div", { className: "rounded-lg border border-zinc-200 dark:border-slate-700 p-3 space-y-3", children: [_jsx(Text, { className: "text-xs font-medium text-zinc-600 dark:text-zinc-300", children: "Spin prizes (weighted random)" }), spinPrizes.length === 0 && (_jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "No spin prizes yet. Add at least one to enable spinning." })), spinPrizes.map((p) => (_jsxs("div", { className: "grid grid-cols-12 gap-2 items-end", children: [_jsx("div", { className: "col-span-5", children: _jsx(Input, { label: "Label", value: p.label, onChange: (e) => updateSpinPrize(p.id, { label: e.target.value }), placeholder: "\u20B9100 off" }) }), _jsx("div", { className: "col-span-3", children: _jsx(Input, { label: "Coupon ID", value: p.couponId ?? "", onChange: (e) => updateSpinPrize(p.id, {
296
+ }, className: "space-y-6", children: [!eventId && (_jsx(Select, { label: "Event type", value: type, options: EVENT_TYPE_OPTIONS, onChange: (e) => setType(e.target.value) })), _jsx(Input, { label: "Title", value: title, onChange: (e) => setTitle(e.target.value), placeholder: "Charizard Flash Sale 2026", required: true }), _jsxs(_Fragment, { children: [_jsx("label", { className: "block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1", children: "Description" }), _jsx(RichTextEditor, { value: description, onChange: setDescription, minHeightClassName: "min-h-[120px]", placeholder: "Describe this event\u2026" })] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [_jsx(Input, { label: "Starts at", type: "datetime-local", value: startsAt, onChange: (e) => setStartsAt(e.target.value), required: true }), _jsx(Input, { label: "Ends at", type: "datetime-local", value: endsAt, onChange: (e) => setEndsAt(e.target.value), required: true })] }), _jsx(Input, { label: "Cover image URL (optional)", value: coverImageUrl, onChange: (e) => setCoverImageUrl(e.target.value), placeholder: "https://\u2026" }), eventId && (_jsx(Select, { label: "Status", value: status, options: EVENT_STATUS_OPTIONS, onChange: (e) => setStatus(e.target.value) })), type === "sale" && (_jsxs("div", { className: CLS_PANEL_SM, children: [_jsx(Text, { className: "text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Sale configuration" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [_jsx(Input, { label: "Discount %", type: "number", value: discountPercent, onChange: (e) => setDiscountPercent(e.target.value), placeholder: "10" }), _jsx(Input, { label: "Banner text (optional)", value: saleBannerText, onChange: (e) => setSaleBannerText(e.target.value), placeholder: "Limited time \u2014 ends Sunday!" })] })] })), type === "offer" && (_jsxs("div", { className: CLS_PANEL_SM, children: [_jsx(Text, { className: "text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Offer configuration" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [_jsx(Input, { label: "Coupon ID", value: couponId, onChange: (e) => setCouponId(e.target.value), placeholder: "Firestore coupon document ID", required: true }), _jsx(Input, { label: "Display code", value: displayCode, onChange: (e) => setDisplayCode(e.target.value), placeholder: "CHARIZARD25", required: true })] }), _jsx(Input, { label: "Banner text (optional)", value: offerBannerText, onChange: (e) => setOfferBannerText(e.target.value), placeholder: "Use CHARIZARD25 at checkout" })] })), type === "poll" && (_jsxs("div", { className: "rounded-xl border border-zinc-200 dark:border-slate-700 p-4 space-y-4", children: [_jsx(Text, { className: "text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Poll configuration" }), _jsxs("div", { className: "space-y-2", children: [_jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Options (minimum 2)" }), pollOptions.map((opt, idx) => (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex-1", children: _jsx(Input, { value: opt.label, onChange: (e) => updatePollOption(opt.id, e.target.value), placeholder: `Option ${idx + 1}` }) }), pollOptions.length > 2 && (_jsx("button", { type: "button", onClick: () => removePollOption(opt.id), className: "text-zinc-400 hover:text-red-500 transition-colors px-2 py-1 text-lg leading-none", "aria-label": "Remove option", children: "\u00D7" }))] }, opt.id))), _jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: addPollOption, children: "+ Add option" })] }), _jsx(Select, { label: "Results visibility", value: resultsVisibility, options: POLL_VISIBILITY_OPTIONS, onChange: (e) => setResultsVisibility(e.target.value) }), _jsxs("div", { className: "space-y-3", children: [_jsx(Toggle, { checked: allowMultiSelect, onChange: setAllowMultiSelect, label: "Allow multi-select" }), _jsx(Toggle, { checked: allowComment, onChange: setAllowComment, label: "Allow comment with vote" })] })] })), type === "survey" && (_jsxs("div", { className: CLS_PANEL_SM, children: [_jsx(Text, { className: "text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Survey configuration" }), _jsx(Input, { label: "Max entries per user", type: "number", value: maxEntriesPerUser, onChange: (e) => setMaxEntriesPerUser(e.target.value), placeholder: "1" }), _jsx(Toggle, { checked: requireLogin, onChange: setRequireLogin, label: "Require login to participate" }), _jsx(Toggle, { checked: hasLeaderboard, onChange: setHasLeaderboard, label: "Show leaderboard" }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Form fields can be configured from the event detail page after saving." })] })), type === "feedback" && (_jsxs("div", { className: CLS_PANEL_SM, children: [_jsx(Text, { className: "text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Feedback configuration" }), _jsx(Toggle, { checked: anonymous, onChange: setAnonymous, label: "Allow anonymous submissions" }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Form fields can be configured from the event detail page after saving." })] })), _jsxs("div", { className: "rounded-xl border border-zinc-200 dark:border-slate-700 p-4 space-y-4", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx(Text, { className: "text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Raffle & spin wheel" }), type !== "raffle" && type !== "spin_wheel" && (_jsx(Toggle, { checked: hasRaffle, onChange: setHasRaffle, label: "Attach raffle" }))] }), (hasRaffle || type === "raffle" || type === "spin_wheel") && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [_jsx(Select, { label: "Raffle type", value: type === "spin_wheel" ? "spin_wheel" : raffleType, options: RAFFLE_TYPE_OPTIONS, onChange: (e) => setRaffleType(e.target.value), disabled: type === "spin_wheel" }), _jsx(Input, { label: "Top N (for top-N raffle types)", type: "number", value: raffleTopN, onChange: (e) => setRaffleTopN(e.target.value), placeholder: "10" })] }), _jsx(Input, { label: "Prize description", value: rafflePrize, onChange: (e) => setRafflePrize(e.target.value), placeholder: "\u20B92,000 store credit + exclusive Pikachu sticker" }), _jsx(Input, { label: "Coupon ID for winner (optional)", value: rafflePrizeCouponId, onChange: (e) => setRafflePrizeCouponId(e.target.value), placeholder: "coupon-vip-winner-2026" }), (raffleType === "spin_wheel" || type === "spin_wheel") && (_jsxs("div", { className: "rounded-lg border border-zinc-200 dark:border-slate-700 p-3 space-y-3", children: [_jsx(Text, { className: "text-xs font-medium text-zinc-600 dark:text-zinc-300", children: "Spin prizes (weighted random)" }), spinPrizes.length === 0 && (_jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "No spin prizes yet. Add at least one to enable spinning." })), spinPrizes.map((p) => (_jsxs("div", { className: "grid grid-cols-12 gap-2 items-end", children: [_jsx("div", { className: "col-span-5", children: _jsx(Input, { label: "Label", value: p.label, onChange: (e) => updateSpinPrize(p.id, { label: e.target.value }), placeholder: "\u20B9100 off" }) }), _jsx("div", { className: "col-span-3", children: _jsx(Input, { label: "Coupon ID", value: p.couponId ?? "", onChange: (e) => updateSpinPrize(p.id, {
296
297
  couponId: e.target.value || undefined,
297
298
  }) }) }), _jsx("div", { className: "col-span-2", children: _jsx(Input, { label: "Weight", type: "number", value: String(p.weight), onChange: (e) => updateSpinPrize(p.id, {
298
299
  weight: Number(e.target.value) || 0,
@@ -6,7 +6,7 @@ import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
6
  import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
7
7
  import { AdminViewCards } from "../../admin/components/AdminViewCards";
8
8
  import { usePanelUrlSync } from "../../../react/hooks/use-panel-url-sync";
9
- import { Button, FilterChipGroup, ListingToolbar, Pagination, ListingViewShell, SideDrawer } from "../../../ui";
9
+ import { BulkActionBar, Button, FilterChipGroup, ListingToolbar, Pagination, ListingViewShell, SideDrawer } from "../../../ui";
10
10
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
11
11
  import { ADMIN_EVENT_STATUS_TABS } from "../../admin/constants/filter-tabs";
12
12
  import { toRecordArray, toRelativeDate, toStringValue, useAdminListingData, } from "../../admin/hooks/useAdminListingData";
@@ -102,5 +102,7 @@ export function AdminEventsView({ children, getRowHref, ...props }) {
102
102
  if (hasChildren) {
103
103
  return _jsx(ListingViewShell, { portal: "admin", ...props, children: children });
104
104
  }
105
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search events by title or type", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: openCreatePanel, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), "Add Event"] }) }), 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: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-200", children: errorMessage })), view === "table" ? (_jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No events found", onRowClick: (row) => openEditPanel(row.id) })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No events found", onRowClick: undefined, selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsxs("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: [_jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }), _jsx(FilterChipGroup, { label: "Type", tabs: TYPE_OPTIONS, value: pendingFilters.type ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, type: id })) })] }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] })), _jsx(SideDrawer, { isOpen: isCreateOpen || isEditOpen, onClose: closePanel, title: isCreateOpen ? "Add Event" : "Edit Event", mode: isCreateOpen ? "create" : "edit", children: (isCreateOpen || isEditOpen) && (_jsx(AdminEventEditorView, { eventId: editId ?? undefined, onSaved: closePanel, embedded: true })) })] }));
105
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search events by title or type", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: openCreatePanel, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), "Add Event"] }) }), _jsx(BulkActionBar, { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [
106
+ { id: "delete", label: "Delete Selected", variant: "secondary", onClick: () => { selection.clearSelection(); } },
107
+ ] }), 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: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-200", children: errorMessage })), view === "table" ? (_jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No events found", onRowClick: (row) => openEditPanel(row.id) })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No events found", onRowClick: undefined, selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsxs("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: [_jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }), _jsx(FilterChipGroup, { label: "Type", tabs: TYPE_OPTIONS, value: pendingFilters.type ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, type: id })) })] }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] })), _jsx(SideDrawer, { isOpen: isCreateOpen || isEditOpen, onClose: closePanel, title: isCreateOpen ? "Add Event" : "Edit Event", mode: isCreateOpen ? "create" : "edit", children: (isCreateOpen || isEditOpen) && (_jsx(AdminEventEditorView, { eventId: editId ?? undefined, onSaved: closePanel, embedded: true })) })] }));
106
108
  }
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState } from "react";
4
4
  import { useAuth } from "../../../react/contexts/SessionContext";
5
5
  import { ROUTES } from "../../../next";
6
- import { LoginRequiredModal } from "../../../ui";
6
+ import { LoginRequiredModal, Text } from "../../../ui";
7
7
  export function EventPollWidget({ eventId, pollConfig, eventStatus, totalEntries, entriesEndpoint, className = "", }) {
8
8
  const { user } = useAuth();
9
9
  const endpoint = entriesEndpoint ?? `/api/events/${eventId}/entries`;
@@ -56,13 +56,13 @@ export function EventPollWidget({ eventId, pollConfig, eventStatus, totalEntries
56
56
  }
57
57
  };
58
58
  if (isEnded) {
59
- return (_jsxs("div", { className: `rounded-xl border border-zinc-200 dark:border-zinc-700 px-5 py-4 space-y-3 ${className}`, "data-section": "eventpollwidget-div-1", children: [_jsx("p", { className: "text-sm font-medium text-zinc-500 dark:text-zinc-400", children: "This poll has closed." }), totalEntries !== undefined && (_jsxs("p", { className: "text-sm text-zinc-400 dark:text-zinc-500", children: [totalEntries.toLocaleString(), " vote", totalEntries !== 1 ? "s" : "", " cast"] })), _jsx("div", { className: "space-y-2", "data-section": "eventpollwidget-div-2", children: pollConfig.options.map((opt) => (_jsx("div", { className: "rounded-lg border border-zinc-100 dark:border-zinc-800 px-4 py-2.5 text-sm text-zinc-600 dark:text-zinc-400", "data-section": "eventpollwidget-div-3", children: opt.label }, opt.id))) })] }));
59
+ return (_jsxs("div", { className: `rounded-xl border border-zinc-200 dark:border-zinc-700 px-5 py-4 space-y-3 ${className}`, "data-section": "eventpollwidget-div-1", children: [_jsx(Text, { className: "text-sm font-medium text-zinc-500 dark:text-zinc-400", children: "This poll has closed." }), totalEntries !== undefined && (_jsxs(Text, { className: "text-sm text-zinc-400 dark:text-zinc-500", children: [totalEntries.toLocaleString(), " vote", totalEntries !== 1 ? "s" : "", " cast"] })), _jsx("div", { className: "space-y-2", "data-section": "eventpollwidget-div-2", children: pollConfig.options.map((opt) => (_jsx("div", { className: "rounded-lg border border-zinc-100 dark:border-zinc-800 px-4 py-2.5 text-sm text-zinc-600 dark:text-zinc-400", "data-section": "eventpollwidget-div-3", children: opt.label }, opt.id))) })] }));
60
60
  }
61
61
  if (pollConfig.requireLogin && !user) {
62
- return (_jsxs("div", { className: `rounded-xl border border-zinc-200 dark:border-zinc-700 px-6 py-8 text-center space-y-3 ${className}`, "data-section": "eventpollwidget-div-4", children: [_jsx("p", { className: "font-semibold text-zinc-900 dark:text-zinc-100", children: "Login to vote" }), _jsx("p", { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "You need an account to participate in this poll." }), _jsx("a", { href: String(ROUTES.AUTH.LOGIN), className: "inline-block rounded-xl bg-primary px-6 py-2.5 text-sm font-semibold text-white hover:bg-primary-600", children: "Log In" })] }));
62
+ return (_jsxs("div", { className: `rounded-xl border border-zinc-200 dark:border-zinc-700 px-6 py-8 text-center space-y-3 ${className}`, "data-section": "eventpollwidget-div-4", children: [_jsx(Text, { className: "font-semibold text-zinc-900 dark:text-zinc-100", children: "Login to vote" }), _jsx(Text, { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "You need an account to participate in this poll." }), _jsx("a", { href: String(ROUTES.AUTH.LOGIN), className: "inline-block rounded-xl bg-primary px-6 py-2.5 text-sm font-semibold text-white hover:bg-primary-600", children: "Log In" })] }));
63
63
  }
64
64
  if (isSubmitted) {
65
- return (_jsxs("div", { className: `rounded-xl border border-green-200 dark:border-green-800 bg-green-50 dark:bg-green-900/20 px-6 py-8 text-center space-y-2 ${className}`, "data-section": "eventpollwidget-div-5", children: [_jsx("p", { className: "font-semibold text-green-700 dark:text-green-300", children: "Vote recorded!" }), _jsx("p", { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "Thanks for participating." })] }));
65
+ return (_jsxs("div", { className: `rounded-xl border border-green-200 dark:border-green-800 bg-green-50 dark:bg-green-900/20 px-6 py-8 text-center space-y-2 ${className}`, "data-section": "eventpollwidget-div-5", children: [_jsx(Text, { className: "font-semibold text-green-700 dark:text-green-300", children: "Vote recorded!" }), _jsx(Text, { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "Thanks for participating." })] }));
66
66
  }
67
- return (_jsxs("div", { className: `space-y-4 ${className}`, "data-section": "eventpollwidget-div-6", children: [_jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to vote in this poll. Please log in or create an account to continue." }), _jsx("p", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-200", children: isMulti ? "Select all that apply:" : "Choose one:" }), _jsx("div", { className: "space-y-2", "data-section": "eventpollwidget-div-7", children: pollConfig.options.map((opt) => (_jsxs("label", { className: "flex items-center gap-3 cursor-pointer rounded-lg border border-zinc-200 dark:border-zinc-700 px-4 py-3 hover:bg-zinc-50 dark:hover:bg-zinc-800 transition-colors", children: [_jsx("input", { type: isMulti ? "checkbox" : "radio", name: `poll-${eventId}`, value: opt.id, checked: selectedVotes.includes(opt.id), onChange: () => toggleVote(opt.id), className: "accent-primary" }), _jsx("span", { className: "text-sm text-zinc-700 dark:text-zinc-300", children: opt.label })] }, opt.id))) }), pollConfig.allowComment && (_jsx("textarea", { value: comment, onChange: (e) => setComment(e.target.value), placeholder: "Add a comment (optional)", rows: 3, className: "w-full rounded-lg border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-800 dark:text-zinc-200 placeholder:text-zinc-400 focus:outline-none focus:ring-2 focus:ring-primary" })), error && _jsx("p", { className: "text-sm text-red-500", children: error }), _jsx("button", { type: "button", onClick: handleSubmit, disabled: isLoading || selectedVotes.length === 0, className: "w-full rounded-xl bg-primary px-6 py-3 text-sm font-semibold text-white hover:bg-primary-600 disabled:opacity-60", children: isLoading ? "Submitting…" : "Submit Vote" })] }));
67
+ return (_jsxs("div", { className: `space-y-4 ${className}`, "data-section": "eventpollwidget-div-6", children: [_jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to vote in this poll. Please log in or create an account to continue." }), _jsx(Text, { className: "text-sm font-medium text-zinc-700 dark:text-zinc-200", children: isMulti ? "Select all that apply:" : "Choose one:" }), _jsx("div", { className: "space-y-2", "data-section": "eventpollwidget-div-7", children: pollConfig.options.map((opt) => (_jsxs("label", { className: "flex items-center gap-3 cursor-pointer rounded-lg border border-zinc-200 dark:border-zinc-700 px-4 py-3 hover:bg-zinc-50 dark:hover:bg-zinc-800 transition-colors", children: [_jsx("input", { type: isMulti ? "checkbox" : "radio", name: `poll-${eventId}`, value: opt.id, checked: selectedVotes.includes(opt.id), onChange: () => toggleVote(opt.id), className: "accent-primary" }), _jsx("span", { className: "text-sm text-zinc-700 dark:text-zinc-300", children: opt.label })] }, opt.id))) }), pollConfig.allowComment && (_jsx("textarea", { value: comment, onChange: (e) => setComment(e.target.value), placeholder: "Add a comment (optional)", rows: 3, className: "w-full rounded-lg border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-800 dark:text-zinc-200 placeholder:text-zinc-400 focus:outline-none focus:ring-2 focus:ring-primary" })), error && _jsx(Text, { className: "text-sm text-red-500", children: error }), _jsx("button", { type: "button", onClick: handleSubmit, disabled: isLoading || selectedVotes.length === 0, className: "w-full rounded-xl bg-primary px-6 py-3 text-sm font-semibold text-white hover:bg-primary-600 disabled:opacity-60", children: isLoading ? "Submitting…" : "Submit Vote" })] }));
68
68
  }
@@ -4,7 +4,7 @@ import { useState, useCallback, useMemo } from "react";
4
4
  import { X } from "lucide-react";
5
5
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
6
  import { useEvents } from "../hooks/useEvents";
7
- import { Pagination, ListingToolbar } from "../../../ui";
7
+ import { ListingToolbar, Pagination, Text } from "../../../ui";
8
8
  import { EventCard } from "./EventCard";
9
9
  import { EventFilters, EVENT_PUBLIC_SORT_OPTIONS } from "./EventFilters";
10
10
  import { EVENT_FIELDS } from "../../../constants/field-names";
@@ -113,5 +113,5 @@ export function EventsIndexListing({ initialData }) {
113
113
  const commitSearch = useCallback(() => {
114
114
  table.set(TABLE_KEYS.QUERY, searchInput.trim());
115
115
  }, [searchInput, table]);
116
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search events...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get(TABLE_KEYS.SORT) || sortBy(EVENT_FIELDS.STARTS_AT, "ASC"), sortOptions: EVENT_PUBLIC_SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, view: view, onViewChange: handleViewToggle, onResetAll: resetAll, hasActiveState: hasActiveState }), 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: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsx("div", { className: "py-6", children: isLoading ? (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: Array.from({ length: 6 }).map((_, i) => (_jsxs("div", { className: "rounded-xl border border-zinc-100 dark:border-slate-700 overflow-hidden animate-pulse", children: [_jsx("div", { className: "aspect-video bg-zinc-200 dark:bg-slate-700" }), _jsxs("div", { className: "p-4 space-y-2", children: [_jsx("div", { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-3/4" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-2/3" }), _jsx("div", { className: "h-8 bg-zinc-200 dark:bg-slate-700 rounded mt-2" })] })] }, i))) })) : events.length === 0 ? (_jsx("p", { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: "No events found." })) : view === "list" ? (_jsx("div", { className: "flex flex-col divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800", children: events.map((event) => (_jsx(EventCard, { event: event }, event.id))) })) : (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: events.map((event) => (_jsx(EventCard, { event: event }, event.id))) })) }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "flex items-center gap-2 text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close filters", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4", children: _jsx(EventFilters, { table: pendingTable, variant: "public" }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }))] }));
116
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search events...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get(TABLE_KEYS.SORT) || sortBy(EVENT_FIELDS.STARTS_AT, "ASC"), sortOptions: EVENT_PUBLIC_SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, view: view, onViewChange: handleViewToggle, onResetAll: resetAll, hasActiveState: hasActiveState }), 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: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsx("div", { className: "py-6", children: isLoading ? (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: Array.from({ length: 6 }).map((_, i) => (_jsxs("div", { className: "rounded-xl border border-zinc-100 dark:border-slate-700 overflow-hidden animate-pulse", children: [_jsx("div", { className: "aspect-video bg-zinc-200 dark:bg-slate-700" }), _jsxs("div", { className: "p-4 space-y-2", children: [_jsx("div", { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-3/4" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-2/3" }), _jsx("div", { className: "h-8 bg-zinc-200 dark:bg-slate-700 rounded mt-2" })] })] }, i))) })) : events.length === 0 ? (_jsx(Text, { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: "No events found." })) : view === "list" ? (_jsx("div", { className: "flex flex-col divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800", children: events.map((event) => (_jsx(EventCard, { event: event }, event.id))) })) : (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: events.map((event) => (_jsx(EventCard, { event: event }, event.id))) })) }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "flex items-center gap-2 text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close filters", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4", children: _jsx(EventFilters, { table: pendingTable, variant: "public" }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }))] }));
117
117
  }