@mohasinac/appkit 2.7.56 → 2.7.58

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 (364) hide show
  1. package/dist/_internal/client/features/layout/DashboardLayoutClient.d.ts +7 -1
  2. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +8 -2
  3. package/dist/_internal/shared/actions/action-registry.js +31 -5
  4. package/dist/client.d.ts +2 -4
  5. package/dist/client.js +2 -3
  6. package/dist/configs/tailwind.d.ts +16 -3
  7. package/dist/configs/tailwind.js +18 -5
  8. package/dist/constants/field-names.d.ts +3 -0
  9. package/dist/constants/field-names.js +3 -0
  10. package/dist/features/about/components/FAQPageView.js +2 -2
  11. package/dist/features/about/components/FeesView.js +1 -1
  12. package/dist/features/about/components/PolicyPageView.js +1 -1
  13. package/dist/features/about/components/PublicProfileView.js +1 -1
  14. package/dist/features/account/components/AddressBook.js +1 -1
  15. package/dist/features/account/components/AddressesIndexListing.js +1 -1
  16. package/dist/features/account/components/BuyerAccountGuideView.js +7 -7
  17. package/dist/features/account/components/BuyerAuctionsGuideView.js +7 -7
  18. package/dist/features/account/components/BuyerOrdersGuideView.js +6 -6
  19. package/dist/features/account/components/BuyerShoppingGuideView.js +7 -7
  20. package/dist/features/account/components/MessagesView.js +1 -1
  21. package/dist/features/account/components/NotificationPreferencesPanel.js +12 -3
  22. package/dist/features/account/components/UserOffersPanel.js +2 -2
  23. package/dist/features/account/components/UserSidebar.js +3 -3
  24. package/dist/features/account/components/UserSupportView.js +5 -5
  25. package/dist/features/admin/components/AdminAdsView.js +1 -1
  26. package/dist/features/admin/components/AdminAllEventEntriesView.js +2 -2
  27. package/dist/features/admin/components/AdminAnalyticsGuideView.js +3 -3
  28. package/dist/features/admin/components/AdminBidsView.js +6 -2
  29. package/dist/features/admin/components/AdminBlogView.js +7 -2
  30. package/dist/features/admin/components/AdminBrandsView.js +7 -2
  31. package/dist/features/admin/components/AdminBundleEditorView.js +13 -9
  32. package/dist/features/admin/components/AdminBundlesView.js +4 -2
  33. package/dist/features/admin/components/AdminCarouselEditorView.js +7 -8
  34. package/dist/features/admin/components/AdminCarouselView.js +6 -4
  35. package/dist/features/admin/components/AdminCartsView.js +1 -1
  36. package/dist/features/admin/components/AdminCatalogGuideView.js +5 -5
  37. package/dist/features/admin/components/AdminCategoriesView.js +7 -2
  38. package/dist/features/admin/components/AdminContactEditorView.js +2 -2
  39. package/dist/features/admin/components/AdminContactView.js +4 -2
  40. package/dist/features/admin/components/AdminContentGuideView.js +6 -6
  41. package/dist/features/admin/components/AdminCouponsView.js +4 -2
  42. package/dist/features/admin/components/AdminEmployeeEditorView.js +1 -1
  43. package/dist/features/admin/components/AdminFaqsView.js +4 -2
  44. package/dist/features/admin/components/AdminFeatureFlagsView.js +1 -1
  45. package/dist/features/admin/components/AdminFeaturesView.js +5 -1
  46. package/dist/features/admin/components/AdminGuideHubView.js +1 -1
  47. package/dist/features/admin/components/AdminHistoryView.js +1 -1
  48. package/dist/features/admin/components/AdminListingScaffold.js +1 -1
  49. package/dist/features/admin/components/AdminMediaView.js +10 -5
  50. package/dist/features/admin/components/AdminNavigationView.js +1 -1
  51. package/dist/features/admin/components/AdminNewsletterView.js +4 -2
  52. package/dist/features/admin/components/AdminNotificationsView.js +7 -2
  53. package/dist/features/admin/components/AdminOrdersGuideView.js +5 -5
  54. package/dist/features/admin/components/AdminOrdersView.js +11 -2
  55. package/dist/features/admin/components/AdminPayoutsView.js +6 -2
  56. package/dist/features/admin/components/AdminPrizeDrawsView.js +4 -0
  57. package/dist/features/admin/components/AdminProductsView.js +14 -2
  58. package/dist/features/admin/components/AdminReturnRequestsView.js +1 -1
  59. package/dist/features/admin/components/AdminReviewsView.js +7 -2
  60. package/dist/features/admin/components/AdminScammerEditorView.js +3 -3
  61. package/dist/features/admin/components/AdminScammersView.js +5 -5
  62. package/dist/features/admin/components/AdminSectionsView.js +2 -2
  63. package/dist/features/admin/components/AdminSessionsView.js +6 -2
  64. package/dist/features/admin/components/AdminSidebar.js +3 -3
  65. package/dist/features/admin/components/AdminSiteSettingsView.js +1 -1
  66. package/dist/features/admin/components/AdminStoreAddressesView.js +1 -1
  67. package/dist/features/admin/components/AdminStoreEditorView.js +1 -1
  68. package/dist/features/admin/components/AdminStoresGuideView.js +6 -6
  69. package/dist/features/admin/components/AdminStoresView.js +7 -2
  70. package/dist/features/admin/components/AdminSublistingCategoriesView.js +3 -1
  71. package/dist/features/admin/components/AdminSupportTicketDetailView.js +4 -4
  72. package/dist/features/admin/components/AdminSupportTicketsView.js +8 -8
  73. package/dist/features/admin/components/AdminTeamGuideView.js +4 -4
  74. package/dist/features/admin/components/AdminTeamView.js +4 -2
  75. package/dist/features/admin/components/AdminTrustGuideView.js +5 -5
  76. package/dist/features/admin/components/AdminUserEditorView.js +2 -2
  77. package/dist/features/admin/components/AdminUsersGuideView.js +5 -5
  78. package/dist/features/admin/components/AdminUsersView.js +6 -2
  79. package/dist/features/admin/components/AdminViewCards.js +3 -3
  80. package/dist/features/admin/components/AdminWishlistsView.js +1 -1
  81. package/dist/features/admin/components/DataTable.js +1 -1
  82. package/dist/features/admin/constants/filter-tabs.d.ts +9 -0
  83. package/dist/features/admin/constants/filter-tabs.js +3 -0
  84. package/dist/features/auctions/components/AuctionBidsTable.js +1 -1
  85. package/dist/features/auctions/components/AuctionBottomActions.d.ts +7 -0
  86. package/dist/features/auctions/components/AuctionBottomActions.js +24 -0
  87. package/dist/features/auctions/components/AuctionDetailPageView.js +7 -7
  88. package/dist/features/auctions/components/AuctionsListView.js +1 -1
  89. package/dist/features/auctions/components/MarketplaceAuctionCard.js +2 -2
  90. package/dist/features/auctions/components/MarketplaceAuctionGrid.js +1 -1
  91. package/dist/features/auctions/components/PlaceBidFormClient.js +1 -1
  92. package/dist/features/auth/components/LoginForm.js +1 -1
  93. package/dist/features/auth/components/VerifyEmailView.js +2 -2
  94. package/dist/features/before-after/components/BeforeAfterGallery.js +1 -1
  95. package/dist/features/blog/components/BlogFeaturedCard.js +1 -1
  96. package/dist/features/blog/components/BlogIndexListing.js +1 -1
  97. package/dist/features/blog/components/BlogListView.js +2 -2
  98. package/dist/features/blog/components/BlogPostView.js +8 -8
  99. package/dist/features/cart/components/CartDrawer.js +2 -2
  100. package/dist/features/cart/repository/cart.repository.js +11 -4
  101. package/dist/features/cart/schemas/firestore.d.ts +3 -0
  102. package/dist/features/categories/components/BrandDetailPageView.js +1 -1
  103. package/dist/features/categories/components/CategoriesIndexListing.js +1 -1
  104. package/dist/features/categories/components/CategoryDetailPageView.js +39 -3
  105. package/dist/features/categories/components/CategoryDetailTabs.d.ts +4 -1
  106. package/dist/features/categories/components/CategoryDetailTabs.js +7 -2
  107. package/dist/features/categories/components/CategoryGrid.js +1 -1
  108. package/dist/features/categories/components/CategoryProductsView.js +1 -1
  109. package/dist/features/categories/components/CategoryStoresListing.d.ts +5 -0
  110. package/dist/features/categories/components/CategoryStoresListing.js +11 -0
  111. package/dist/features/categories/components/CategoryTableColumns.js +2 -2
  112. package/dist/features/categories/components/CategoryTree.js +1 -1
  113. package/dist/features/categories/components/index.d.ts +2 -0
  114. package/dist/features/categories/components/index.js +1 -0
  115. package/dist/features/checkout/components/CheckoutStepper.js +2 -2
  116. package/dist/features/classified/components/ClassifiedIndexListing.js +2 -0
  117. package/dist/features/classified/components/ClassifiedListView.js +1 -1
  118. package/dist/features/collections/components/CollectionCard.js +1 -1
  119. package/dist/features/contact/components/ContactInfoSidebar.js +1 -1
  120. package/dist/features/copilot/components/AdminCopilotView.js +2 -2
  121. package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +2 -0
  122. package/dist/features/digital-codes/components/DigitalCodesListView.js +1 -1
  123. package/dist/features/events/components/AdminEventsView.js +5 -1
  124. package/dist/features/events/components/EventCard.js +1 -1
  125. package/dist/features/events/components/EventPollWidget.js +3 -3
  126. package/dist/features/events/components/EventStatusBadge.js +5 -5
  127. package/dist/features/events/components/EventsIndexListing.js +1 -1
  128. package/dist/features/events/components/EventsListView.js +2 -2
  129. package/dist/features/events/components/SpinWheelView.js +5 -3
  130. package/dist/features/faq/components/FAQAccordion.js +2 -2
  131. package/dist/features/filters/AsyncFacetSection.js +3 -3
  132. package/dist/features/filters/FilterFacetSection.js +5 -5
  133. package/dist/features/filters/RangeFilter.js +1 -1
  134. package/dist/features/forms/Input.js +5 -5
  135. package/dist/features/forms/Select.js +3 -3
  136. package/dist/features/forms/Slider.js +1 -1
  137. package/dist/features/forms/Textarea.js +3 -3
  138. package/dist/features/forms/utils.d.ts +2 -2
  139. package/dist/features/forms/utils.js +2 -2
  140. package/dist/features/history/hooks/useHistory.js +23 -10
  141. package/dist/features/homepage/components/AdvertisementBanner.js +2 -2
  142. package/dist/features/homepage/components/CharacterHotspotForm.js +2 -2
  143. package/dist/features/homepage/components/FeaturedResultsSection.js +1 -1
  144. package/dist/features/homepage/components/HeroSection.js +1 -1
  145. package/dist/features/homepage/components/NewsletterSection.js +1 -1
  146. package/dist/features/homepage/components/SectionCarousel.js +1 -1
  147. package/dist/features/layout/BottomActions.js +2 -2
  148. package/dist/features/layout/ListingLayout.js +3 -3
  149. package/dist/features/layout/TitleBarLayout.js +1 -1
  150. package/dist/features/live/components/LiveItemsIndexListing.js +2 -0
  151. package/dist/features/live/components/LiveItemsListView.js +1 -1
  152. package/dist/features/media/index.d.ts +2 -0
  153. package/dist/features/media/index.js +1 -0
  154. package/dist/features/media/modals/ImageCropModal.js +1 -1
  155. package/dist/features/media/modals/ImageEditor.d.ts +12 -0
  156. package/dist/features/media/modals/ImageEditor.js +73 -0
  157. package/dist/features/media/upload/ImageUpload.d.ts +5 -1
  158. package/dist/features/media/upload/ImageUpload.js +33 -8
  159. package/dist/features/media/upload/MediaUploadField.d.ts +5 -1
  160. package/dist/features/media/upload/MediaUploadField.js +26 -12
  161. package/dist/features/orders/components/OrdersList.js +12 -12
  162. package/dist/features/orders/components/RefundHistoryTable.js +2 -2
  163. package/dist/features/orders/components/RefundRequestView.js +3 -3
  164. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +1 -1
  165. package/dist/features/pre-orders/components/PreOrderActionsClient.js +1 -1
  166. package/dist/features/pre-orders/components/PreOrderBadge.js +5 -5
  167. package/dist/features/pre-orders/components/PreOrderBottomActions.d.ts +5 -0
  168. package/dist/features/pre-orders/components/PreOrderBottomActions.js +22 -0
  169. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +5 -5
  170. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +47 -0
  171. package/dist/features/pre-orders/components/PreOrdersListView.js +1 -1
  172. package/dist/features/pre-orders/components/PreorderCard.js +3 -3
  173. package/dist/features/products/components/AuctionsIndexListing.js +23 -0
  174. package/dist/features/products/components/BidHistory.js +2 -2
  175. package/dist/features/products/components/CompareOverlay.js +1 -1
  176. package/dist/features/products/components/CustomFieldsEditor.js +1 -1
  177. package/dist/features/products/components/CustomSectionTabContent.js +1 -1
  178. package/dist/features/products/components/CustomSectionsEditor.js +1 -1
  179. package/dist/features/products/components/GroupSettingsPanel.js +2 -2
  180. package/dist/features/products/components/MakeOfferButton.js +2 -2
  181. package/dist/features/products/components/PrizeDrawBottomActions.d.ts +6 -0
  182. package/dist/features/products/components/PrizeDrawBottomActions.js +24 -0
  183. package/dist/features/products/components/PrizeDrawDetailPageView.js +5 -7
  184. package/dist/features/products/components/PrizeDrawEntryActions.js +5 -18
  185. package/dist/features/products/components/PrizeDrawItemsEditor.js +3 -3
  186. package/dist/features/products/components/PrizeRevealModal.js +7 -4
  187. package/dist/features/products/components/ProductDetailActions.d.ts +6 -1
  188. package/dist/features/products/components/ProductDetailActions.js +36 -6
  189. package/dist/features/products/components/ProductDetailPageView.js +19 -18
  190. package/dist/features/products/components/ProductFeaturesSelector.js +1 -1
  191. package/dist/features/products/components/ProductGalleryClient.js +1 -1
  192. package/dist/features/products/components/ProductGrid.js +8 -8
  193. package/dist/features/products/components/ProductTabs.js +1 -1
  194. package/dist/features/products/components/ProductTabsShell.js +1 -1
  195. package/dist/features/products/components/ProductsIndexListing.js +47 -0
  196. package/dist/features/products/components/RelatedProducts.js +1 -1
  197. package/dist/features/products/components/ShowGroupSection.js +1 -1
  198. package/dist/features/products/components/SublistingCarouselSection.js +1 -1
  199. package/dist/features/products/components/SublistingCategorySelect.js +1 -1
  200. package/dist/features/products/components/index.d.ts +0 -2
  201. package/dist/features/products/components/index.js +0 -1
  202. package/dist/features/products/constants/action-defs.d.ts +7 -0
  203. package/dist/features/products/constants/action-defs.js +14 -0
  204. package/dist/features/products/constants/listing-tabs.d.ts +6 -0
  205. package/dist/features/products/constants/listing-tabs.js +1 -0
  206. package/dist/features/promotions/components/CouponCard.js +3 -3
  207. package/dist/features/promotions/components/CouponsIndexListing.js +2 -2
  208. package/dist/features/promotions/components/PromotionsView.js +1 -1
  209. package/dist/features/reviews/components/ReviewDetailPageView.js +1 -1
  210. package/dist/features/reviews/components/ReviewDetailShell.js +4 -4
  211. package/dist/features/reviews/components/ReviewModal.js +2 -2
  212. package/dist/features/reviews/components/ReviewSummary.js +1 -1
  213. package/dist/features/reviews/components/ReviewsIndexListing.js +1 -1
  214. package/dist/features/reviews/components/ReviewsList.js +1 -1
  215. package/dist/features/seller/components/SellerAddressesView.js +4 -3
  216. package/dist/features/seller/components/SellerAnalyticsAlertsView.js +2 -2
  217. package/dist/features/seller/components/SellerAuctionsView.js +11 -4
  218. package/dist/features/seller/components/SellerBidsView.js +22 -7
  219. package/dist/features/seller/components/SellerBundlesView.js +11 -4
  220. package/dist/features/seller/components/SellerClassifiedView.js +12 -5
  221. package/dist/features/seller/components/SellerCouponEditorView.js +2 -2
  222. package/dist/features/seller/components/SellerCouponsView.js +13 -4
  223. package/dist/features/seller/components/SellerDigitalCodesView.js +11 -4
  224. package/dist/features/seller/components/SellerFeaturesView.js +1 -1
  225. package/dist/features/seller/components/SellerGoogleReviewsView.js +10 -5
  226. package/dist/features/seller/components/SellerGroupedListingsView.js +2 -0
  227. package/dist/features/seller/components/SellerLiveView.js +13 -6
  228. package/dist/features/seller/components/SellerOffersPanel.js +2 -2
  229. package/dist/features/seller/components/SellerOffersView.js +2 -2
  230. package/dist/features/seller/components/SellerOrdersView.js +41 -18
  231. package/dist/features/seller/components/SellerPayoutMethodsView.js +14 -5
  232. package/dist/features/seller/components/SellerPayoutsView.js +2 -2
  233. package/dist/features/seller/components/SellerPreOrdersView.js +7 -2
  234. package/dist/features/seller/components/SellerPrizeDrawsView.js +7 -2
  235. package/dist/features/seller/components/SellerProductShell.js +27 -9
  236. package/dist/features/seller/components/SellerProductsCards.js +2 -1
  237. package/dist/features/seller/components/SellerProductsView.js +22 -9
  238. package/dist/features/seller/components/SellerReviewsView.js +9 -1
  239. package/dist/features/seller/components/SellerShippingConfigsView.js +15 -6
  240. package/dist/features/seller/components/SellerSidebar.js +2 -2
  241. package/dist/features/seller/components/SellerStoreCategoriesView.js +11 -4
  242. package/dist/features/seller/components/SellerTemplatesView.js +20 -7
  243. package/dist/features/seller/components/analytics/SellerTopProducts.js +1 -1
  244. package/dist/features/shell/StepForm.js +9 -3
  245. package/dist/features/site-settings/components/ActionPermissionsManager.js +1 -1
  246. package/dist/features/site-settings/components/NavPermissionsManager.js +1 -1
  247. package/dist/features/stores/components/InteractiveStoreCard.js +1 -1
  248. package/dist/features/stores/components/StoreDetailLayoutView.js +1 -1
  249. package/dist/features/stores/components/StoreFinanceGuideView.js +2 -2
  250. package/dist/features/stores/components/StoreHeader.js +1 -1
  251. package/dist/features/stores/components/StoreListingsGuideView.js +3 -3
  252. package/dist/features/stores/components/StoreOrdersGuideView.js +4 -4
  253. package/dist/features/stores/components/StoreReviewsListing.js +1 -1
  254. package/dist/features/stores/components/StoreSettingsGuideView.js +2 -2
  255. package/dist/features/stores/components/StoresIndexListing.js +17 -1
  256. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +4 -4
  257. package/dist/features/wishlist/components/WishlistPage.js +3 -3
  258. package/dist/features/wishlist/hooks/useWishlistToggle.js +6 -1
  259. package/dist/index.d.ts +5 -2
  260. package/dist/index.js +9 -3
  261. package/dist/react/hooks/use-action-dispatch.d.ts +5 -0
  262. package/dist/react/hooks/use-action-dispatch.js +10 -0
  263. package/dist/seed/cart-seed-data.js +50 -3
  264. package/dist/seed/categories-seed-data.js +80 -16
  265. package/dist/seed/index.d.ts +3 -0
  266. package/dist/seed/index.js +3 -0
  267. package/dist/seed/manifest.js +15 -1
  268. package/dist/seed/products-classifieds-seed-data.d.ts +10 -0
  269. package/dist/seed/products-classifieds-seed-data.js +197 -0
  270. package/dist/seed/products-digital-codes-seed-data.d.ts +10 -0
  271. package/dist/seed/products-digital-codes-seed-data.js +204 -0
  272. package/dist/seed/products-live-items-seed-data.d.ts +13 -0
  273. package/dist/seed/products-live-items-seed-data.js +190 -0
  274. package/dist/styles.css +301 -3
  275. package/dist/tailwind-utilities.css +1 -1
  276. package/dist/tokens/index.d.ts +3 -3
  277. package/dist/tokens/index.js +3 -3
  278. package/dist/tokens/motion.d.ts +162 -0
  279. package/dist/tokens/motion.js +89 -0
  280. package/dist/ui/DataTable.js +6 -5
  281. package/dist/ui/components/Accordion.js +2 -1
  282. package/dist/ui/components/Button.style.css +15 -0
  283. package/dist/ui/components/Card.d.ts +5 -2
  284. package/dist/ui/components/Card.js +29 -11
  285. package/dist/ui/components/Div.d.ts +2 -16
  286. package/dist/ui/components/Div.js +2 -16
  287. package/dist/ui/components/Input.js +1 -1
  288. package/dist/ui/components/Layout.d.ts +9 -19
  289. package/dist/ui/components/Layout.js +9 -7
  290. package/dist/ui/components/ListingToolbar.js +1 -1
  291. package/dist/ui/components/Modal.js +7 -4
  292. package/dist/ui/components/Motion.d.ts +75 -0
  293. package/dist/ui/components/Motion.js +122 -0
  294. package/dist/ui/components/Select.js +1 -1
  295. package/dist/ui/components/Semantic.d.ts +81 -14
  296. package/dist/ui/components/Semantic.js +75 -10
  297. package/dist/ui/components/Semantic.style.css +261 -2
  298. package/dist/ui/components/SideDrawer.d.ts +1 -1
  299. package/dist/ui/components/SideDrawer.js +8 -6
  300. package/dist/ui/components/SideModal.d.ts +1 -1
  301. package/dist/ui/components/SideModal.js +11 -9
  302. package/dist/ui/components/StackedViewShell.js +6 -1
  303. package/dist/ui/components/StatsGrid.js +1 -1
  304. package/dist/ui/components/Toast.js +5 -2
  305. package/dist/ui/components/Typography.d.ts +44 -3
  306. package/dist/ui/components/Typography.js +15 -30
  307. package/dist/ui/components/Typography.style.css +24 -0
  308. package/dist/ui/components/VacationBanner.js +2 -1
  309. package/dist/ui/components/surface-tokens.d.ts +70 -0
  310. package/dist/ui/components/surface-tokens.js +68 -0
  311. package/dist/ui/forms/FormShell.d.ts +6 -1
  312. package/dist/ui/forms/FormShell.js +32 -4
  313. package/dist/ui/index.d.ts +9 -6
  314. package/dist/ui/index.js +4 -4
  315. package/dist/validation/schemas.d.ts +28 -28
  316. package/package.json +3 -1
  317. package/dist/_internal/client/features/seller/print-center/InventoryLabel.d.ts +0 -12
  318. package/dist/_internal/client/features/seller/print-center/InventoryLabel.js +0 -49
  319. package/dist/_internal/client/features/seller/print-center/LabelDesignPicker.d.ts +0 -7
  320. package/dist/_internal/client/features/seller/print-center/LabelDesignPicker.js +0 -32
  321. package/dist/_internal/client/features/seller/print-center/OrderPackingLabel.d.ts +0 -28
  322. package/dist/_internal/client/features/seller/print-center/OrderPackingLabel.js +0 -33
  323. package/dist/_internal/client/features/seller/print-center/PhysicalLocationModal.d.ts +0 -12
  324. package/dist/_internal/client/features/seller/print-center/PhysicalLocationModal.js +0 -30
  325. package/dist/_internal/client/features/seller/print-center/PrintCenterView.d.ts +0 -12
  326. package/dist/_internal/client/features/seller/print-center/PrintCenterView.js +0 -102
  327. package/dist/_internal/client/features/seller/print-center/PrintGrid.d.ts +0 -12
  328. package/dist/_internal/client/features/seller/print-center/PrintGrid.js +0 -13
  329. package/dist/_internal/client/features/seller/print-center/StoreCard.d.ts +0 -19
  330. package/dist/_internal/client/features/seller/print-center/StoreCard.js +0 -30
  331. package/dist/_internal/client/features/seller/print-center/WebsiteCard.d.ts +0 -11
  332. package/dist/_internal/client/features/seller/print-center/WebsiteCard.js +0 -25
  333. package/dist/_internal/client/features/seller/print-center/index.d.ts +0 -11
  334. package/dist/_internal/client/features/seller/print-center/index.js +0 -10
  335. package/dist/_internal/client/features/seller/print-center/types.d.ts +0 -20
  336. package/dist/_internal/client/features/seller/print-center/types.js +0 -20
  337. package/dist/_internal/client/features/seller/print-center/useInventoryPdf.d.ts +0 -18
  338. package/dist/_internal/client/features/seller/print-center/useInventoryPdf.js +0 -76
  339. package/dist/features/account/repository/address.repository.d.ts +0 -17
  340. package/dist/features/account/repository/address.repository.js +0 -184
  341. package/dist/features/auctions/components/AuctionCard.d.ts +0 -29
  342. package/dist/features/auctions/components/AuctionCard.js +0 -38
  343. package/dist/features/categories/components/BundleAddToCartCta.d.ts +0 -16
  344. package/dist/features/categories/components/BundleAddToCartCta.js +0 -54
  345. package/dist/features/categories/components/CategoriesListView.d.ts +0 -31
  346. package/dist/features/categories/components/CategoriesListView.js +0 -27
  347. package/dist/features/products/components/AuctionsView.d.ts +0 -6
  348. package/dist/features/products/components/AuctionsView.js +0 -5
  349. package/dist/features/products/components/BuyBar.d.ts +0 -21
  350. package/dist/features/products/components/BuyBar.js +0 -19
  351. package/dist/features/products/components/PreOrdersView.d.ts +0 -6
  352. package/dist/features/products/components/PreOrdersView.js +0 -5
  353. package/dist/features/reviews/components/ReviewsListView.d.ts +0 -31
  354. package/dist/features/reviews/components/ReviewsListView.js +0 -16
  355. package/dist/features/stores/components/StoresListView.d.ts +0 -19
  356. package/dist/features/stores/components/StoresListView.js +0 -25
  357. package/dist/features/stores/repository/store-address.repository.d.ts +0 -55
  358. package/dist/features/stores/repository/store-address.repository.js +0 -187
  359. package/dist/ui/components/BulkActionsBar.d.ts +0 -18
  360. package/dist/ui/components/BulkActionsBar.js +0 -25
  361. package/dist/ui/components/CollageLightbox.d.ts +0 -18
  362. package/dist/ui/components/CollageLightbox.js +0 -41
  363. package/dist/ui/components/StickyBottomBar.d.ts +0 -22
  364. package/dist/ui/components/StickyBottomBar.js +0 -20
@@ -10,6 +10,7 @@ import { toRecordArray, toRelativeDate, toStringValue, useAdminListingData, } fr
10
10
  import { DataTable } from "./DataTable";
11
11
  import { BUNDLE_COPY, BUNDLE_STOCK_VARIANT, } from "../../../_internal/shared/features/categories/bundle-copy";
12
12
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
13
+ import { useBottomActions } from "../../layout";
13
14
  const PAGE_SIZE = 25;
14
15
  const FILTER_KEYS = ["isActive", "bundleStockStatus"];
15
16
  const DEFAULT_SORT = "name";
@@ -53,7 +54,7 @@ const COLUMNS = [
53
54
  function BundlesFilterDrawer({ filterOpen, setFilterOpen, activeFilterCount, clearFilters, pendingFilters, setPendingFilters, applyFilters, }) {
54
55
  if (!filterOpen)
55
56
  return null;
56
- return (_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: [_jsxs("div", { className: "space-y-2", children: [_jsx(Text, { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Status" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [
57
+ return (_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 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-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: [_jsxs("div", { className: "space-y-2", children: [_jsx(Text, { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Status" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [
57
58
  { label: "All", value: "" },
58
59
  { label: "Active", value: "true" },
59
60
  { label: "Inactive", value: "false" },
@@ -189,9 +190,10 @@ export function AdminBundlesView({ getEditHref, newHref }) {
189
190
  },
190
191
  },
191
192
  ];
193
+ useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: bulkActions } } : {});
192
194
  return (_jsxs("div", { className: "min-h-screen", children: [_jsx(Heading, { level: 1, className: "sr-only", children: "Bundles" }), _jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search bundles by name or slug\u2026", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => {
193
195
  table.set("sort", v);
194
- }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsx(Button, { asChild: true, size: "sm", variant: "primary", children: _jsxs("a", { href: newHref, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), BUNDLE_COPY.adminList.newButton] }) }) }), _jsx(BulkActionBar, { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: bulkActions }), 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 })), _jsx(DataTable, { columns: COLUMNS, rows: rows, isLoading: isLoading, emptyLabel: BUNDLE_COPY.adminList.empty, getRowHref: getEditHref, selectedIds: selection.selectedIdSet, onToggleSelect: selection.toggle, onToggleSelectAll: (next) => next
196
+ }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsx(Button, { asChild: true, size: "sm", variant: "primary", children: _jsxs("a", { href: newHref, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), BUNDLE_COPY.adminList.newButton] }) }) }), _jsx(BulkActionBar, { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: bulkActions }), 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-error-surface px-4 py-3 text-sm text-error dark:border-red-900/60", children: errorMessage })), _jsx(DataTable, { columns: COLUMNS, rows: rows, isLoading: isLoading, emptyLabel: BUNDLE_COPY.adminList.empty, getRowHref: getEditHref, selectedIds: selection.selectedIdSet, onToggleSelect: selection.toggle, onToggleSelectAll: (next) => next
195
197
  ? selection.setSelectedIds(rows.map((r) => r.id))
196
198
  : selection.clearSelection(), renderRowActions: (row) => (_jsx(Button, { variant: "ghost", size: "sm", isLoading: rebuildingId === row.id, disabled: rebuildingId === row.id, onClick: () => void handleRebuild(row.id), children: ACTIONS.ADMIN["rebuild-bundle"].label })) })] }), _jsx(BundlesFilterDrawer, { filterOpen: filterOpen, setFilterOpen: setFilterOpen, activeFilterCount: activeFilterCount, clearFilters: clearFilters, pendingFilters: pendingFilters, setPendingFilters: setPendingFilters, applyFilters: applyFilters })] }));
197
199
  }
@@ -2,10 +2,11 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import React from "react";
4
4
  import { useMutation, useQuery } from "@tanstack/react-query";
5
- import { Alert, Button, Form, FormActions, Input, Select, StackedViewShell, Toggle, Div, Text, Heading, Row, } from "../../../ui";
5
+ import { Alert, Button, ConfirmDeleteModal, Form, FormActions, Input, Select, StackedViewShell, Toggle, Div, Text, Heading, Row, } from "../../../ui";
6
6
  import { FieldInput, FormShellContext, useFormShellState } from "../../../ui/forms";
7
7
  import { apiClient } from "../../../http";
8
8
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
9
+ import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
9
10
  const CLS_PANEL = "rounded-xl border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-900 p-4 space-y-3";
10
11
  const CLS_ROW_BETWEEN = "flex items-center justify-between";
11
12
  const CLS_SECTION_HEADING = "text-sm font-semibold text-zinc-900 dark:text-zinc-100";
@@ -55,7 +56,7 @@ const TEXT_ALIGN_OPTIONS = [
55
56
  // ── Zone Picker ──────────────────────────────────────────────────────────────
56
57
  function ZonePicker({ selected, onChange, disabled, }) {
57
58
  const zones = [1, 2, 3, 4, 5, 6];
58
- return (_jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-zinc-500 mb-1", children: "Zone (row \u00D7 col grid)" }), _jsx("div", { className: "grid gap-1", style: { gridTemplateRows: "repeat(2, 1fr)", gridTemplateColumns: "repeat(3, 1fr)", width: 150 }, children: zones.map((z) => {
59
+ return (_jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400 mb-1", children: "Zone (row \u00D7 col grid)" }), _jsx("div", { className: "grid gap-1", style: { gridTemplateRows: "repeat(2, 1fr)", gridTemplateColumns: "repeat(3, 1fr)", width: 150 }, children: zones.map((z) => {
59
60
  const isDisabled = disabled?.(z) ?? false;
60
61
  return (_jsx("button", { type: "button", disabled: isDisabled, onClick: () => !isDisabled && onChange(z), className: `rounded text-xs font-mono py-2 border transition-colors ${selected === z
61
62
  ? "bg-primary text-white border-primary"
@@ -79,7 +80,7 @@ function CardEditor({ card, index, otherZones, onChange, onRemove, }) {
79
80
  { value: "", label: "— inherit desktop zone —" },
80
81
  { value: "2", label: "Zone 2 (row 1, center)" },
81
82
  { value: "5", label: "Zone 5 (row 2, center)" },
82
- ] }), _jsxs(Div, { children: [_jsx(Text, { className: "text-sm font-medium mb-2", children: "Background" }), _jsx(BackgroundEditor, { value: card.background, onChange: (bg) => set({ background: bg }), prefix: `card-${index}` })] }), _jsxs(Div, { className: "space-y-2", children: [_jsx(Text, { className: "text-sm font-medium", children: "Content" }), _jsx(Input, { label: "Eyebrow", value: card.content?.eyebrow ?? "", onChange: (e) => setContent({ eyebrow: e.target.value || undefined }), placeholder: "New \u00B7 Limited \u00B7 Featured" }), _jsx(Input, { label: "Title", value: card.content?.title ?? "", onChange: (e) => setContent({ title: e.target.value }) }), _jsx(Input, { label: "Subtitle", value: card.content?.subtitle ?? "", onChange: (e) => setContent({ subtitle: e.target.value || undefined }) }), _jsx(Input, { label: "Description", value: card.content?.description ?? "", onChange: (e) => setContent({ description: e.target.value || undefined }) }), _jsx(Input, { label: "Text colour (CSS)", value: card.content?.textColor ?? "#ffffff", onChange: (e) => setContent({ textColor: e.target.value }) }), _jsx(Select, { label: "Text align", value: card.content?.textAlign ?? "left", onChange: (e) => setContent({ textAlign: e.target.value }), options: TEXT_ALIGN_OPTIONS })] }), _jsxs(Div, { className: "space-y-2", children: [_jsxs(Row, { className: CLS_ROW_BETWEEN, children: [_jsx(Text, { className: "text-sm font-medium", children: "Buttons (max 3)" }), buttons.length < 3 && (_jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => set({ buttons: [...buttons, makeButton()] }), children: "+ Add button" }))] }), buttons.map((btn, bi) => (_jsxs(Div, { className: "rounded-lg border border-zinc-200 dark:border-zinc-800 p-3 space-y-2", children: [_jsxs(Row, { className: CLS_ROW_BETWEEN, children: [_jsxs(Text, { className: "text-xs font-medium text-zinc-500", children: ["Button ", bi + 1] }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => set({ buttons: buttons.filter((_, i) => i !== bi) }), children: "\u2715" })] }), _jsx(Input, { label: "Label", value: btn.text, onChange: (e) => { const next = [...buttons]; next[bi] = { ...btn, text: e.target.value }; set({ buttons: next }); } }), _jsx(Input, { label: "Link (href)", value: btn.href, onChange: (e) => { const next = [...buttons]; next[bi] = { ...btn, href: e.target.value }; set({ buttons: next }); }, placeholder: "/products or https://..." }), _jsx(Select, { label: "Variant", value: btn.variant, onChange: (e) => { const next = [...buttons]; next[bi] = { ...btn, variant: e.target.value }; set({ buttons: next }); }, options: VARIANT_OPTIONS }), _jsx(Toggle, { label: "Open in new tab", checked: btn.openInNewTab ?? false, onChange: (v) => { const next = [...buttons]; next[bi] = { ...btn, openInNewTab: v }; set({ buttons: next }); } })] }, btn.id ?? bi)))] }), _jsxs(Div, { className: "space-y-2", children: [_jsx(Text, { className: "text-sm font-medium", children: "Hover effect" }), _jsx(Select, { label: "Effect", value: card.hover?.effect ?? "none", onChange: (e) => set({ hover: { effect: e.target.value } }), options: HOVER_OPTIONS })] }), _jsx(Toggle, { label: "Button-only card (no text content)", checked: card.isButtonOnly ?? false, onChange: (v) => set({ isButtonOnly: v }) })] }));
83
+ ] }), _jsxs(Div, { children: [_jsx(Text, { className: "text-sm font-medium mb-2", children: "Background" }), _jsx(BackgroundEditor, { value: card.background, onChange: (bg) => set({ background: bg }), prefix: `card-${index}` })] }), _jsxs(Div, { className: "space-y-2", children: [_jsx(Text, { className: "text-sm font-medium", children: "Content" }), _jsx(Input, { label: "Eyebrow", value: card.content?.eyebrow ?? "", onChange: (e) => setContent({ eyebrow: e.target.value || undefined }), placeholder: "New \u00B7 Limited \u00B7 Featured" }), _jsx(Input, { label: "Title", value: card.content?.title ?? "", onChange: (e) => setContent({ title: e.target.value }) }), _jsx(Input, { label: "Subtitle", value: card.content?.subtitle ?? "", onChange: (e) => setContent({ subtitle: e.target.value || undefined }) }), _jsx(Input, { label: "Description", value: card.content?.description ?? "", onChange: (e) => setContent({ description: e.target.value || undefined }) }), _jsx(Input, { label: "Text colour (CSS)", value: card.content?.textColor ?? "#ffffff", onChange: (e) => setContent({ textColor: e.target.value }) }), _jsx(Select, { label: "Text align", value: card.content?.textAlign ?? "left", onChange: (e) => setContent({ textAlign: e.target.value }), options: TEXT_ALIGN_OPTIONS })] }), _jsxs(Div, { className: "space-y-2", children: [_jsxs(Row, { className: CLS_ROW_BETWEEN, children: [_jsx(Text, { className: "text-sm font-medium", children: "Buttons (max 3)" }), buttons.length < 3 && (_jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => set({ buttons: [...buttons, makeButton()] }), children: "+ Add button" }))] }), buttons.map((btn, bi) => (_jsxs(Div, { className: "rounded-lg border border-zinc-200 dark:border-zinc-800 p-3 space-y-2", children: [_jsxs(Row, { className: CLS_ROW_BETWEEN, children: [_jsxs(Text, { className: "text-xs font-medium text-zinc-500 dark:text-zinc-400", children: ["Button ", bi + 1] }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => set({ buttons: buttons.filter((_, i) => i !== bi) }), children: "\u2715" })] }), _jsx(Input, { label: "Label", value: btn.text, onChange: (e) => { const next = [...buttons]; next[bi] = { ...btn, text: e.target.value }; set({ buttons: next }); } }), _jsx(Input, { label: "Link (href)", value: btn.href, onChange: (e) => { const next = [...buttons]; next[bi] = { ...btn, href: e.target.value }; set({ buttons: next }); }, placeholder: "/products or https://..." }), _jsx(Select, { label: "Variant", value: btn.variant, onChange: (e) => { const next = [...buttons]; next[bi] = { ...btn, variant: e.target.value }; set({ buttons: next }); }, options: VARIANT_OPTIONS }), _jsx(Toggle, { label: "Open in new tab", checked: btn.openInNewTab ?? false, onChange: (v) => { const next = [...buttons]; next[bi] = { ...btn, openInNewTab: v }; set({ buttons: next }); } })] }, btn.id ?? bi)))] }), _jsxs(Div, { className: "space-y-2", children: [_jsx(Text, { className: "text-sm font-medium", children: "Hover effect" }), _jsx(Select, { label: "Effect", value: card.hover?.effect ?? "none", onChange: (e) => set({ hover: { effect: e.target.value } }), options: HOVER_OPTIONS })] }), _jsx(Toggle, { label: "Button-only card (no text content)", checked: card.isButtonOnly ?? false, onChange: (v) => set({ isButtonOnly: v }) })] }));
83
84
  }
84
85
  // ── Main Editor ──────────────────────────────────────────────────────────────
85
86
  export function AdminCarouselEditorView({ slideId, onSaved, onDeleted, onCancel, ...rest }) {
@@ -104,6 +105,7 @@ export function AdminCarouselEditorView({ slideId, onSaved, onDeleted, onCancel,
104
105
  const [overlayBtnNewTab, setOverlayBtnNewTab] = React.useState(false);
105
106
  const [errorMsg, setErrorMsg] = React.useState("");
106
107
  const [successMsg, setSuccessMsg] = React.useState("");
108
+ const [deleteConfirmOpen, setDeleteConfirmOpen] = React.useState(false);
107
109
  const { shellCtx, setFieldError, clearErrors } = useFormShellState();
108
110
  const slideQuery = useQuery({
109
111
  queryKey: ["admin", "carousel", slideId],
@@ -205,13 +207,10 @@ export function AdminCarouselEditorView({ slideId, onSaved, onDeleted, onCancel,
205
207
  return;
206
208
  }
207
209
  saveMutation.mutate();
208
- }, className: "space-y-6", children: [_jsxs(Div, { className: CLS_PANEL, children: [_jsx(Heading, { level: 3, className: CLS_SECTION_HEADING, children: "Slide info" }), _jsx(FieldInput, { name: "title", label: "Title", value: title, onChange: (v) => setTitle(v), required: true, placeholder: "e.g. Hot Wheels RLC Exclusives" }), _jsx(Toggle, { label: "Active (visible on homepage)", checked: active, onChange: setActive }), _jsx(Input, { label: "Display order", type: "number", value: order, onChange: (e) => setOrder(e.target.value), min: 0, placeholder: "1" }), _jsx(Select, { label: "Slide height", value: height, onChange: (e) => setHeight(e.target.value), options: HEIGHT_OPTIONS }), _jsx(Input, { label: "Autoplay delay (ms)", type: "number", value: autoplayDelayMs, onChange: (e) => setAutoplayDelayMs(e.target.value), min: 1000, max: 15000, placeholder: "4000", helperText: "How long this slide shows before auto-advancing. Default: 4000 ms." })] }), _jsxs(Div, { className: CLS_PANEL, children: [_jsx(Heading, { level: 3, className: CLS_SECTION_HEADING, children: "Background" }), _jsx(BackgroundEditor, { value: background, onChange: setBackground, prefix: "slide" })] }), _jsxs(Div, { className: CLS_PANEL, children: [_jsx(Heading, { level: 3, className: CLS_SECTION_HEADING, children: "Overlay text (optional)" }), _jsx(Text, { className: "text-sm text-zinc-500", children: "Centred text layered over the background. Leave blank to use cards only." }), _jsx(Input, { label: "Heading", value: overlayTitle, onChange: (e) => setOverlayTitle(e.target.value), placeholder: "India's #1 Collectibles Marketplace" }), _jsx(Input, { label: "Subtitle", value: overlaySubtitle, onChange: (e) => setOverlaySubtitle(e.target.value), placeholder: "Pok\u00E9mon TCG \u00B7 Hot Wheels \u00B7 Beyblade X" }), _jsx(Input, { label: "Description", value: overlayDesc, onChange: (e) => setOverlayDesc(e.target.value), placeholder: "One sentence description..." }), _jsxs(Div, { className: "rounded-lg border border-zinc-200 dark:border-zinc-800 p-3 space-y-2", children: [_jsx(Text, { className: "text-sm font-medium", children: "CTA button" }), _jsx(Input, { label: "Button text", value: overlayBtnText, onChange: (e) => setOverlayBtnText(e.target.value), placeholder: "Shop Now" }), _jsx(Input, { label: "Button link", value: overlayBtnLink, onChange: (e) => setOverlayBtnLink(e.target.value), placeholder: "/products" }), _jsx(Select, { label: "Variant", value: overlayBtnVariant, onChange: (e) => setOverlayBtnVariant(e.target.value), options: VARIANT_OPTIONS.filter((v) => ["primary", "secondary", "outline"].includes(v.value)) }), _jsx(Toggle, { label: "Open in new tab", checked: overlayBtnNewTab, onChange: setOverlayBtnNewTab })] })] }), _jsxs(Div, { className: CLS_PANEL, children: [_jsxs(Row, { className: CLS_ROW_BETWEEN, children: [_jsx(Heading, { level: 3, className: CLS_SECTION_HEADING, children: "Cards (0\u20132)" }), cards.length < 2 && (_jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => {
210
+ }, className: "space-y-6", children: [_jsxs(Div, { className: CLS_PANEL, children: [_jsx(Heading, { level: 3, className: CLS_SECTION_HEADING, children: "Slide info" }), _jsx(FieldInput, { name: "title", label: "Title", value: title, onChange: (v) => setTitle(v), required: true, placeholder: "e.g. Hot Wheels RLC Exclusives" }), _jsx(Toggle, { label: "Active (visible on homepage)", checked: active, onChange: setActive }), _jsx(Input, { label: "Display order", type: "number", value: order, onChange: (e) => setOrder(e.target.value), min: 0, placeholder: "1" }), _jsx(Select, { label: "Slide height", value: height, onChange: (e) => setHeight(e.target.value), options: HEIGHT_OPTIONS }), _jsx(Input, { label: "Autoplay delay (ms)", type: "number", value: autoplayDelayMs, onChange: (e) => setAutoplayDelayMs(e.target.value), min: 1000, max: 15000, placeholder: "4000", helperText: "How long this slide shows before auto-advancing. Default: 4000 ms." })] }), _jsxs(Div, { className: CLS_PANEL, children: [_jsx(Heading, { level: 3, className: CLS_SECTION_HEADING, children: "Background" }), _jsx(BackgroundEditor, { value: background, onChange: setBackground, prefix: "slide" })] }), _jsxs(Div, { className: CLS_PANEL, children: [_jsx(Heading, { level: 3, className: CLS_SECTION_HEADING, children: "Overlay text (optional)" }), _jsx(Text, { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "Centred text layered over the background. Leave blank to use cards only." }), _jsx(Input, { label: "Heading", value: overlayTitle, onChange: (e) => setOverlayTitle(e.target.value), placeholder: "India's #1 Collectibles Marketplace" }), _jsx(Input, { label: "Subtitle", value: overlaySubtitle, onChange: (e) => setOverlaySubtitle(e.target.value), placeholder: "Pok\u00E9mon TCG \u00B7 Hot Wheels \u00B7 Beyblade X" }), _jsx(Input, { label: "Description", value: overlayDesc, onChange: (e) => setOverlayDesc(e.target.value), placeholder: "One sentence description..." }), _jsxs(Div, { className: "rounded-lg border border-zinc-200 dark:border-zinc-800 p-3 space-y-2", children: [_jsx(Text, { className: "text-sm font-medium", children: "CTA button" }), _jsx(Input, { label: "Button text", value: overlayBtnText, onChange: (e) => setOverlayBtnText(e.target.value), placeholder: "Shop Now" }), _jsx(Input, { label: "Button link", value: overlayBtnLink, onChange: (e) => setOverlayBtnLink(e.target.value), placeholder: "/products" }), _jsx(Select, { label: "Variant", value: overlayBtnVariant, onChange: (e) => setOverlayBtnVariant(e.target.value), options: VARIANT_OPTIONS.filter((v) => ["primary", "secondary", "outline"].includes(v.value)) }), _jsx(Toggle, { label: "Open in new tab", checked: overlayBtnNewTab, onChange: setOverlayBtnNewTab })] })] }), _jsxs(Div, { className: CLS_PANEL, children: [_jsxs(Row, { className: CLS_ROW_BETWEEN, children: [_jsx(Heading, { level: 3, className: CLS_SECTION_HEADING, children: "Cards (0\u20132)" }), cards.length < 2 && (_jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => {
209
211
  const usedZones = cards.map((c) => c.zone);
210
212
  const freeZone = [1, 2, 3, 4, 5, 6].find((z) => !usedZones.includes(z)) ?? 1;
211
213
  setCards([...cards, makeCard(freeZone)]);
212
- }, children: "+ Add card" }))] }), cards.length === 0 && (_jsx(Text, { className: "text-sm text-zinc-400", children: "No cards \u2014 the overlay text covers the whole slide." })), cards.map((card, i) => (_jsx(CardEditor, { card: card, index: i, otherZones: occupiedZones.filter((z) => z !== card.zone), onChange: (updated) => setCards(cards.map((c, ci) => (ci === i ? updated : c))), onRemove: () => setCards(cards.filter((_, ci) => ci !== i)) }, card.id)))] }), _jsxs(FormActions, { children: [_jsx(Button, { type: "submit", isLoading: saveMutation.isPending, disabled: !title || saveMutation.isPending, children: isEdit ? "Save changes" : "Create slide" }), onCancel && (_jsx(Button, { type: "button", variant: "outline", onClick: onCancel, children: "Cancel" })), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => {
213
- if (confirm("Delete this slide? This cannot be undone."))
214
- deleteMutation.mutate();
215
- }, children: "Delete slide" }))] })] }, "slide-form") }),
214
+ }, children: "+ Add card" }))] }), cards.length === 0 && (_jsx(Text, { className: "text-sm text-zinc-400", children: "No cards \u2014 the overlay text covers the whole slide." })), cards.map((card, i) => (_jsx(CardEditor, { card: card, index: i, otherZones: occupiedZones.filter((z) => z !== card.zone), onChange: (updated) => setCards(cards.map((c, ci) => (ci === i ? updated : c))), onRemove: () => setCards(cards.filter((_, ci) => ci !== i)) }, card.id)))] }), _jsxs(FormActions, { children: [_jsx(Button, { type: "submit", isLoading: saveMutation.isPending, disabled: !title || saveMutation.isPending, children: isEdit ? "Save changes" : "Create slide" }), onCancel && (_jsx(Button, { type: "button", variant: "outline", onClick: onCancel, children: "Cancel" })), isEdit && (_jsxs(_Fragment, { children: [_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => setDeleteConfirmOpen(true), children: ACTIONS.ADMIN["delete-carousel"].label }), _jsx(ConfirmDeleteModal, { isOpen: deleteConfirmOpen, onClose: () => setDeleteConfirmOpen(false), onConfirm: () => { setDeleteConfirmOpen(false); deleteMutation.mutate(); }, title: ACTIONS.ADMIN["delete-carousel"].confirmation.title, message: ACTIONS.ADMIN["delete-carousel"].confirmation.body, isDeleting: deleteMutation.isPending })] }))] })] }, "slide-form") }),
216
215
  ] }));
217
216
  }
@@ -6,6 +6,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
6
6
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
7
7
  import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
8
8
  import { BulkActionBar, ListingToolbar, ListingViewShell, Pagination, Text } from "../../../ui";
9
+ import { useBottomActions } from "../../layout";
9
10
  import { ADMIN_ENDPOINTS, HOMEPAGE_ENDPOINTS } from "../../../constants/api-endpoints";
10
11
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
11
12
  import { toRecordArray, toRelativeDate, toStringValue, useAdminListingData, } from "../hooks/useAdminListingData";
@@ -18,7 +19,7 @@ const DEFAULT_SORT = "order";
18
19
  function CarouselFilterDrawer({ filterOpen, setFilterOpen, activeFilterCount, clearFilters, pendingFilters, setPendingFilters, applyFilters, }) {
19
20
  if (!filterOpen)
20
21
  return null;
21
- return (_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" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsxs("div", { className: "space-y-2", children: [_jsx(Text, { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Status" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Active", value: "true" }, { label: "Inactive", value: "false" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, active: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.active || "") === opt.value ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] }) }), _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})` : ""] }) })] })] }));
22
+ return (_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 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsxs("div", { className: "space-y-2", children: [_jsx(Text, { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Status" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Active", value: "true" }, { label: "Inactive", value: "false" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, active: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.active || "") === opt.value ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] }) }), _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})` : ""] }) })] })] }));
22
23
  }
23
24
  export function AdminCarouselView({ children, onBulkDelete, ...props }) {
24
25
  const hasChildren = React.Children.count(children) > 0;
@@ -143,6 +144,7 @@ export function AdminCarouselView({ children, onBulkDelete, ...props }) {
143
144
  onClick: async () => { await onBulkDelete(selection.selectedIds); selection.clearSelection(); },
144
145
  }] : []),
145
146
  ];
147
+ useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: bulkActions } } : {});
146
148
  if (hasChildren) {
147
149
  return _jsx(ListingViewShell, { portal: "admin", ...props, children: children });
148
150
  }
@@ -169,12 +171,12 @@ export function AdminCarouselView({ children, onBulkDelete, ...props }) {
169
171
  {
170
172
  key: "status",
171
173
  header: "Status",
172
- render: (row) => (_jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${row.status === "Active" ? "bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300" : "bg-zinc-100 text-zinc-600 dark:bg-zinc-800 dark:text-zinc-400"}`, children: row.status })),
174
+ render: (row) => (_jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${row.status === "Active" ? "bg-success-surface text-success" : "bg-zinc-100 text-zinc-600 dark:bg-zinc-800 dark:text-zinc-400"}`, children: row.status })),
173
175
  },
174
176
  {
175
177
  key: "updatedAt",
176
178
  header: "Updated",
177
- render: (row) => _jsx("span", { className: "text-sm text-zinc-500", children: row.updatedAt }),
179
+ render: (row) => _jsx("span", { className: "text-sm text-zinc-500 dark:text-zinc-400", children: row.updatedAt }),
178
180
  },
179
181
  {
180
182
  key: "actions",
@@ -189,5 +191,5 @@ export function AdminCarouselView({ children, onBulkDelete, ...props }) {
189
191
  ] })),
190
192
  },
191
193
  ];
192
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search slide titles", onSearchChange: setSearchInput, onSearchCommit: commitSearch, showTableView: true, view: view, onViewChange: (v) => setView(v), 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) }) })), selection.selectedCount > 0 && bulkActions.length > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), _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 })), _jsx(DataTable, { rows: displayRows, columns: columns, isLoading: isLoading, emptyLabel: "No carousel slides \u2014 use 'New slide' to add one", getRowHref: (row) => `/admin/carousel/${row.id}/edit` })] }), _jsx(CarouselFilterDrawer, { filterOpen: filterOpen, setFilterOpen: setFilterOpen, activeFilterCount: activeFilterCount, clearFilters: clearFilters, pendingFilters: pendingFilters, setPendingFilters: setPendingFilters, applyFilters: applyFilters })] }));
194
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search slide titles", onSearchChange: setSearchInput, onSearchCommit: commitSearch, showTableView: true, view: view, onViewChange: (v) => setView(v), 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) }) })), selection.selectedCount > 0 && bulkActions.length > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-error-surface px-4 py-3 text-sm text-error dark:border-red-900/60", children: errorMessage })), _jsx(DataTable, { rows: displayRows, columns: columns, isLoading: isLoading, emptyLabel: "No carousel slides \u2014 use 'New slide' to add one", getRowHref: (row) => `/admin/carousel/${row.id}/edit` })] }), _jsx(CarouselFilterDrawer, { filterOpen: filterOpen, setFilterOpen: setFilterOpen, activeFilterCount: activeFilterCount, clearFilters: clearFilters, pendingFilters: pendingFilters, setPendingFilters: setPendingFilters, applyFilters: applyFilters })] }));
193
195
  }
@@ -91,5 +91,5 @@ export function AdminCartsView({ children, ...props }) {
91
91
  if (hasChildren) {
92
92
  return _jsx(ListingViewShell, { portal: "admin", ...props, children: children });
93
93
  }
94
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search by user ID or session", 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 }), 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 })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No carts found", selectedIds: selectedIds, onToggleSelect: toggleSelect, onToggleSelectAll: (next) => setSelectedIds(next ? new Set(rows.map((r) => r.id)) : new Set()) })] }), 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" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _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})` : ""] }) })] })] }))] }));
94
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search by user ID or session", 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 }), 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-error-surface px-4 py-3 text-sm text-error dark:border-red-900/60", children: errorMessage })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No carts found", selectedIds: selectedIds, onToggleSelect: toggleSelect, onToggleSelectAll: (next) => setSelectedIds(next ? new Set(rows.map((r) => r.id)) : new Set()) })] }), 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 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _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})` : ""] }) })] })] }))] }));
95
95
  }
@@ -1,24 +1,24 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Package, FolderTree, Tag, Star, AlertTriangle } from "lucide-react";
3
- import { Div, Heading, Text, Section, Alert } from "../../../ui";
3
+ import { Div, Heading, Span, Text, Section, Alert } from "../../../ui";
4
4
  import { GC } from "../../_guide-cls";
5
5
  export function AdminCatalogGuideView() {
6
6
  return (_jsxs(Div, { className: "space-y-8 pb-10 max-w-3xl mx-auto", children: [_jsxs(Section, { children: [_jsxs(Div, { className: "flex items-center gap-3 mb-2", children: [_jsx(Div, { className: "flex-shrink-0 w-10 h-10 rounded-xl flex items-center justify-center", style: { background: "linear-gradient(135deg,var(--appkit-color-primary-700,#4f46e5) 0%,var(--appkit-color-cobalt,#2563eb) 100%)" }, children: _jsx(Package, { className: "w-5 h-5 text-white" }) }), _jsx(Text, { className: "text-sm font-semibold text-[var(--appkit-color-text-muted)] uppercase tracking-widest", children: "Admin Guide" })] }), _jsx(Heading, { level: 1, className: "text-2xl md:text-3xl font-bold text-[var(--appkit-color-text)] mb-2", children: "Catalog" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: "Products, categories, brands, and reviews \u2014 how the LetItRip catalog is structured and managed." })] }), [
7
7
  {
8
8
  Icon: Package, title: "Product Management",
9
- content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Listing types" }), ": ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "standard" }), " (prefix ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "product-" }), "), ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "auction" }), " (prefix ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "auction-" }), "), ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "pre-order" }), " (prefix ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "preorder-" }), ")."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Admin vs store creation" }), ": Admins can create products on behalf of any store via the store picker in AdminProductEditorView."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Status lifecycle" }), ": DRAFT \u2192 PUBLISHED \u2192 ARCHIVED. Published products appear in search. Archived products are hidden but not deleted."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "J13 rule" }), ": Always use ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "listingType" }), " field \u2014 the legacy ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "isAuction" }), "/", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "isPreOrder" }), " booleans have been removed. All queries use ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "where(\"listingType\", \"==\", x)" }), "."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Media URLs" }), ": Never write raw Firebase Storage URLs to Firestore. All product image URLs must use the ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "/api/media/[slug]" }), " proxy format."] })] })),
9
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Listing types" }), ": ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "standard" }), " (prefix ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "product-" }), "), ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "auction" }), " (prefix ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "auction-" }), "), ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "pre-order" }), " (prefix ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "preorder-" }), ")."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Admin vs store creation" }), ": Admins can create products on behalf of any store via the store picker in AdminProductEditorView."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Status lifecycle" }), ": DRAFT \u2192 PUBLISHED \u2192 ARCHIVED. Published products appear in search. Archived products are hidden but not deleted."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "J13 rule" }), ": Always use ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "listingType" }), " field \u2014 the legacy ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "isAuction" }), "/", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "isPreOrder" }), " booleans have been removed. All queries use ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "where(\"listingType\", \"==\", x)" }), "."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Media URLs" }), ": Never write raw Firebase Storage URLs to Firestore. All product image URLs must use the ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "/api/media/[slug]" }), " proxy format."] })] })),
10
10
  },
11
11
  {
12
12
  Icon: FolderTree, title: "Category Taxonomy",
13
- content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "3-tier system" }), ": Root (tier 1) \u2192 Subcategory (tier 2) \u2192 Leaf (tier 3). Only leaf categories can be assigned to products."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Key fields" }), ": ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "parentId" }), " points to the direct parent; ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "rootId" }), " always points to the tier-1 root; ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "path" }), " stores the full hierarchy path."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "isLeaf" }), ": Must be ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "true" }), " on any category that can be selected in the product form. Tier-1 and tier-2 categories must have ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "isLeaf: false" }), "."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Slug prefix" }), ": All category slugs start with ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "category-" }), "."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Adding a new root" }), ": Rare. Requires: ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "display.icon" }), ", decision on ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "showOnHomepage" }), ", and a senior admin sign-off."] })] })),
13
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "3-tier system" }), ": Root (tier 1) \u2192 Subcategory (tier 2) \u2192 Leaf (tier 3). Only leaf categories can be assigned to products."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Key fields" }), ": ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "parentId" }), " points to the direct parent; ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "rootId" }), " always points to the tier-1 root; ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "path" }), " stores the full hierarchy path."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "isLeaf" }), ": Must be ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "true" }), " on any category that can be selected in the product form. Tier-1 and tier-2 categories must have ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "isLeaf: false" }), "."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Slug prefix" }), ": All category slugs start with ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "category-" }), "."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Adding a new root" }), ": Rare. Requires: ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "display.icon" }), ", decision on ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "showOnHomepage" }), ", and a senior admin sign-off."] })] })),
14
14
  },
15
15
  {
16
16
  Icon: Tag, title: "Brands",
17
- content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Slug prefix" }), ": ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "brand-" }), ". Slugs are immutable after products reference them."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "displayOrder" }), ": Controls the sort order on public brand pages. Lower numbers appear first."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "isActive: false" }), ": Hides the brand from public discovery but preserves historical product links. Use this instead of deleting a brand."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "logoURL / bannerURL" }), ": Must use the ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "/api/media/" }), " proxy \u2014 never raw Storage URLs."] })] })),
17
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Slug prefix" }), ": ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "brand-" }), ". Slugs are immutable after products reference them."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "displayOrder" }), ": Controls the sort order on public brand pages. Lower numbers appear first."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "isActive: false" }), ": Hides the brand from public discovery but preserves historical product links. Use this instead of deleting a brand."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "logoURL / bannerURL" }), ": Must use the ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "/api/media/" }), " proxy \u2014 never raw Storage URLs."] })] })),
18
18
  },
19
19
  {
20
20
  Icon: Star, title: "Reviews",
21
- content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "isVerifiedPurchase" }), ": Set automatically by the system after order DELIVERED. Never manually toggle this field."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "sellerResponse" }), ": Written by the seller via their store dashboard. Admins should not edit seller responses \u2014 only remove clearly violating ones."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "When to delete vs hide" }), ": Delete for violations (PII, slurs, spam). Hide (move to unlisted) if a dispute is pending resolution."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "helpfulCount" }), ": Read-only \u2014 incremented by buyer votes. Do not manually edit this field."] })] })),
21
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "isVerifiedPurchase" }), ": Set automatically by the system after order DELIVERED. Never manually toggle this field."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "sellerResponse" }), ": Written by the seller via their store dashboard. Admins should not edit seller responses \u2014 only remove clearly violating ones."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "When to delete vs hide" }), ": Delete for violations (PII, slurs, spam). Hide (move to unlisted) if a dispute is pending resolution."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "helpfulCount" }), ": Read-only \u2014 incremented by buyer votes. Do not manually edit this field."] })] })),
22
22
  },
23
23
  {
24
24
  Icon: AlertTriangle, title: "Common Admin Mistakes",
@@ -12,6 +12,7 @@ import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
12
12
  import { toRecordArray, toRelativeDate, toStringValue, useAdminListingData, } from "../hooks/useAdminListingData";
13
13
  import { DataTable } from "./DataTable";
14
14
  import { AdminCategoryEditorView } from "./AdminCategoryEditorView";
15
+ import { useBottomActions } from "../../layout";
15
16
  const PAGE_SIZE = 50;
16
17
  const FILTER_KEYS = ["isActive", "isFeatured"];
17
18
  const DEFAULT_SORT = "name";
@@ -23,7 +24,7 @@ const SORT_OPTIONS = [
23
24
  function CategoriesFilterDrawer({ filterOpen, setFilterOpen, activeFilterCount, clearFilters, pendingFilters, setPendingFilters, applyFilters, }) {
24
25
  if (!filterOpen)
25
26
  return null;
26
- return (_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: [_jsxs("div", { className: "space-y-2", children: [_jsx(Text, { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Active" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Active", value: "true" }, { label: "Inactive", value: "false" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isActive: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isActive || "") === opt.value ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Text, { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Featured" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Featured only", value: "true" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isFeatured: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isFeatured || "") === opt.value ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] })] }), _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})` : ""] }) })] })] }));
27
+ return (_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 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-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: [_jsxs("div", { className: "space-y-2", children: [_jsx(Text, { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Active" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Active", value: "true" }, { label: "Inactive", value: "false" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isActive: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isActive || "") === opt.value ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Text, { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Featured" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Featured only", value: "true" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isFeatured: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isFeatured || "") === opt.value ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] })] }), _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})` : ""] }) })] })] }));
27
28
  }
28
29
  export function AdminCategoriesView({ children, getRowHref, ...props }) {
29
30
  const hasChildren = React.Children.count(children) > 0;
@@ -93,8 +94,12 @@ export function AdminCategoriesView({ children, getRowHref, ...props }) {
93
94
  if (hasChildren) {
94
95
  return _jsx(ListingViewShell, { portal: "admin", ...props, children: children });
95
96
  }
97
+ useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [
98
+ { id: "edit", label: ACTIONS.ADMIN["edit-category"].label, variant: "primary", onClick: () => { const id = selection.selectedIds[0]; if (id)
99
+ openEditPanel(id); selection.clearSelection(); } },
100
+ ] } } : {});
96
101
  return (_jsxs("div", { className: "min-h-screen", children: [_jsx(Heading, { level: 1, className: "sr-only", children: "Categories" }), _jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search categories, slugs, or parent category", 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 Category"] }) }), _jsx(BulkActionBar, { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [
97
102
  { id: "edit", label: ACTIONS.ADMIN["edit-category"].label, variant: "primary", onClick: () => { const id = selection.selectedIds[0]; if (id)
98
103
  openEditPanel(id); selection.clearSelection(); } },
99
- ] }), 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 categories found", selectedIds: selection.selectedIdSet, onToggleSelect: selection.toggle, onToggleSelectAll: (next) => next ? selection.setSelectedIds(rows.map(r => r.id)) : selection.clearSelection(), onRowClick: (row) => openEditPanel(row.id) })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No categories found", onRowClick: (row) => openEditPanel(row.id), selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] }), _jsx(CategoriesFilterDrawer, { filterOpen: filterOpen, setFilterOpen: setFilterOpen, activeFilterCount: activeFilterCount, clearFilters: clearFilters, pendingFilters: pendingFilters, setPendingFilters: setPendingFilters, applyFilters: applyFilters }), _jsx(SideDrawer, { isOpen: isCreateOpen || isEditOpen, onClose: closePanel, title: isCreateOpen ? "Add Category" : "Edit Category", mode: isCreateOpen ? "create" : "edit", children: (isCreateOpen || isEditOpen) && (_jsx(AdminCategoryEditorView, { categoryId: editId ?? undefined, onSaved: closePanel, onDeleted: closePanel, embedded: true })) })] }));
104
+ ] }), 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-error-surface px-4 py-3 text-sm text-error dark:border-red-900/60", children: errorMessage })), view === "table" ? (_jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No categories found", selectedIds: selection.selectedIdSet, onToggleSelect: selection.toggle, onToggleSelectAll: (next) => next ? selection.setSelectedIds(rows.map(r => r.id)) : selection.clearSelection(), onRowClick: (row) => openEditPanel(row.id) })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No categories found", onRowClick: (row) => openEditPanel(row.id), selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] }), _jsx(CategoriesFilterDrawer, { filterOpen: filterOpen, setFilterOpen: setFilterOpen, activeFilterCount: activeFilterCount, clearFilters: clearFilters, pendingFilters: pendingFilters, setPendingFilters: setPendingFilters, applyFilters: applyFilters }), _jsx(SideDrawer, { isOpen: isCreateOpen || isEditOpen, onClose: closePanel, title: isCreateOpen ? "Add Category" : "Edit Category", mode: isCreateOpen ? "create" : "edit", children: (isCreateOpen || isEditOpen) && (_jsx(AdminCategoryEditorView, { categoryId: editId ?? undefined, onSaved: closePanel, onDeleted: closePanel, embedded: true })) })] }));
100
105
  }
@@ -22,9 +22,9 @@ export function AdminContactEditorView({ open, onClose, submissionId, subject, n
22
22
  },
23
23
  });
24
24
  const statusColor = {
25
- new: "bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300",
25
+ new: "bg-info-surface text-info",
26
26
  read: "bg-zinc-100 text-zinc-600 dark:bg-zinc-800 dark:text-zinc-400",
27
- resolved: "bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300",
27
+ resolved: "bg-success-surface text-success",
28
28
  };
29
29
  return (_jsx(SideDrawer, { isOpen: open, onClose: onClose, title: subject ?? "Contact Submission", children: _jsxs(Div, { className: "flex flex-col gap-5 p-4", children: [_jsxs(Div, { className: "flex items-center gap-2", children: [_jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Status:" }), _jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${statusColor[currentStatus ?? "new"] ?? statusColor.new}`, children: currentStatus ?? "new" })] }), _jsxs(Div, { className: "flex flex-col gap-1", children: [_jsx(Text, { className: "text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wide", children: "From" }), _jsx(Text, { className: "text-sm font-medium text-zinc-900 dark:text-zinc-100", children: name ?? "Unknown" }), email && (_jsx(Text, { className: "text-sm text-zinc-500 dark:text-zinc-400", children: email }))] }), _jsxs(Div, { className: "flex flex-col gap-1", children: [_jsx(Text, { className: "text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wide", children: "Message" }), _jsx(Div, { className: "rounded-lg border border-zinc-200 dark:border-zinc-700 bg-zinc-50 dark:bg-zinc-800 p-3 max-h-64 overflow-y-auto", children: _jsx(Text, { className: "text-sm text-zinc-800 dark:text-zinc-200 whitespace-pre-wrap leading-relaxed", children: message ?? "No message body." }) })] }), _jsxs(FormActions, { align: "right", children: [email && (_jsx(Button, { type: "button", variant: "outline", onClick: () => {
30
30
  window.location.href = `mailto:${email}?subject=Re: ${encodeURIComponent(subject ?? "")}`;
@@ -6,6 +6,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
6
6
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
7
7
  import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
8
8
  import { BulkActionBar, ConfirmDeleteModal, FilterChipGroup, ListingToolbar, ListingViewShell, Pagination, RowActionMenu, useToast, } from "../../../ui";
9
+ import { useBottomActions } from "../../layout";
9
10
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
10
11
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
11
12
  import { ROW_ACTION_META, ROW_ACTION_ID } from "../../../features/products/constants/action-defs";
@@ -25,7 +26,7 @@ const STATUS_OPTIONS = ADMIN_CONTACT_STATUS_TABS;
25
26
  function ContactFilterDrawer({ filterOpen, setFilterOpen, activeFilterCount, clearFilters, pendingFilters, setPendingFilters, applyFilters, }) {
26
27
  if (!filterOpen)
27
28
  return null;
28
- return (_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" }) })] })] }), _jsx("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("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})` : ""] }) })] })] }));
29
+ return (_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 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("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("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})` : ""] }) })] })] }));
29
30
  }
30
31
  export function AdminContactView({ children, onBulkMarkRead, onBulkArchive, onBulkDelete, ...props }) {
31
32
  const hasChildren = React.Children.count(children) > 0;
@@ -141,10 +142,11 @@ export function AdminContactView({ children, onBulkMarkRead, onBulkArchive, onBu
141
142
  onClick: async () => { await onBulkDelete(selection.selectedIds); selection.clearSelection(); },
142
143
  }] : []),
143
144
  ];
145
+ useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: bulkActions } } : {});
144
146
  if (hasChildren) {
145
147
  return _jsx(ListingViewShell, { portal: "admin", ...props, children: children });
146
148
  }
147
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search by subject, name, or email", 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 }), 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) }) })), selection.selectedCount > 0 && bulkActions.length > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), _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 })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No contact submissions found", renderRowActions: (row) => {
149
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search by subject, name, or email", 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 }), 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) }) })), selection.selectedCount > 0 && bulkActions.length > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-error-surface px-4 py-3 text-sm text-error dark:border-red-900/60", children: errorMessage })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No contact submissions found", renderRowActions: (row) => {
148
150
  const cr = row;
149
151
  return (_jsx(RowActionMenu, { actions: [
150
152
  { label: ROW_ACTION_META[ROW_ACTION_ID.VIEW].label, onClick: () => { setSelectedRow(cr); setDrawerOpen(true); } },
@@ -1,28 +1,28 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { FileText, Calendar, BookOpen, Layout, Grid, Megaphone, Mail } from "lucide-react";
3
- import { Div, Heading, Text, Section, Alert } from "../../../ui";
3
+ import { Div, Heading, Span, Text, Section, Alert } from "../../../ui";
4
4
  import { GC } from "../../_guide-cls";
5
5
  export function AdminContentGuideView() {
6
6
  return (_jsxs(Div, { className: "space-y-8 pb-10 max-w-3xl mx-auto", children: [_jsxs(Section, { children: [_jsxs(Div, { className: "flex items-center gap-3 mb-2", children: [_jsx(Div, { className: "flex-shrink-0 w-10 h-10 rounded-xl flex items-center justify-center", style: { background: "linear-gradient(135deg,var(--appkit-color-primary-700,#4f46e5) 0%,var(--appkit-color-cobalt,#2563eb) 100%)" }, children: _jsx(FileText, { className: "w-5 h-5 text-white" }) }), _jsx(Text, { className: "text-sm font-semibold text-[var(--appkit-color-text-muted)] uppercase tracking-widest", children: "Admin Guide" })] }), _jsx(Heading, { level: 1, className: "text-2xl md:text-3xl font-bold text-[var(--appkit-color-text)] mb-2", children: "Content & Marketing" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: "Blog posts, events, FAQs, carousel, homepage sections, ads, and newsletter on LetItRip." })] }), [
7
7
  {
8
8
  Icon: FileText, title: "Blog Posts",
9
- content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Statuses" }), ": ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "draft" }), " (not public), ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "published" }), " (live, indexed)."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "readTimeMinutes" }), ": Auto-calculated from content word count (200 wpm). Override manually if the post has heavy media."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "youtubeId" }), ": Optional embedded YouTube video. Use only the video ID (e.g. ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "dQw4w9WgXcQ" }), "), not the full URL."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Media in body" }), ": All images in rich text must use the ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "/api/media/" }), " proxy URL, not raw Firebase Storage links."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "isFeatured" }), ": Sets the post as featured in the blog listing. Different from the homepage featured section \u2014 that is driven by a separate ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "homepageSections" }), " config."] })] })),
9
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Statuses" }), ": ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "draft" }), " (not public), ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "published" }), " (live, indexed)."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "readTimeMinutes" }), ": Auto-calculated from content word count (200 wpm). Override manually if the post has heavy media."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "youtubeId" }), ": Optional embedded YouTube video. Use only the video ID (e.g. ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "dQw4w9WgXcQ" }), "), not the full URL."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Media in body" }), ": All images in rich text must use the ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "/api/media/" }), " proxy URL, not raw Firebase Storage links."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "isFeatured" }), ": Sets the post as featured in the blog listing. Different from the homepage featured section \u2014 that is driven by a separate ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "homepageSections" }), " config."] })] })),
10
10
  },
11
11
  {
12
12
  Icon: Calendar, title: "Events",
13
- content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Event types" }), ": ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "sale" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "offer" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "poll" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "survey" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "feedback" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "raffle" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "spin_wheel" }), "."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Status" }), ": Computed from ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "startsAt" }), "/", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "endsAt" }), " (upcoming \u2192 active \u2192 ended). Do not set a status field manually \u2014 it will be overwritten."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "stats.totalEntries vs approvedEntries" }), ": ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "totalEntries" }), " = all submitted (including waitlisted); ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "approvedEntries" }), " = CONFIRMED only."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Cancelling an entry" }), ": Set status to CANCELLED in the entry doc. Do not delete entries \u2014 audit trail is needed for raffle fairness."] })] })),
13
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Event types" }), ": ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "sale" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "offer" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "poll" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "survey" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "feedback" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "raffle" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "spin_wheel" }), "."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Status" }), ": Computed from ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "startsAt" }), "/", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "endsAt" }), " (upcoming \u2192 active \u2192 ended). Do not set a status field manually \u2014 it will be overwritten."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "stats.totalEntries vs approvedEntries" }), ": ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "totalEntries" }), " = all submitted (including waitlisted); ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "approvedEntries" }), " = CONFIRMED only."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Cancelling an entry" }), ": Set status to CANCELLED in the entry doc. Do not delete entries \u2014 audit trail is needed for raffle fairness."] })] })),
14
14
  },
15
15
  {
16
16
  Icon: BookOpen, title: "FAQs",
17
- content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Categories" }), " and where they appear: Shipping (help + footer), Returns (help), Payments (help), Auctions (help), Pre-orders (help). Set ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "showOnHomepage: true" }), " for up to 5 FAQs shown on the public home page."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "searchTokens[]" }), ": Must be manually filled \u2014 drives the FAQ search feature. Include synonyms, misspellings, and related keywords."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "priority + order" }), ": ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "priority" }), " sorts FAQs within their category; ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "order" }), " is the global absolute position. ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "isPinned: true" }), " floats the FAQ above non-pinned items in its category."] })] })),
17
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Categories" }), " and where they appear: Shipping (help + footer), Returns (help), Payments (help), Auctions (help), Pre-orders (help). Set ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "showOnHomepage: true" }), " for up to 5 FAQs shown on the public home page."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "searchTokens[]" }), ": Must be manually filled \u2014 drives the FAQ search feature. Include synonyms, misspellings, and related keywords."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "priority + order" }), ": ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "priority" }), " sorts FAQs within their category; ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "order" }), " is the global absolute position. ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "isPinned: true" }), " floats the FAQ above non-pinned items in its category."] })] })),
18
18
  },
19
19
  {
20
20
  Icon: Layout, title: "Carousel Slides",
21
- content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "MAX_ACTIVE_SLIDES = 5" }), ": You cannot activate a 6th slide. Deactivate an existing slide first."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "background.type" }), ": ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "image" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "video" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "color" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "gradient" }), ". Do not have 2 active video slides simultaneously \u2014 auto-playing two videos degrades mobile performance."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Reordering" }), ": Drag slides in AdminCarouselView to reorder. The ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "order" }), " field is updated automatically."] }), _jsxs("li", { children: [_jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "cards[]" }), ": Each slide contains an array of content cards displayed as an overlay. Max 3 cards per slide recommended for readability."] })] })),
21
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "MAX_ACTIVE_SLIDES = 5" }), ": You cannot activate a 6th slide. Deactivate an existing slide first."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "background.type" }), ": ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "image" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "video" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "color" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "gradient" }), ". Do not have 2 active video slides simultaneously \u2014 auto-playing two videos degrades mobile performance."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Reordering" }), ": Drag slides in AdminCarouselView to reorder. The ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "order" }), " field is updated automatically."] }), _jsxs("li", { children: [_jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "cards[]" }), ": Each slide contains an array of content cards displayed as an overlay. Max 3 cards per slide recommended for readability."] })] })),
22
22
  },
23
23
  {
24
24
  Icon: Grid, title: "Homepage Sections",
25
- content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "21 section types" }), ": product-grid, brand-grid, category-grid, event-highlight, blog-preview, etc. The full list and config shapes are in ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "appkit/src/features/homepage/schemas/firestore.ts" }), "."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "order" }), ": Controls render sequence on the public homepage. Lower numbers appear higher on the page."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "enabled: false" }), ": Hides the section without deleting it \u2014 useful for temporary removal."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Never edit Firestore directly" }), ": Always use AdminSectionsView. The config shapes are validated on write \u2014 direct Firestore edits can produce invalid shapes that crash the home page render."] })] })),
25
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "21 section types" }), ": product-grid, brand-grid, category-grid, event-highlight, blog-preview, etc. The full list and config shapes are in ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "appkit/src/features/homepage/schemas/firestore.ts" }), "."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "order" }), ": Controls render sequence on the public homepage. Lower numbers appear higher on the page."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "enabled: false" }), ": Hides the section without deleting it \u2014 useful for temporary removal."] }), _jsxs("li", { children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Never edit Firestore directly" }), ": Always use AdminSectionsView. The config shapes are validated on write \u2014 direct Firestore edits can produce invalid shapes that crash the home page render."] })] })),
26
26
  },
27
27
  {
28
28
  Icon: Megaphone, title: "Ads",
@@ -6,6 +6,7 @@ import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
6
  import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
7
7
  import { usePanelUrlSync } from "../../../react/hooks/use-panel-url-sync";
8
8
  import { BulkActionBar, Button, Div, FilterChipGroup, ListingToolbar, Pagination, ListingViewShell, SideDrawer, Text, useToast } from "../../../ui";
9
+ import { useBottomActions } from "../../layout";
9
10
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
10
11
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
11
12
  import { ADMIN_COUPON_TYPE_TABS } from "../constants/filter-tabs";
@@ -25,7 +26,7 @@ const TYPE_OPTIONS = ADMIN_COUPON_TYPE_TABS;
25
26
  function CouponsFilterDrawer({ filterOpen, setFilterOpen, activeFilterCount, clearFilters, pendingFilters, setPendingFilters, applyFilters, }) {
26
27
  if (!filterOpen)
27
28
  return null;
28
- return (_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" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _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})` : ""] }) })] })] }));
29
+ return (_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 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _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})` : ""] }) })] })] }));
29
30
  }
30
31
  export function AdminCouponsView({ children, getRowHref, onBulkArchive, onBulkDelete, ...props }) {
31
32
  const hasChildren = React.Children.count(children) > 0;
@@ -116,8 +117,9 @@ export function AdminCouponsView({ children, getRowHref, onBulkArchive, onBulkDe
116
117
  onClick: async () => { await onBulkDelete(selection.selectedIds); selection.clearSelection(); },
117
118
  }] : []),
118
119
  ];
120
+ useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: bulkActions } } : {});
119
121
  if (hasChildren) {
120
122
  return _jsx(ListingViewShell, { portal: "admin", ...props, children: children });
121
123
  }
122
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search codes, campaigns, or seller scopes", 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 Coupon"] }) }), selection.selectedCount > 0 && bulkActions.length > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), 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 })), isLoading ? (_jsx(Div, { className: "fluid-grid-card gap-3", children: Array.from({ length: 6 }).map((_, i) => (_jsxs(Div, { className: "rounded-xl border-2 border-zinc-100 dark:border-slate-700 p-4 animate-pulse space-y-3", children: [_jsx(Div, { className: "h-6 bg-zinc-200 dark:bg-slate-700 rounded w-2/3" }), _jsx(Div, { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx(Div, { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-1/2" })] }, i))) })) : rows.length === 0 ? (_jsx(Div, { className: "py-16 text-center", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-500", children: "No coupons found" }) })) : (_jsx(Div, { className: "fluid-grid-card gap-3", children: rows.map((row) => (_jsx(CouponCard, { coupon: row.raw, onEdit: openEditPanel, onToggleActive: handleToggle, onDelete: handleDelete }, row.id))) }))] }), _jsx(CouponsFilterDrawer, { filterOpen: filterOpen, setFilterOpen: setFilterOpen, activeFilterCount: activeFilterCount, clearFilters: clearFilters, pendingFilters: pendingFilters, setPendingFilters: setPendingFilters, applyFilters: applyFilters }), _jsx(SideDrawer, { isOpen: isCreateOpen || isEditOpen, onClose: closePanel, title: isCreateOpen ? "Add Coupon" : "Edit Coupon", mode: isCreateOpen ? "create" : "edit", children: (isCreateOpen || isEditOpen) && (_jsx(AdminCouponEditorView, { couponId: editId ?? undefined, onSaved: closePanel, onDeleted: closePanel, embedded: true })) })] }));
124
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search codes, campaigns, or seller scopes", 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 Coupon"] }) }), selection.selectedCount > 0 && bulkActions.length > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), 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-error-surface px-4 py-3 text-sm text-error dark:border-red-900/60", children: errorMessage })), isLoading ? (_jsx(Div, { className: "fluid-grid-card gap-3", children: Array.from({ length: 6 }).map((_, i) => (_jsxs(Div, { className: "rounded-xl border-2 border-zinc-100 dark:border-slate-700 p-4 animate-pulse space-y-3", children: [_jsx(Div, { className: "h-6 bg-zinc-200 dark:bg-slate-700 rounded w-2/3" }), _jsx(Div, { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx(Div, { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-1/2" })] }, i))) })) : rows.length === 0 ? (_jsx(Div, { className: "py-16 text-center", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-400", children: "No coupons found" }) })) : (_jsx(Div, { className: "fluid-grid-card gap-3", children: rows.map((row) => (_jsx(CouponCard, { coupon: row.raw, onEdit: openEditPanel, onToggleActive: handleToggle, onDelete: handleDelete }, row.id))) }))] }), _jsx(CouponsFilterDrawer, { filterOpen: filterOpen, setFilterOpen: setFilterOpen, activeFilterCount: activeFilterCount, clearFilters: clearFilters, pendingFilters: pendingFilters, setPendingFilters: setPendingFilters, applyFilters: applyFilters }), _jsx(SideDrawer, { isOpen: isCreateOpen || isEditOpen, onClose: closePanel, title: isCreateOpen ? "Add Coupon" : "Edit Coupon", mode: isCreateOpen ? "create" : "edit", children: (isCreateOpen || isEditOpen) && (_jsx(AdminCouponEditorView, { couponId: editId ?? undefined, onSaved: closePanel, onDeleted: closePanel, embedded: true })) })] }));
123
125
  }
@@ -75,7 +75,7 @@ function PermissionDomainsPanel({ permissions, togglePerm }) {
75
75
  if (domainPerms.length === 0)
76
76
  return null;
77
77
  const checked = domainPerms.filter((p) => permissions.has(p)).length;
78
- return (_jsxs("details", { className: "group", children: [_jsxs("summary", { className: "flex cursor-pointer items-center justify-between px-3 py-2 text-xs font-semibold uppercase tracking-wide text-zinc-600 dark:text-zinc-400 select-none hover:bg-zinc-50 dark:hover:bg-slate-800 transition-colors", children: [_jsx("span", { children: domain.label }), _jsxs("span", { className: "text-xs font-normal normal-case text-zinc-400 dark:text-zinc-500", children: [checked, "/", domainPerms.length] })] }), _jsx("div", { className: "grid grid-cols-2 gap-x-2 gap-y-1.5 px-3 py-2.5 bg-zinc-50/60 dark:bg-slate-800/40", children: domainPerms.map((perm) => (_jsxs("label", { className: "flex items-center gap-2 cursor-pointer text-xs text-zinc-700 dark:text-zinc-300", children: [_jsx("input", { type: "checkbox", checked: permissions.has(perm), onChange: () => togglePerm(perm), className: "h-3.5 w-3.5 rounded border-zinc-300 dark:border-slate-600 accent-primary" }), formatPermLabel(perm)] }, perm))) })] }, domain.prefix));
78
+ return (_jsxs("details", { className: "group", children: [_jsxs("summary", { className: "flex cursor-pointer items-center justify-between px-3 py-2 text-xs font-semibold uppercase tracking-wide text-zinc-600 dark:text-zinc-400 select-none hover:bg-zinc-50 dark:hover:bg-slate-800 transition-colors", children: [_jsx("span", { children: domain.label }), _jsxs("span", { className: "text-xs font-normal normal-case text-zinc-400 dark:text-zinc-400", children: [checked, "/", domainPerms.length] })] }), _jsx("div", { className: "grid grid-cols-2 gap-x-2 gap-y-1.5 px-3 py-2.5 bg-zinc-50/60 dark:bg-slate-800/40", children: domainPerms.map((perm) => (_jsxs("label", { className: "flex items-center gap-2 cursor-pointer text-xs text-zinc-700 dark:text-zinc-300", children: [_jsx("input", { type: "checkbox", checked: permissions.has(perm), onChange: () => togglePerm(perm), className: "h-3.5 w-3.5 rounded border-zinc-300 dark:border-slate-600 accent-primary" }), formatPermLabel(perm)] }, perm))) })] }, domain.prefix));
79
79
  }) })] }));
80
80
  }
81
81
  // --- Component ---------------------------------------------------------------