@mohasinac/appkit 2.8.2 → 2.8.4

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 (451) hide show
  1. package/dist/_internal/client/features/classified/ClassifiedDetailView.js +7 -1
  2. package/dist/_internal/client/features/digital-code/CodeRevealPanel.js +4 -1
  3. package/dist/_internal/client/features/digital-code/DigitalCodeDetailView.js +7 -1
  4. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +3 -2
  5. package/dist/_internal/client/features/live/LiveItemDetailView.js +11 -2
  6. package/dist/_internal/client/scaffolds/AppShell.js +2 -1
  7. package/dist/_internal/client/scaffolds/DashboardScaffold.js +2 -1
  8. package/dist/_internal/server/features/checkout/actions.js +40 -39
  9. package/dist/_internal/shared/actions/action-registry.js +6 -0
  10. package/dist/_internal/shared/config/index.d.ts +1 -1
  11. package/dist/_internal/shared/config/schema.d.ts +0 -8
  12. package/dist/client-entry.d.ts +1 -1
  13. package/dist/client.d.ts +3 -1
  14. package/dist/client.js +3 -1
  15. package/dist/configs/next.js +12 -22
  16. package/dist/constants/api-endpoints.d.ts +6 -0
  17. package/dist/constants/api-endpoints.js +2 -0
  18. package/dist/features/about/components/AboutView.js +5 -2
  19. package/dist/features/about/components/FAQPageView.js +3 -3
  20. package/dist/features/about/components/FeesView.js +13 -5
  21. package/dist/features/about/components/HelpPageView.js +9 -5
  22. package/dist/features/about/components/HowAuctionsWorkView.js +9 -5
  23. package/dist/features/about/components/HowCheckoutWorksView.js +9 -5
  24. package/dist/features/about/components/HowOffersWorkView.js +10 -5
  25. package/dist/features/about/components/HowOrdersWorkView.js +10 -5
  26. package/dist/features/about/components/HowPayoutsWorkView.js +9 -5
  27. package/dist/features/about/components/HowPreOrdersWorkView.js +9 -5
  28. package/dist/features/about/components/HowReviewsWorkView.js +9 -5
  29. package/dist/features/about/components/PolicyPageView.js +3 -3
  30. package/dist/features/about/components/PublicProfileView.js +11 -4
  31. package/dist/features/about/components/SecurityPrivacyView.js +8 -4
  32. package/dist/features/about/components/ShippingPolicyView.js +3 -2
  33. package/dist/features/about/components/TrackOrderView.js +2 -2
  34. package/dist/features/about/components/UnauthorizedView.js +3 -3
  35. package/dist/features/account/components/AddressBook.js +1 -1
  36. package/dist/features/account/components/AddressForm.js +2 -2
  37. package/dist/features/account/components/AddressInlineSelect.d.ts +24 -0
  38. package/dist/features/account/components/AddressInlineSelect.js +78 -0
  39. package/dist/features/account/components/AddressSelectorCreate.d.ts +2 -1
  40. package/dist/features/account/components/AddressSelectorCreate.js +5 -32
  41. package/dist/features/account/components/AddressesIndexListing.js +3 -3
  42. package/dist/features/account/components/ChatWindow.js +2 -1
  43. package/dist/features/account/components/NotificationBell.js +13 -7
  44. package/dist/features/account/components/NotificationPreferencesPanel.js +4 -1
  45. package/dist/features/account/components/UserOffersPanel.js +2 -1
  46. package/dist/features/account/components/UserSidebar.js +11 -7
  47. package/dist/features/account/components/UserSupportView.js +13 -4
  48. package/dist/features/account/components/index.d.ts +2 -0
  49. package/dist/features/account/components/index.js +1 -0
  50. package/dist/features/addresses/repository/addresses.repository.d.ts +1 -0
  51. package/dist/features/addresses/repository/addresses.repository.js +13 -0
  52. package/dist/features/admin/components/AdminAdEditorView.js +8 -5
  53. package/dist/features/admin/components/AdminAddressEditorView.js +5 -5
  54. package/dist/features/admin/components/AdminAdsView.js +10 -7
  55. package/dist/features/admin/components/AdminAllEventEntriesView.js +5 -3
  56. package/dist/features/admin/components/AdminBidsView.js +6 -4
  57. package/dist/features/admin/components/AdminBlogEditorView.js +15 -9
  58. package/dist/features/admin/components/AdminBlogView.js +6 -4
  59. package/dist/features/admin/components/AdminBrandEditorView.js +10 -4
  60. package/dist/features/admin/components/AdminBrandsView.js +12 -10
  61. package/dist/features/admin/components/AdminBundleEditorView.js +4 -5
  62. package/dist/features/admin/components/AdminBundlesView.js +13 -11
  63. package/dist/features/admin/components/AdminCarouselEditorView.js +6 -3
  64. package/dist/features/admin/components/AdminCarouselView.js +6 -6
  65. package/dist/features/admin/components/AdminCartsView.js +6 -4
  66. package/dist/features/admin/components/AdminCatalogGuideView.js +2 -1
  67. package/dist/features/admin/components/AdminCategoriesView.js +12 -10
  68. package/dist/features/admin/components/AdminCategoryEditorView.js +11 -5
  69. package/dist/features/admin/components/AdminClassifiedView.js +4 -3
  70. package/dist/features/admin/components/AdminContactEditorView.js +8 -1
  71. package/dist/features/admin/components/AdminContactView.js +6 -4
  72. package/dist/features/admin/components/AdminCouponEditorView.js +23 -5
  73. package/dist/features/admin/components/AdminCouponsView.js +6 -4
  74. package/dist/features/admin/components/AdminDigitalCodesView.js +4 -3
  75. package/dist/features/admin/components/AdminEmployeeEditorView.js +7 -4
  76. package/dist/features/admin/components/AdminFaqEditorView.js +9 -3
  77. package/dist/features/admin/components/AdminFaqsView.js +9 -7
  78. package/dist/features/admin/components/AdminFeatureEditorView.js +7 -1
  79. package/dist/features/admin/components/AdminFeatureFlagsView.js +4 -1
  80. package/dist/features/admin/components/AdminFeaturesView.js +5 -4
  81. package/dist/features/admin/components/AdminFilterBar.js +4 -4
  82. package/dist/features/admin/components/AdminGroupedListingsView.js +66 -30
  83. package/dist/features/admin/components/AdminGuideHubView.js +4 -1
  84. package/dist/features/admin/components/AdminHistoryView.js +4 -3
  85. package/dist/features/admin/components/AdminLiveView.js +4 -3
  86. package/dist/features/admin/components/AdminMediaView.js +4 -1
  87. package/dist/features/admin/components/AdminNavigationView.js +7 -4
  88. package/dist/features/admin/components/AdminNewsletterView.js +5 -3
  89. package/dist/features/admin/components/AdminNotificationsView.js +8 -6
  90. package/dist/features/admin/components/AdminOrderEditorView.js +2 -2
  91. package/dist/features/admin/components/AdminOrdersView.js +6 -4
  92. package/dist/features/admin/components/AdminPageHeader.js +5 -2
  93. package/dist/features/admin/components/AdminPayoutsView.js +7 -5
  94. package/dist/features/admin/components/AdminPrizeDrawsView.js +11 -9
  95. package/dist/features/admin/components/AdminProductEditorView.js +12 -5
  96. package/dist/features/admin/components/AdminProductsView.js +11 -9
  97. package/dist/features/admin/components/AdminReturnRequestsView.js +4 -3
  98. package/dist/features/admin/components/AdminReviewsView.js +10 -8
  99. package/dist/features/admin/components/AdminScammerEditorView.js +6 -2
  100. package/dist/features/admin/components/AdminScammersView.js +11 -9
  101. package/dist/features/admin/components/AdminSectionsView.js +20 -22
  102. package/dist/features/admin/components/AdminSessionsManager.js +2 -1
  103. package/dist/features/admin/components/AdminSessionsView.js +8 -6
  104. package/dist/features/admin/components/AdminSidebar.js +11 -7
  105. package/dist/features/admin/components/AdminSiteConfigGuideView.js +2 -1
  106. package/dist/features/admin/components/AdminSiteSettingsView.js +5 -1
  107. package/dist/features/admin/components/AdminStoreAddressesView.js +4 -3
  108. package/dist/features/admin/components/AdminStoreEditorView.js +5 -5
  109. package/dist/features/admin/components/AdminStoresView.js +6 -4
  110. package/dist/features/admin/components/AdminSublistingCategoriesView.js +6 -5
  111. package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +3 -3
  112. package/dist/features/admin/components/AdminSupportTicketDetailView.js +10 -3
  113. package/dist/features/admin/components/AdminSupportTicketsView.js +11 -9
  114. package/dist/features/admin/components/AdminTeamView.js +6 -4
  115. package/dist/features/admin/components/AdminTrustGuideView.js +3 -3
  116. package/dist/features/admin/components/AdminUsersGuideView.js +3 -3
  117. package/dist/features/admin/components/AdminUsersView.js +6 -4
  118. package/dist/features/admin/components/AdminViewCards.js +12 -6
  119. package/dist/features/admin/components/AdminWishlistsView.js +4 -3
  120. package/dist/features/admin/components/BrandQuickCreateForm.js +2 -2
  121. package/dist/features/admin/components/CategoryQuickCreateForm.js +2 -2
  122. package/dist/features/admin/components/DashboardStats.js +9 -3
  123. package/dist/features/admin/components/DataListingView.js +3 -3
  124. package/dist/features/admin/components/DataTable.js +11 -7
  125. package/dist/features/admin/components/DrawerFormFooter.js +2 -2
  126. package/dist/features/admin/components/QuickEditMenu.js +2 -1
  127. package/dist/features/admin/components/analytics/AdminAnalyticsCharts.js +5 -1
  128. package/dist/features/admin/constants/filter-tabs.d.ts +1 -1
  129. package/dist/features/admin/constants/filter-tabs.js +0 -11
  130. package/dist/features/admin/types/index.d.ts +1 -1
  131. package/dist/features/auctions/actions/bid-actions.js +4 -2
  132. package/dist/features/auctions/components/AuctionBidsTable.js +4 -1
  133. package/dist/features/auctions/components/AuctionDetailPageView.js +14 -6
  134. package/dist/features/auctions/components/AuctionsListView.js +7 -6
  135. package/dist/features/auctions/components/CollapsibleBidHistory.js +5 -1
  136. package/dist/features/auctions/components/MarketplaceAuctionCard.js +9 -3
  137. package/dist/features/auctions/components/MarketplaceAuctionGrid.js +8 -2
  138. package/dist/features/auctions/components/PlaceBidFormClient.js +4 -1
  139. package/dist/features/auth/components/RegisterForm.js +2 -2
  140. package/dist/features/auth/components/VerifyEmailView.js +5 -2
  141. package/dist/features/before-after/components/BeforeAfterSlider.js +1 -1
  142. package/dist/features/blog/actions/blog-actions.js +3 -2
  143. package/dist/features/blog/components/BlogFeaturedCard.js +8 -1
  144. package/dist/features/blog/components/BlogIndexListing.js +11 -5
  145. package/dist/features/blog/components/BlogListView.js +11 -3
  146. package/dist/features/blog/components/BlogPostView.js +10 -3
  147. package/dist/features/cart/components/CartDrawer.js +11 -3
  148. package/dist/features/cart/components/CartSummary.js +2 -2
  149. package/dist/features/cart/components/CheckoutOtpModal.js +2 -1
  150. package/dist/features/categories/components/BrandDetailPageView.js +15 -10
  151. package/dist/features/categories/components/BrandDetailTabs.js +5 -1
  152. package/dist/features/categories/components/BundleDetailView.js +6 -3
  153. package/dist/features/categories/components/BundleDynamicRuleEditor.js +3 -1
  154. package/dist/features/categories/components/BundleItemsPicker.js +10 -3
  155. package/dist/features/categories/components/CategoriesIndexListing.js +13 -7
  156. package/dist/features/categories/components/CategoriesIndexPageView.js +5 -4
  157. package/dist/features/categories/components/CategoryBundlesListing.js +10 -6
  158. package/dist/features/categories/components/CategoryDetailPageView.js +18 -12
  159. package/dist/features/categories/components/CategoryDetailTabs.js +5 -1
  160. package/dist/features/categories/components/CategoryFilters.d.ts +12 -12
  161. package/dist/features/categories/components/CategoryFilters.js +13 -12
  162. package/dist/features/categories/components/CategoryForm.js +6 -3
  163. package/dist/features/categories/components/CategoryGrid.js +9 -2
  164. package/dist/features/categories/components/CategoryProductsListing.js +10 -4
  165. package/dist/features/categories/components/CategorySelectorCreate.js +3 -3
  166. package/dist/features/categories/components/CategorySortSelect.js +1 -1
  167. package/dist/features/categories/components/CategoryStoresListing.js +3 -3
  168. package/dist/features/categories/components/CategoryTableColumns.js +10 -6
  169. package/dist/features/categories/components/CategoryTree.d.ts +1 -1
  170. package/dist/features/categories/components/CategoryTree.js +2 -2
  171. package/dist/features/categories/schemas/firestore.d.ts +2 -2
  172. package/dist/features/checkout/actions/checkout-actions.d.ts +1 -1
  173. package/dist/features/checkout/actions/checkout-actions.js +1 -1
  174. package/dist/features/classified/components/ClassifiedFilters.js +2 -2
  175. package/dist/features/classified/components/ClassifiedIndexListing.js +9 -3
  176. package/dist/features/classified/components/ClassifiedListView.js +6 -5
  177. package/dist/features/collections/components/CollectionCard.js +2 -1
  178. package/dist/features/contact/components/ContactForm.js +4 -2
  179. package/dist/features/contact/components/ContactInfoSidebar.js +4 -1
  180. package/dist/features/copilot/components/AdminCopilotView.js +13 -5
  181. package/dist/features/cron/jobs/auction-expiry.job.d.ts +2 -2
  182. package/dist/features/cron/jobs/auction-expiry.job.js +2 -1
  183. package/dist/features/cron/jobs/preorder-reminder.job.d.ts +1 -1
  184. package/dist/features/cron/jobs/preorder-reminder.job.js +2 -1
  185. package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +9 -3
  186. package/dist/features/digital-codes/components/DigitalCodesListView.js +4 -3
  187. package/dist/features/events/actions/event-actions.js +6 -4
  188. package/dist/features/events/components/AdminEventEditorView.js +63 -41
  189. package/dist/features/events/components/AdminEventEntriesView.js +9 -6
  190. package/dist/features/events/components/AdminEventsView.js +7 -5
  191. package/dist/features/events/components/EventCard.js +7 -1
  192. package/dist/features/events/components/EventFilters.d.ts +4 -4
  193. package/dist/features/events/components/EventFilters.js +2 -2
  194. package/dist/features/events/components/EventFormDrawer.js +2 -1
  195. package/dist/features/events/components/EventLeaderboard.js +4 -4
  196. package/dist/features/events/components/EventOfferCard.js +4 -1
  197. package/dist/features/events/components/EventParticipateView.js +3 -2
  198. package/dist/features/events/components/EventPollWidget.js +6 -5
  199. package/dist/features/events/components/EventRaffleEntryForm.js +5 -2
  200. package/dist/features/events/components/EventRaffleWinnerView.js +7 -1
  201. package/dist/features/events/components/EventRafflesSection.js +6 -4
  202. package/dist/features/events/components/EventSaleBanner.js +5 -2
  203. package/dist/features/events/components/EventsIndexListing.js +8 -2
  204. package/dist/features/events/components/EventsListView.js +4 -1
  205. package/dist/features/events/components/SpinWheelView.js +7 -2
  206. package/dist/features/events/schemas/firestore.d.ts +1 -0
  207. package/dist/features/events/types/index.d.ts +1 -0
  208. package/dist/features/faq/actions/faq-actions.js +4 -2
  209. package/dist/features/faq/components/ContactCTA.js +4 -1
  210. package/dist/features/faq/components/FAQCategorySidebar.js +2 -2
  211. package/dist/features/faq/components/FAQHelpfulButtons.js +8 -5
  212. package/dist/features/faq/components/FAQPageContent.js +7 -6
  213. package/dist/features/faq/components/FAQSortDropdown.js +2 -2
  214. package/dist/features/filters/AsyncFacetSection.js +4 -2
  215. package/dist/features/filters/FilterFacetSection.js +14 -6
  216. package/dist/features/filters/RangeFilter.js +4 -2
  217. package/dist/features/filters/SwitchFilter.js +2 -1
  218. package/dist/features/forms/Checkbox.js +1 -1
  219. package/dist/features/forms/Radio.js +1 -1
  220. package/dist/features/forms/Slider.js +1 -1
  221. package/dist/features/homepage/components/AdSlot.js +4 -4
  222. package/dist/features/homepage/components/AdvertisementBanner.js +13 -4
  223. package/dist/features/homepage/components/AnnouncementBar.js +2 -1
  224. package/dist/features/homepage/components/BeforeAfterCard.js +8 -2
  225. package/dist/features/homepage/components/BrandsSection.js +6 -3
  226. package/dist/features/homepage/components/CTABannerSection.js +2 -2
  227. package/dist/features/homepage/components/CharacterHotspot.js +5 -2
  228. package/dist/features/homepage/components/CharacterHotspotForm.js +8 -4
  229. package/dist/features/homepage/components/CustomCardsSection.js +13 -7
  230. package/dist/features/homepage/components/CustomerReviewsSection.js +9 -3
  231. package/dist/features/homepage/components/FAQSection.js +7 -4
  232. package/dist/features/homepage/components/FeaturedBundlesSection.js +8 -2
  233. package/dist/features/homepage/components/FeaturedResultsSection.js +1 -1
  234. package/dist/features/homepage/components/GoogleReviewsSection.js +14 -8
  235. package/dist/features/homepage/components/HeroCarousel.js +1 -1
  236. package/dist/features/homepage/components/HomepageSkeleton.js +7 -1
  237. package/dist/features/homepage/components/HowItWorksInfoView.js +2 -2
  238. package/dist/features/homepage/components/HowItWorksSection.js +2 -2
  239. package/dist/features/homepage/components/MarketplaceHomepageView.js +4 -2
  240. package/dist/features/homepage/components/NewsletterBanner.js +3 -2
  241. package/dist/features/homepage/components/NewsletterSection.js +5 -2
  242. package/dist/features/homepage/components/PromoGrid.js +4 -1
  243. package/dist/features/homepage/components/SectionCarousel.js +7 -4
  244. package/dist/features/homepage/components/SecurityHighlightsSection.js +3 -3
  245. package/dist/features/homepage/components/ShopByCategorySection.js +10 -4
  246. package/dist/features/homepage/components/SiteFeaturesSection.js +5 -2
  247. package/dist/features/homepage/components/SocialFeedSection.js +4 -4
  248. package/dist/features/homepage/components/SocialPostCard.js +6 -3
  249. package/dist/features/homepage/components/TrustFeaturesSection.js +5 -5
  250. package/dist/features/homepage/components/TrustIndicatorsSection.js +5 -2
  251. package/dist/features/homepage/components/WelcomeSection.js +1 -1
  252. package/dist/features/homepage/components/WhatsAppCommunitySection.js +3 -3
  253. package/dist/features/layout/AppLayoutShell.js +2 -1
  254. package/dist/features/layout/BackToTop.js +1 -1
  255. package/dist/features/layout/BottomActions.js +4 -30
  256. package/dist/features/layout/BottomActionsContext.d.ts +0 -36
  257. package/dist/features/layout/BottomActionsContext.js +0 -36
  258. package/dist/features/layout/BottomNavItem.js +1 -1
  259. package/dist/features/layout/BottomSheet.js +4 -1
  260. package/dist/features/layout/FooterLayout.js +1 -1
  261. package/dist/features/layout/NavbarLayout.js +4 -1
  262. package/dist/features/layout/SidebarLayout.js +5 -2
  263. package/dist/features/live/components/LiveItemFilters.js +2 -2
  264. package/dist/features/live/components/LiveItemsIndexListing.js +9 -3
  265. package/dist/features/live/components/LiveItemsListView.js +6 -5
  266. package/dist/features/loyalty/components/CoinsDisplay.js +4 -2
  267. package/dist/features/media/AvatarUpload.js +2 -2
  268. package/dist/features/media/MediaLightbox.js +3 -2
  269. package/dist/features/media/modals/VideoThumbnailSelector.js +4 -1
  270. package/dist/features/media/modals/VideoTrimModal.js +1 -1
  271. package/dist/features/media/upload/CameraCapture.js +1 -1
  272. package/dist/features/media/upload/ImageUpload.js +4 -1
  273. package/dist/features/media/upload/MediaUploadField.js +11 -2
  274. package/dist/features/media/upload/MediaUploadList.js +5 -1
  275. package/dist/features/orders/components/MarketplaceOrderCard.js +2 -2
  276. package/dist/features/orders/components/OrdersList.js +2 -1
  277. package/dist/features/orders/components/RefundHistoryTable.js +4 -1
  278. package/dist/features/orders/components/RefundRequestView.js +2 -1
  279. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +5 -1
  280. package/dist/features/pre-orders/components/PreOrderActionsClient.js +3 -3
  281. package/dist/features/pre-orders/components/PreOrderBadge.js +2 -1
  282. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +16 -7
  283. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +32 -24
  284. package/dist/features/pre-orders/components/PreOrdersListView.js +5 -4
  285. package/dist/features/products/actions/product-actions.js +17 -15
  286. package/dist/features/products/columns/index.d.ts +1 -1
  287. package/dist/features/products/columns/index.js +1 -1
  288. package/dist/features/products/columns/productTableColumns.js +9 -4
  289. package/dist/features/products/components/AuctionsIndexListing.js +9 -3
  290. package/dist/features/products/components/BidHistory.js +4 -4
  291. package/dist/features/products/components/CompareOverlay.js +10 -2
  292. package/dist/features/products/components/CustomFieldsEditor.js +2 -1
  293. package/dist/features/products/components/CustomSectionTabContent.js +2 -2
  294. package/dist/features/products/components/CustomSectionsEditor.js +3 -2
  295. package/dist/features/products/components/GroupSettingsPanel.js +34 -26
  296. package/dist/features/products/components/MakeOfferButton.js +6 -2
  297. package/dist/features/products/components/MakeOfferForm.js +2 -1
  298. package/dist/features/products/components/MarketplaceBundleCard.js +6 -3
  299. package/dist/features/products/components/MarketplacePrizeDrawCard.js +3 -2
  300. package/dist/features/products/components/PlaceBidForm.js +2 -1
  301. package/dist/features/products/components/PrizeDrawCollage.js +6 -16
  302. package/dist/features/products/components/PrizeDrawDetailPageView.js +6 -1
  303. package/dist/features/products/components/PrizeDrawItemsEditor.js +4 -2
  304. package/dist/features/products/components/PrizeDrawsIndexListing.js +6 -3
  305. package/dist/features/products/components/PrizeDrawsListingView.js +5 -4
  306. package/dist/features/products/components/PrizeDrawsSection.js +6 -4
  307. package/dist/features/products/components/PrizeRevealModal.js +5 -1
  308. package/dist/features/products/components/ProductDetailPageView.js +32 -16
  309. package/dist/features/products/components/ProductFeatureBadges.js +9 -9
  310. package/dist/features/products/components/ProductForm.d.ts +11 -1
  311. package/dist/features/products/components/ProductForm.js +10 -5
  312. package/dist/features/products/components/ProductGalleryClient.js +8 -4
  313. package/dist/features/products/components/ProductGradingTab.js +4 -1
  314. package/dist/features/products/components/ProductGrid.js +35 -14
  315. package/dist/features/products/components/ProductInfo.js +2 -1
  316. package/dist/features/products/components/ProductTabs.js +2 -1
  317. package/dist/features/products/components/ProductTabsShell.js +5 -1
  318. package/dist/features/products/components/ProductsIndexListing.js +32 -24
  319. package/dist/features/products/components/ProductsIndexPageView.js +2 -2
  320. package/dist/features/products/components/RelatedProducts.js +3 -3
  321. package/dist/features/products/components/ShowGroupSection.js +10 -6
  322. package/dist/features/products/components/SublistingCarouselSection.js +7 -3
  323. package/dist/features/products/components/SublistingCategorySelect.d.ts +3 -1
  324. package/dist/features/products/components/SublistingCategorySelect.js +4 -37
  325. package/dist/features/products/constants/action-defs.js +3 -3
  326. package/dist/features/products/constants/sieve.d.ts +2 -2
  327. package/dist/features/products/constants/sieve.js +2 -2
  328. package/dist/features/products/hooks/useRelatedProducts.js +5 -4
  329. package/dist/features/promotions/components/CouponCard.js +5 -3
  330. package/dist/features/promotions/components/CouponsIndexListing.js +7 -3
  331. package/dist/features/promotions/repository/coupons.repository.d.ts +8 -0
  332. package/dist/features/promotions/repository/coupons.repository.js +2 -0
  333. package/dist/features/reviews/actions/review-actions.js +2 -1
  334. package/dist/features/reviews/components/ReviewDetailPageView.js +3 -3
  335. package/dist/features/reviews/components/ReviewDetailShell.js +15 -3
  336. package/dist/features/reviews/components/ReviewSummary.js +4 -2
  337. package/dist/features/reviews/components/ReviewsIndexListing.js +8 -2
  338. package/dist/features/reviews/components/ReviewsIndexPageView.js +7 -6
  339. package/dist/features/reviews/components/ReviewsList.js +1 -1
  340. package/dist/features/scams/actions/scam-actions.js +3 -2
  341. package/dist/features/scams/components/ScamAwarenessModal.js +2 -2
  342. package/dist/features/scams/components/ScamProfileView.js +3 -3
  343. package/dist/features/scams/components/ScamRegistryView.js +11 -8
  344. package/dist/features/search/actions/search-actions.js +7 -6
  345. package/dist/features/search/components/Search.js +9 -6
  346. package/dist/features/search/components/SearchFiltersRow.js +1 -1
  347. package/dist/features/search/components/SearchResultsSection.js +1 -1
  348. package/dist/features/seller/components/CouponInlineSelect.d.ts +22 -0
  349. package/dist/features/seller/components/CouponInlineSelect.js +104 -0
  350. package/dist/features/seller/components/GroupInlineSelect.d.ts +23 -0
  351. package/dist/features/seller/components/GroupInlineSelect.js +80 -0
  352. package/dist/features/seller/components/PhysicalLocationModal.js +2 -1
  353. package/dist/features/seller/components/PrintCenterView.js +2 -1
  354. package/dist/features/seller/components/ProductInlineSelect.d.ts +24 -0
  355. package/dist/features/seller/components/ProductInlineSelect.js +42 -0
  356. package/dist/features/seller/components/QuickProductForm.js +4 -1
  357. package/dist/features/seller/components/SellerAddressesView.js +8 -3
  358. package/dist/features/seller/components/SellerAnalyticsAlertsView.js +6 -3
  359. package/dist/features/seller/components/SellerAnalyticsView.js +2 -2
  360. package/dist/features/seller/components/SellerAuctionsView.js +7 -5
  361. package/dist/features/seller/components/SellerBidsView.js +12 -10
  362. package/dist/features/seller/components/SellerBundlesView.js +9 -7
  363. package/dist/features/seller/components/SellerClassifiedView.js +6 -5
  364. package/dist/features/seller/components/SellerCouponEditorView.d.ts +2 -0
  365. package/dist/features/seller/components/SellerCouponEditorView.js +15 -3
  366. package/dist/features/seller/components/SellerCouponsView.js +7 -5
  367. package/dist/features/seller/components/SellerDashboardView.js +2 -2
  368. package/dist/features/seller/components/SellerDigitalCodesView.js +7 -6
  369. package/dist/features/seller/components/SellerGoogleReviewsView.js +2 -2
  370. package/dist/features/seller/components/SellerGroupedListingsView.js +10 -9
  371. package/dist/features/seller/components/SellerLiveView.js +6 -5
  372. package/dist/features/seller/components/SellerOffersView.js +6 -4
  373. package/dist/features/seller/components/SellerOrdersView.js +18 -13
  374. package/dist/features/seller/components/SellerPayoutMethodsView.js +8 -6
  375. package/dist/features/seller/components/SellerPayoutRequestView.js +5 -1
  376. package/dist/features/seller/components/SellerPayoutSettingsView.js +5 -2
  377. package/dist/features/seller/components/SellerPayoutsView.js +6 -4
  378. package/dist/features/seller/components/SellerPreOrdersView.js +12 -10
  379. package/dist/features/seller/components/SellerPrizeDrawsView.js +12 -10
  380. package/dist/features/seller/components/SellerProductShell.js +1 -1
  381. package/dist/features/seller/components/SellerProductsCards.js +4 -1
  382. package/dist/features/seller/components/SellerProductsView.js +14 -12
  383. package/dist/features/seller/components/SellerReviewsView.js +7 -3
  384. package/dist/features/seller/components/SellerShippingConfigsView.js +7 -6
  385. package/dist/features/seller/components/SellerShippingView.js +1 -1
  386. package/dist/features/seller/components/SellerSidebar.js +15 -8
  387. package/dist/features/seller/components/SellerStoreCategoriesView.js +5 -4
  388. package/dist/features/seller/components/SellerStorefrontView.js +2 -2
  389. package/dist/features/seller/components/SellerTemplatesView.js +11 -7
  390. package/dist/features/seller/components/SublistingInlineSelect.d.ts +19 -0
  391. package/dist/features/seller/components/SublistingInlineSelect.js +84 -0
  392. package/dist/features/seller/components/analytics/SellerTopProducts.js +1 -1
  393. package/dist/features/seller/components/index.d.ts +8 -0
  394. package/dist/features/seller/components/index.js +4 -0
  395. package/dist/features/shell/FormShell.js +10 -2
  396. package/dist/features/shell/QuickFormDrawer.js +5 -5
  397. package/dist/features/shell/StepForm.js +6 -6
  398. package/dist/features/site-settings/components/ActionPermissionsManager.js +8 -4
  399. package/dist/features/site-settings/components/NavPermissionsManager.js +7 -4
  400. package/dist/features/stores/actions/store-query-actions.js +3 -2
  401. package/dist/features/stores/components/InteractiveStoreCard.js +5 -1
  402. package/dist/features/stores/components/StoreAboutView.js +4 -1
  403. package/dist/features/stores/components/StoreAddressSelectorCreate.d.ts +2 -1
  404. package/dist/features/stores/components/StoreAddressSelectorCreate.js +5 -31
  405. package/dist/features/stores/components/StoreAuctionsListing.js +6 -3
  406. package/dist/features/stores/components/StoreAuctionsPageView.js +4 -2
  407. package/dist/features/stores/components/StoreDetailLayoutView.d.ts +1 -1
  408. package/dist/features/stores/components/StoreDetailLayoutView.js +7 -6
  409. package/dist/features/stores/components/StoreGuideHubView.js +5 -2
  410. package/dist/features/stores/components/StoreHeader.js +8 -1
  411. package/dist/features/stores/components/StorePreOrdersListing.js +6 -3
  412. package/dist/features/stores/components/StorePreOrdersPageView.js +4 -2
  413. package/dist/features/stores/components/StorePrizeDrawsPageView.js +4 -2
  414. package/dist/features/stores/components/StoreProductsListing.js +6 -3
  415. package/dist/features/stores/components/StoreProductsPageView.js +2 -1
  416. package/dist/features/stores/components/StoreProductsView.js +5 -4
  417. package/dist/features/stores/components/StoreReviewsListing.js +8 -2
  418. package/dist/features/stores/components/StoresIndexListing.js +16 -9
  419. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +7 -1
  420. package/dist/features/whatsapp-bot/components/WhatsAppChatButton.js +2 -1
  421. package/dist/features/wishlist/components/WishlistPage.js +2 -1
  422. package/dist/features/wishlist/components/WishlistView.js +4 -3
  423. package/dist/index.d.ts +10 -0
  424. package/dist/index.js +13 -1
  425. package/dist/next/components/GlobalError.js +2 -2
  426. package/dist/next/routing/route-map.d.ts +2 -0
  427. package/dist/next/routing/route-map.js +1 -0
  428. package/dist/react/ErrorBoundary.js +2 -2
  429. package/dist/styles.css +2 -1
  430. package/dist/tailwind-utilities.css +1 -1
  431. package/dist/ui/DataTable.js +17 -16
  432. package/dist/ui/components/DateInput.js +2 -2
  433. package/dist/ui/components/DetailPageGallery.js +4 -1
  434. package/dist/ui/components/DetailPageTabs.js +6 -2
  435. package/dist/ui/components/ImageLightbox.js +5 -3
  436. package/dist/ui/components/Input.js +6 -3
  437. package/dist/ui/components/Layout.d.ts +4 -0
  438. package/dist/ui/components/Layout.js +1 -1
  439. package/dist/ui/components/Layout.style.css +1 -0
  440. package/dist/ui/components/ListingFilterDrawer.js +4 -1
  441. package/dist/ui/components/ListingLayout.js +9 -8
  442. package/dist/ui/components/ListingToolbar.js +5 -1
  443. package/dist/ui/components/PaginatedSelect.d.ts +1 -2
  444. package/dist/ui/components/PaginatedSelect.js +1 -2
  445. package/dist/ui/components/Radio.js +1 -1
  446. package/dist/ui/components/Select.js +2 -1
  447. package/dist/ui/components/Slider.js +1 -1
  448. package/dist/ui/components/VacationBanner.js +2 -1
  449. package/dist/ui/components/surface-tokens.d.ts +1 -0
  450. package/dist/ui/components/surface-tokens.js +1 -0
  451. package/package.json +11 -2
@@ -1,7 +1,9 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit";
4
+ import { sortBy } from "@mohasinac/appkit";
3
5
  import { useState, useCallback } from "react";
4
- import { Badge, Button, Stack, Text, useToast } from "../../../ui";
6
+ import { Badge, Button, Div, Stack, Text, useToast } from "../../../ui";
5
7
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
6
8
  import { toRecordArray, toRelativeDate, toStringValue, } from "../hooks/useAdminListingData";
7
9
  import { DataListingView } from "./DataListingView";
@@ -61,16 +63,16 @@ export function AdminBundlesView({ getEditHref, newHref }) {
61
63
  searchPlaceholder: "Search bundles by name or slug…",
62
64
  emptyLabel: BUNDLE_COPY.adminList.empty,
63
65
  filterKeys: ["isActive", "bundleStockStatus"],
64
- defaultSort: "name",
66
+ defaultSort: sortBy("name", "ASC"),
65
67
  queryKey: ["admin", "bundles", "listing"],
66
68
  endpoint: ADMIN_ENDPOINTS.BUNDLES,
67
69
  sortOptions: [
68
- { value: "name", label: "Name A–Z" },
69
- { value: "-name", label: "Name Z–A" },
70
- { value: "-bundlePriceInPaise", label: "Price high→low" },
70
+ { value: sortBy("name", "ASC"), label: "Name A–Z" },
71
+ { value: sortBy("name", "DESC"), label: "Name Z–A" },
72
+ { value: sortBy("bundlePriceInPaise", "DESC"), label: "Price high→low" },
71
73
  { value: "bundlePriceInPaise", label: "Price low→high" },
72
- { value: "-createdAt", label: "Newest" },
73
- { value: "createdAt", label: "Oldest" },
74
+ { value: sortBy("createdAt", "DESC"), label: "Newest" },
75
+ { value: sortBy("createdAt", "ASC"), label: "Oldest" },
74
76
  ],
75
77
  columns: COLUMNS,
76
78
  mapRows: (response) => toRecordArray(response.items).map((item, index) => ({
@@ -90,9 +92,9 @@ export function AdminBundlesView({ getEditHref, newHref }) {
90
92
  buildFilters: (filterState) => {
91
93
  const parts = [];
92
94
  if (filterState.isActive)
93
- parts.push(`isActive==${filterState.isActive}`);
95
+ parts.push(sieveFilter("isActive", SIEVE_OP.EQ, filterState.isActive));
94
96
  if (filterState.bundleStockStatus)
95
- parts.push(`bundleStockStatus==${filterState.bundleStockStatus}`);
97
+ parts.push(sieveFilter("bundleStockStatus", SIEVE_OP.EQ, filterState.bundleStockStatus));
96
98
  return parts.join(",") || undefined;
97
99
  },
98
100
  getRowHref: getEditHref,
@@ -120,13 +122,13 @@ export function AdminBundlesView({ getEditHref, newHref }) {
120
122
  }),
121
123
  ],
122
124
  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 })),
123
- renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(_Fragment, { 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: [
125
+ renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(_Fragment, { 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: [
124
126
  { label: "All", value: "" },
125
127
  { label: "Active", value: "true" },
126
128
  { label: "Inactive", value: "false" },
127
129
  ].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
128
130
  ? "bg-primary text-white border-primary"
129
- : "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: "Stock" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [
131
+ : "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: "Stock" }), _jsx(Div, { className: "flex flex-wrap gap-2", children: [
130
132
  { label: "All", value: "" },
131
133
  { label: "Sold out", value: "out_of_stock" },
132
134
  ].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, bundleStockStatus: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.bundleStockStatus || "") === opt.value
@@ -7,6 +7,9 @@ import { FieldInput, FormShellContext, useFormShellState } from "../../../ui/for
7
7
  import { apiClient } from "../../../http";
8
8
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
9
9
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
10
+ const __P = {
11
+ p3: "p-3",
12
+ };
10
13
  const CLS_PANEL = "rounded-xl border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-900 p-4 space-y-3";
11
14
  const CLS_ROW_BETWEEN = "flex items-center justify-between";
12
15
  const CLS_SECTION_HEADING = "text-sm font-semibold text-zinc-900 dark:text-zinc-100";
@@ -68,7 +71,7 @@ function ZonePicker({ selected, onChange, disabled, }) {
68
71
  // ── Background Editor ────────────────────────────────────────────────────────
69
72
  function BackgroundEditor({ value, onChange, prefix, }) {
70
73
  const set = (patch) => onChange({ ...value, ...patch });
71
- return (_jsxs(Div, { className: "space-y-3", children: [_jsx(Select, { label: "Background type", value: value.type, onChange: (e) => onChange({ type: e.target.value }), options: BG_TYPE_OPTIONS }), (value.type === "image" || value.type === "video") && (_jsxs(_Fragment, { children: [_jsx(Input, { label: `${value.type === "image" ? "Image" : "Video"} URL`, value: value.url ?? "", onChange: (e) => set({ url: e.target.value }), placeholder: "https://..." }), _jsx(Input, { label: "Mobile URL (optional)", value: value.mobileUrl ?? "", onChange: (e) => set({ mobileUrl: e.target.value || undefined }), placeholder: "https://... (portrait crop)" }), value.type === "video" && (_jsx(Input, { label: "Poster / thumbnail URL", value: value.thumbnail ?? "", onChange: (e) => set({ thumbnail: e.target.value || undefined }), placeholder: "https://..." })), _jsxs(Div, { className: "space-y-2 rounded-lg border border-zinc-200 dark:border-zinc-800 p-3", children: [_jsx(Toggle, { label: "Dim overlay", checked: value.dimOverlay?.enabled ?? false, onChange: (v) => set({ dimOverlay: { enabled: v, opacity: value.dimOverlay?.opacity ?? 40 } }) }), value.dimOverlay?.enabled && (_jsxs(Div, { children: [_jsxs(Text, { className: "text-sm font-medium mb-1", children: ["Opacity (", value.dimOverlay.opacity, "%)"] }), _jsx("input", { type: "range", min: 0, max: 90, step: 5, value: value.dimOverlay.opacity, onChange: (e) => set({ dimOverlay: { enabled: true, opacity: Number(e.target.value) } }), className: "w-full" })] }))] })] })), value.type === "color" && (_jsx(Input, { label: "Colour (CSS token or hex)", value: value.color ?? "", onChange: (e) => set({ color: e.target.value }), placeholder: "var(--appkit-color-primary) or #1a1a2e" })), value.type === "gradient" && (_jsxs(_Fragment, { children: [_jsx(Input, { label: "From colour", value: value.gradientFrom ?? "", onChange: (e) => set({ gradientFrom: e.target.value }), placeholder: "var(--appkit-color-primary)" }), _jsx(Input, { label: "To colour", value: value.gradientTo ?? "", onChange: (e) => set({ gradientTo: e.target.value }), placeholder: "var(--appkit-color-secondary)" }), _jsx(Input, { label: "Angle (degrees)", type: "number", value: String(value.gradientAngle ?? 135), onChange: (e) => set({ gradientAngle: Number(e.target.value) }), min: 0, max: 360 })] }))] }));
74
+ return (_jsxs(Div, { className: "space-y-3", children: [_jsx(Select, { label: "Background type", value: value.type, onChange: (e) => onChange({ type: e.target.value }), options: BG_TYPE_OPTIONS }), (value.type === "image" || value.type === "video") && (_jsxs(_Fragment, { children: [_jsx(Input, { label: `${value.type === "image" ? "Image" : "Video"} URL`, value: value.url ?? "", onChange: (e) => set({ url: e.target.value }), placeholder: "https://..." }), _jsx(Input, { label: "Mobile URL (optional)", value: value.mobileUrl ?? "", onChange: (e) => set({ mobileUrl: e.target.value || undefined }), placeholder: "https://... (portrait crop)" }), value.type === "video" && (_jsx(Input, { label: "Poster / thumbnail URL", value: value.thumbnail ?? "", onChange: (e) => set({ thumbnail: e.target.value || undefined }), placeholder: "https://..." })), _jsxs(Div, { className: `space-y-2 rounded-lg border border-zinc-200 dark:border-zinc-800 ${__P.p3}`, children: [_jsx(Toggle, { label: "Dim overlay", checked: value.dimOverlay?.enabled ?? false, onChange: (v) => set({ dimOverlay: { enabled: v, opacity: value.dimOverlay?.opacity ?? 40 } }) }), value.dimOverlay?.enabled && (_jsxs(Div, { children: [_jsxs(Text, { className: "text-sm font-medium mb-1", children: ["Opacity (", value.dimOverlay.opacity, "%)"] }), _jsx("input", { type: "range", min: 0, max: 90, step: 5, value: value.dimOverlay.opacity, onChange: (e) => set({ dimOverlay: { enabled: true, opacity: Number(e.target.value) } }), className: "w-full" })] }))] })] })), value.type === "color" && (_jsx(Input, { label: "Colour (CSS token or hex)", value: value.color ?? "", onChange: (e) => set({ color: e.target.value }), placeholder: "var(--appkit-color-primary) or #1a1a2e" })), value.type === "gradient" && (_jsxs(_Fragment, { children: [_jsx(Input, { label: "From colour", value: value.gradientFrom ?? "", onChange: (e) => set({ gradientFrom: e.target.value }), placeholder: "var(--appkit-color-primary)" }), _jsx(Input, { label: "To colour", value: value.gradientTo ?? "", onChange: (e) => set({ gradientTo: e.target.value }), placeholder: "var(--appkit-color-secondary)" }), _jsx(Input, { label: "Angle (degrees)", type: "number", value: String(value.gradientAngle ?? 135), onChange: (e) => set({ gradientAngle: Number(e.target.value) }), min: 0, max: 360 })] }))] }));
72
75
  }
73
76
  // ── Card Editor ──────────────────────────────────────────────────────────────
74
77
  function CardEditor({ card, index, otherZones, onChange, onRemove, }) {
@@ -80,7 +83,7 @@ function CardEditor({ card, index, otherZones, onChange, onRemove, }) {
80
83
  { value: "", label: "— inherit desktop zone —" },
81
84
  { value: "2", label: "Zone 2 (row 1, center)" },
82
85
  { value: "5", label: "Zone 5 (row 2, center)" },
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 }) })] }));
86
+ ] }), _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.p3} 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 }) })] }));
84
87
  }
85
88
  // ── Main Editor ──────────────────────────────────────────────────────────────
86
89
  export function AdminCarouselEditorView({ slideId, onSaved, onDeleted, onCancel, ...rest }) {
@@ -207,7 +210,7 @@ export function AdminCarouselEditorView({ slideId, onSaved, onDeleted, onCancel,
207
210
  return;
208
211
  }
209
212
  saveMutation.mutate();
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: () => {
213
+ }, 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.p3} 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: () => {
211
214
  const usedZones = cards.map((c) => c.zone);
212
215
  const freeZone = [1, 2, 3, 4, 5, 6].find((z) => !usedZones.includes(z)) ?? 1;
213
216
  setCards([...cards, makeCard(freeZone)]);
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import React, { useState, useCallback } from "react";
4
4
  import { useMutation, useQueryClient } from "@tanstack/react-query";
5
- import { BulkActionBar, ConfirmDeleteModal, ListingFilterDrawer, ListingToolbar, ListingLayout, Pagination, Text } from "../../../ui";
5
+ import { BulkActionBar, Button, ConfirmDeleteModal, Div, ListingFilterDrawer, ListingToolbar, ListingLayout, Pagination, Span, Text } from "../../../ui";
6
6
  import { useBottomActions } from "../../layout";
7
7
  import { ADMIN_ENDPOINTS, HOMEPAGE_ENDPOINTS } from "../../../constants/api-endpoints";
8
8
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
@@ -102,7 +102,7 @@ export function AdminCarouselView({ children, onBulkDelete, ...props }) {
102
102
  }
103
103
  const displayRows = (localRows.length > 0 ? localRows : fetchedRows).map((row) => ({
104
104
  ...row,
105
- secondary: (_jsxs("div", { className: "flex items-center gap-3", children: [row.thumbnailUrl && (_jsx("img", { src: row.thumbnailUrl, alt: "", className: "w-14 h-9 object-cover rounded flex-shrink-0 bg-zinc-200 dark:bg-zinc-800" })), _jsx("span", { className: "text-sm text-zinc-500 dark:text-zinc-400 truncate", children: row.secondary })] })),
105
+ secondary: (_jsxs(Div, { className: "flex items-center gap-3", children: [row.thumbnailUrl && (_jsx("img", { src: row.thumbnailUrl, alt: "", className: "w-14 h-9 object-cover rounded flex-shrink-0 bg-zinc-200 dark:bg-zinc-800" })), _jsx(Span, { size: "sm", className: "text-zinc-500 dark:text-zinc-400 truncate", children: row.secondary })] })),
106
106
  }));
107
107
  const columns = [
108
108
  {
@@ -113,7 +113,7 @@ export function AdminCarouselView({ children, onBulkDelete, ...props }) {
113
113
  {
114
114
  key: "primary",
115
115
  header: "Title",
116
- render: (row) => _jsx("span", { className: "font-medium text-zinc-900 dark:text-zinc-100", children: row.primary }),
116
+ render: (row) => _jsx(Span, { weight: "medium", className: "text-zinc-900 dark:text-zinc-100", children: row.primary }),
117
117
  },
118
118
  {
119
119
  key: "secondary",
@@ -123,12 +123,12 @@ export function AdminCarouselView({ children, onBulkDelete, ...props }) {
123
123
  {
124
124
  key: "status",
125
125
  header: "Status",
126
- 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 })),
126
+ render: (row) => (_jsx(Span, { size: "xs", weight: "medium", className: `inline-flex items-center rounded-full px-2 py-0.5 ${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 })),
127
127
  },
128
128
  {
129
129
  key: "updatedAt",
130
130
  header: "Updated",
131
- render: (row) => _jsx("span", { className: "text-sm text-zinc-500 dark:text-zinc-400", children: row.updatedAt }),
131
+ render: (row) => _jsx(Span, { size: "sm", className: "text-zinc-500 dark:text-zinc-400", children: row.updatedAt }),
132
132
  },
133
133
  {
134
134
  key: "actions",
@@ -143,5 +143,5 @@ export function AdminCarouselView({ children, onBulkDelete, ...props }) {
143
143
  ] })),
144
144
  },
145
145
  ];
146
- 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-error/20 bg-error-surface px-4 py-3 text-sm text-error", 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(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearFilters, activeCount: activeFilterCount, 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))) })] }) }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Carousel Slide", message: "Delete this carousel slide? This cannot be undone.", onConfirm: () => { deleteMutation.mutate(deleteTargetId); setDeleteTargetId(null); }, onClose: () => setDeleteTargetId(null), isDeleting: deleteMutation.isPending }))] }));
146
+ 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-error/20 bg-error-surface px-4 py-3 text-sm text-error", 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(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearFilters, activeCount: activeFilterCount, 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, { variant: "ghost", type: "button", onClick: () => setPendingFilters((p) => ({ ...p, active: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors min-h-0 h-auto ${(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))) })] }) }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Carousel Slide", message: "Delete this carousel slide? This cannot be undone.", onConfirm: () => { deleteMutation.mutate(deleteTargetId); setDeleteTargetId(null); }, onClose: () => setDeleteTargetId(null), isDeleting: deleteMutation.isPending }))] }));
147
147
  }
@@ -1,5 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit";
4
+ import { sortBy } from "@mohasinac/appkit";
3
5
  import React from "react";
4
6
  import { FilterChipGroup, ListingLayout } from "../../../ui";
5
7
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
@@ -12,12 +14,12 @@ const ADMIN_CARTS_CONFIG = {
12
14
  searchPlaceholder: "Search by user ID or session",
13
15
  emptyLabel: "No carts found",
14
16
  filterKeys: ["type"],
15
- defaultSort: "-updatedAt",
17
+ defaultSort: sortBy("updatedAt", "DESC"),
16
18
  queryKey: ["admin", "carts", "listing"],
17
19
  endpoint: ADMIN_ENDPOINTS.ADMIN_CARTS,
18
20
  sortOptions: [
19
- { value: "-updatedAt", label: "Recently updated" },
20
- { value: "updatedAt", label: "Oldest" },
21
+ { value: sortBy("updatedAt", "DESC"), label: "Recently updated" },
22
+ { value: sortBy("updatedAt", "ASC"), label: "Oldest" },
21
23
  ],
22
24
  mapRows: (response) => toRecordArray(response.items).map((item, index) => {
23
25
  const isGuest = !item.userId;
@@ -34,7 +36,7 @@ const ADMIN_CARTS_CONFIG = {
34
36
  };
35
37
  }),
36
38
  getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
37
- buildFilters: (state) => state.type && state.type !== "All" ? `type==${state.type}` : undefined,
39
+ buildFilters: (state) => state.type && state.type !== "All" ? sieveFilter("type", SIEVE_OP.EQ, state.type) : undefined,
38
40
  renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsx(FilterChipGroup, { label: "Type", tabs: ADMIN_CART_OWNERSHIP_TABS, value: pendingFilters.type ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, type: id })) })),
39
41
  };
40
42
  export function AdminCartsView({ children, ...props }) {
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Package, FolderTree, Tag, Star, AlertTriangle } from "lucide-react";
3
3
  import { Div, Heading, Span, Text, Section, Alert } from "../../../ui";
4
4
  import { GC } from "../../_guide-cls";
5
+ const CLS_CODE = "text-xs bg-amber-100 dark:bg-amber-900/30 px-1 rounded";
5
6
  export function AdminCatalogGuideView() {
6
7
  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
8
  {
@@ -22,7 +23,7 @@ export function AdminCatalogGuideView() {
22
23
  },
23
24
  {
24
25
  Icon: AlertTriangle, title: "Common Admin Mistakes",
25
- content: (_jsx(Alert, { variant: "warning", children: _jsxs("ul", { className: "space-y-1 text-sm", children: [_jsx("li", { children: "\u2717 Publishing a product with no images \u2014 buyers cannot evaluate it." }), _jsxs("li", { children: ["\u2717 Creating a subcategory without setting ", _jsx("code", { className: "text-xs bg-amber-100 dark:bg-amber-900/30 px-1 rounded", children: "rootId" }), " \u2014 category tree breaks."] }), _jsxs("li", { children: ["\u2717 Setting ", _jsx("code", { className: "text-xs bg-amber-100 dark:bg-amber-900/30 px-1 rounded", children: "parentId" }), " of a root category to anything other than ", _jsx("code", { className: "text-xs bg-amber-100 dark:bg-amber-900/30 px-1 rounded", children: "null" }), " \u2014 creates circular hierarchy."] }), _jsx("li", { children: "\u2717 Duplicating brand slugs \u2014 Firestore document ID collision, second write silently overwrites the first." }), _jsx("li", { children: "\u2717 Writing raw Firebase Storage URLs to Firestore \u2014 breaks the media watermark proxy and CDN caching." })] }) })),
26
+ content: (_jsx(Alert, { variant: "warning", children: _jsxs("ul", { className: "space-y-1 text-sm", children: [_jsx("li", { children: "\u2717 Publishing a product with no images \u2014 buyers cannot evaluate it." }), _jsxs("li", { children: ["\u2717 Creating a subcategory without setting ", _jsx("code", { className: CLS_CODE, children: "rootId" }), " \u2014 category tree breaks."] }), _jsxs("li", { children: ["\u2717 Setting ", _jsx("code", { className: CLS_CODE, children: "parentId" }), " of a root category to anything other than ", _jsx("code", { className: CLS_CODE, children: "null" }), " \u2014 creates circular hierarchy."] }), _jsx("li", { children: "\u2717 Duplicating brand slugs \u2014 Firestore document ID collision, second write silently overwrites the first." }), _jsx("li", { children: "\u2717 Writing raw Firebase Storage URLs to Firestore \u2014 breaks the media watermark proxy and CDN caching." })] }) })),
26
27
  },
27
28
  ].map(({ Icon, title, content }) => (_jsxs(Section, { className: "rounded-2xl border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] overflow-hidden", children: [_jsxs(Div, { className: "flex items-center gap-3 px-6 py-4 border-b border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-2,var(--appkit-color-border))]/20", children: [_jsx(Icon, { className: "w-5 h-5 text-[var(--appkit-color-primary)]" }), _jsx(Heading, { level: 2, className: "text-base font-semibold text-[var(--appkit-color-text)]", children: title })] }), _jsx(Div, { className: "px-6 py-5", children: content })] }, title)))] }));
28
29
  }
@@ -1,7 +1,9 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit";
4
+ import { sortBy } from "@mohasinac/appkit";
3
5
  import React from "react";
4
- import { Heading, ListingLayout, Span, Text } from "../../../ui";
6
+ import { Div, Heading, ListingLayout, Span, Text } from "../../../ui";
5
7
  import { CATEGORY_ENDPOINTS } from "../../../constants/api-endpoints";
6
8
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
7
9
  import { toRecordArray, toRelativeDate, toStringValue, } from "../hooks/useAdminListingData";
@@ -12,13 +14,13 @@ const COLUMNS = [
12
14
  key: "primary",
13
15
  header: "Category",
14
16
  sortable: true,
15
- render: (row) => (_jsxs("div", { className: "space-y-1", children: [_jsx(Text, { className: "font-semibold text-zinc-900 dark:text-zinc-100", children: row.primary }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: row.secondary })] })),
17
+ render: (row) => (_jsxs(Div, { className: "space-y-1", children: [_jsx(Text, { className: "font-semibold text-zinc-900 dark:text-zinc-100", children: row.primary }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: row.secondary })] })),
16
18
  },
17
19
  {
18
20
  key: "status",
19
21
  header: "Status",
20
22
  className: "w-32",
21
- render: (row) => (_jsx(Span, { className: "inline-flex rounded-full bg-primary-50 px-2.5 py-1 text-xs font-medium text-primary-800 dark:bg-secondary-900/30 dark:text-secondary-300", children: row.status })),
23
+ render: (row) => (_jsx(Span, { size: "xs", weight: "medium", className: "inline-flex rounded-full bg-primary-50 px-2.5 py-1 text-primary-800 dark:bg-secondary-900/30 dark:text-secondary-300", children: row.status })),
22
24
  },
23
25
  {
24
26
  key: "updatedAt",
@@ -33,14 +35,14 @@ const ADMIN_CATEGORIES_CONFIG = {
33
35
  searchPlaceholder: "Search categories, slugs, or parent category",
34
36
  emptyLabel: "No categories found",
35
37
  filterKeys: ["isActive", "isFeatured"],
36
- defaultSort: "name",
38
+ defaultSort: sortBy("name", "ASC"),
37
39
  pageSize: 50,
38
40
  queryKey: ["admin", "categories", "listing"],
39
41
  endpoint: `${CATEGORY_ENDPOINTS.LIST}?flat=true`,
40
42
  sortOptions: [
41
- { value: "name", label: "Name A–Z" },
42
- { value: "-name", label: "Name Z–A" },
43
- { value: "-createdAt", label: "Newest" },
43
+ { value: sortBy("name", "ASC"), label: "Name A–Z" },
44
+ { value: sortBy("name", "DESC"), label: "Name Z–A" },
45
+ { value: sortBy("createdAt", "DESC"), label: "Newest" },
44
46
  ],
45
47
  columns: COLUMNS,
46
48
  mapRows: (response) => {
@@ -61,7 +63,7 @@ const ADMIN_CATEGORIES_CONFIG = {
61
63
  buildFilters: (state) => {
62
64
  const parts = [];
63
65
  if (state.isActive)
64
- parts.push(`isActive==${state.isActive}`);
66
+ parts.push(sieveFilter("isActive", SIEVE_OP.EQ, state.isActive));
65
67
  if (state.isFeatured === "true")
66
68
  parts.push("isFeatured==true");
67
69
  return parts.join(",") || undefined;
@@ -83,13 +85,13 @@ const ADMIN_CATEGORIES_CONFIG = {
83
85
  },
84
86
  },
85
87
  ],
86
- renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(_Fragment, { 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: [
88
+ renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(_Fragment, { 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: [
87
89
  { label: "All", value: "" },
88
90
  { label: "Active", value: "true" },
89
91
  { label: "Inactive", value: "false" },
90
92
  ].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
91
93
  ? "bg-primary text-white border-primary"
92
- : "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: [
94
+ : "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: [
93
95
  { label: "All", value: "" },
94
96
  { label: "Featured only", value: "true" },
95
97
  ].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
@@ -2,11 +2,17 @@
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 { Button, Card, CardBody, ConfirmDeleteModal, Form, PaginatedSelect, Input, StackedViewShell, Text, Toggle, useToast } from "../../../ui";
5
+ import { Button, Card, CardBody, ConfirmDeleteModal, Div, Form, PaginatedSelect, Input, StackedViewShell, Text, Toggle, useToast } from "../../../ui";
6
6
  import { apiClient } from "../../../http";
7
7
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
8
8
  import { CategoryQuickCreateForm } from "./CategoryQuickCreateForm";
9
9
  import { FieldInput, FormShellContext, useFormShellState } from "../../../ui/forms";
10
+ const __P = {
11
+ p4: "p-4",
12
+ };
13
+ const __O = {
14
+ yAuto: "overflow-y-auto",
15
+ };
10
16
  async function loadCategoryOptions(query, page) {
11
17
  const params = new URLSearchParams({ page: String(page), pageSize: "25" });
12
18
  if (query)
@@ -111,13 +117,13 @@ export function AdminCategoryEditorView({ categoryId, onSaved, onDeleted, embedd
111
117
  return;
112
118
  }
113
119
  saveMutation.mutate();
114
- }, className: "space-y-6", children: [_jsxs(Card, { variant: "outlined", padding: "lg", children: [_jsx(Text, { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400 mb-4", children: "Identity" }), _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "grid sm:grid-cols-2 gap-4", children: [_jsx(FieldInput, { name: "name", label: "Category name", value: name, onChange: (v) => handleNameChange(v), required: true, placeholder: "e.g. Toys & Games" }), _jsx(Input, { label: "Slug", value: slug, onChange: (e) => {
120
+ }, className: "space-y-6", children: [_jsxs(Card, { variant: "outlined", padding: "lg", children: [_jsx(Text, { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400 mb-4", children: "Identity" }), _jsxs(Div, { className: "space-y-4", children: [_jsxs(Div, { className: "grid sm:grid-cols-2 gap-4", children: [_jsx(FieldInput, { name: "name", label: "Category name", value: name, onChange: (v) => handleNameChange(v), required: true, placeholder: "e.g. Toys & Games" }), _jsx(Input, { label: "Slug", value: slug, onChange: (e) => {
115
121
  setSlug(e.target.value);
116
122
  setSlugManual(true);
117
- }, placeholder: "toys-and-games", helperText: "Auto-generated from name. Used in URLs." })] }), _jsx(Input, { label: "Description", value: description, onChange: (e) => setDescription(e.target.value), placeholder: "Brief description of the category" }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Text, { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Parent category" }), _jsx(PaginatedSelect, { value: parentId || null, onChange: (v) => setParentId(v ?? ""), loadOptions: loadCategoryOptions, placeholder: "Search categories\u2026 (leave empty for root)", searchPlaceholder: "Type category name\u2026", noResultsText: "No categories found", ariaLabel: "Parent category", createLabel: "Category", renderCreateForm: ({ onCreated, onCancel }) => (_jsx(CategoryQuickCreateForm, { onSaved: (id, n) => { setParentId(id); onCreated({ value: id, label: n }); }, onCancel: onCancel })) }), _jsx(Text, { className: "text-xs text-neutral-500 dark:text-neutral-400", children: "Leave empty to create a root category." })] })] })] }), _jsxs(Card, { variant: "outlined", padding: "lg", children: [_jsx(Text, { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400 mb-4", children: "Display" }), _jsxs("div", { className: "space-y-4", children: [_jsx(Input, { label: "Display order", value: order, onChange: (e) => setOrder(e.target.value), type: "number", min: 0, placeholder: "0" }), _jsx(Toggle, { label: "Active", checked: isActive, onChange: setIsActive }), _jsx(Toggle, { label: "Show in menu", checked: showInMenu, onChange: setShowInMenu })] })] }), _jsxs("div", { className: "flex gap-3 lg:hidden", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !name || isSubmitting, children: isEdit ? "Save changes" : "Create category" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => setDeleteOpen(true), children: "Delete category" }))] })] }, "cat-form") }));
123
+ }, placeholder: "toys-and-games", helperText: "Auto-generated from name. Used in URLs." })] }), _jsx(Input, { label: "Description", value: description, onChange: (e) => setDescription(e.target.value), placeholder: "Brief description of the category" }), _jsxs(Div, { className: "flex flex-col gap-1", children: [_jsx(Text, { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Parent category" }), _jsx(PaginatedSelect, { value: parentId || null, onChange: (v) => setParentId(v ?? ""), loadOptions: loadCategoryOptions, placeholder: "Search categories\u2026 (leave empty for root)", searchPlaceholder: "Type category name\u2026", noResultsText: "No categories found", ariaLabel: "Parent category", createLabel: "Category", renderCreateForm: ({ onCreated, onCancel }) => (_jsx(CategoryQuickCreateForm, { onSaved: (id, n) => { setParentId(id); onCreated({ value: id, label: n }); }, onCancel: onCancel })) }), _jsx(Text, { className: "text-xs text-neutral-500 dark:text-neutral-400", children: "Leave empty to create a root category." })] })] })] }), _jsxs(Card, { variant: "outlined", padding: "lg", children: [_jsx(Text, { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400 mb-4", children: "Display" }), _jsxs(Div, { className: "space-y-4", children: [_jsx(Input, { label: "Display order", value: order, onChange: (e) => setOrder(e.target.value), type: "number", min: 0, placeholder: "0" }), _jsx(Toggle, { label: "Active", checked: isActive, onChange: setIsActive }), _jsx(Toggle, { label: "Show in menu", checked: showInMenu, onChange: setShowInMenu })] })] }), _jsxs(Div, { className: "flex gap-3 lg:hidden", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !name || isSubmitting, children: isEdit ? "Save changes" : "Create category" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => setDeleteOpen(true), children: "Delete category" }))] })] }, "cat-form") }));
118
124
  if (embedded) {
119
- return _jsx("div", { className: "overflow-y-auto p-4", children: formContent });
125
+ return _jsx(Div, { className: `${__O.yAuto} ${__P.p4}`, children: formContent });
120
126
  }
121
- const twoPanel = (_jsxs("div", { className: "grid gap-6 lg:grid-cols-[1fr_280px] lg:items-start", children: [_jsx(CardBody, { className: "min-w-0 space-y-6 p-0", children: formContent }), _jsx("div", { className: "hidden lg:block lg:sticky lg:top-[var(--header-height,0px)]", children: actionSidebar })] }));
127
+ const twoPanel = (_jsxs(Div, { className: "grid gap-6 lg:grid-cols-[1fr_280px] lg:items-start", children: [_jsx(CardBody, { className: "min-w-0 space-y-6 p-0", children: formContent }), _jsx(Div, { className: "hidden lg:block lg:sticky lg:top-[var(--header-height,0px)]", children: actionSidebar })] }));
122
128
  return (_jsxs(_Fragment, { children: [_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Category" : "Create Category", sections: [twoPanel] }), _jsx(ConfirmDeleteModal, { isOpen: deleteOpen, onClose: () => setDeleteOpen(false), onConfirm: () => deleteMutation.mutate(), isDeleting: deleteMutation.isPending, title: "Delete this category?", message: "Products in this category will become uncategorized. This action cannot be undone.", confirmText: "Delete category", variant: "danger" })] }));
123
129
  }
@@ -4,6 +4,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
4
4
  * AdminClassifiedView — admin browse of classified listings (W1-29).
5
5
  * Read-only summary with edit-handoff to the seller-portal edit route.
6
6
  */
7
+ import { sortBy } from "@mohasinac/appkit";
7
8
  import React from "react";
8
9
  import { ListingLayout } from "../../../ui";
9
10
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
@@ -15,12 +16,12 @@ const ADMIN_CLASSIFIED_CONFIG = {
15
16
  searchPlaceholder: "Search classified by name or seller",
16
17
  emptyLabel: "No classified listings",
17
18
  filterKeys: [],
18
- defaultSort: "-createdAt",
19
+ defaultSort: sortBy("createdAt", "DESC"),
19
20
  queryKey: ["admin", "classified", "listing"],
20
21
  endpoint: ADMIN_ENDPOINTS.PRODUCTS,
21
22
  sortOptions: [
22
- { value: "-createdAt", label: "Newest" },
23
- { value: "createdAt", label: "Oldest" },
23
+ { value: sortBy("createdAt", "DESC"), label: "Newest" },
24
+ { value: sortBy("createdAt", "ASC"), label: "Oldest" },
24
25
  { value: "title", label: "Title A–Z" },
25
26
  ],
26
27
  mapRows: (response) => toRecordArray(response.items).map((item, index) => ({
@@ -4,6 +4,13 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
4
4
  import { Button, Div, FormActions, SideDrawer, Text, useToast, } from "../../../ui";
5
5
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
6
6
  import { apiClient } from "../../../http";
7
+ const __P = {
8
+ p3: "p-3",
9
+ p4: "p-4",
10
+ };
11
+ const __O = {
12
+ yAuto: "overflow-y-auto",
13
+ };
7
14
  export function AdminContactEditorView({ open, onClose, submissionId, subject, name, email, message, currentStatus, }) {
8
15
  const queryClient = useQueryClient();
9
16
  const { showToast } = useToast();
@@ -26,7 +33,7 @@ export function AdminContactEditorView({ open, onClose, submissionId, subject, n
26
33
  read: "bg-zinc-100 text-zinc-600 dark:bg-zinc-800 dark:text-zinc-400",
27
34
  resolved: "bg-success-surface text-success",
28
35
  };
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: () => {
36
+ return (_jsx(SideDrawer, { isOpen: open, onClose: onClose, title: subject ?? "Contact Submission", children: _jsxs(Div, { className: `flex flex-col gap-5 ${__P.p4}`, 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.p3} max-h-64 ${__O.yAuto}`, 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
37
  window.location.href = `mailto:${email}?subject=Re: ${encodeURIComponent(subject ?? "")}`;
31
38
  }, children: "Reply via email" })), _jsx(Button, { type: "button", variant: "secondary", onClick: onClose, children: "Close" }), _jsx(Button, { type: "button", variant: "secondary", disabled: !submissionId || actionMutation.isPending || currentStatus === "read" || currentStatus === "resolved", isLoading: actionMutation.isPending && actionMutation.variables === "read", onClick: () => actionMutation.mutate("read"), children: "Mark read" }), _jsx(Button, { type: "button", disabled: !submissionId || actionMutation.isPending || currentStatus === "resolved", isLoading: actionMutation.isPending && actionMutation.variables === "resolved", onClick: () => actionMutation.mutate("resolved"), children: "Archive" })] })] }) }));
32
39
  }
@@ -1,5 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit";
4
+ import { sortBy } from "@mohasinac/appkit";
3
5
  import React, { useState } from "react";
4
6
  import { useMutation, useQueryClient } from "@tanstack/react-query";
5
7
  import { ConfirmDeleteModal, FilterChipGroup, ListingLayout, RowActionMenu, useToast } from "../../../ui";
@@ -53,12 +55,12 @@ export function AdminContactView({ children, onBulkMarkRead, onBulkArchive, onBu
53
55
  searchPlaceholder: "Search by subject, name, or email",
54
56
  emptyLabel: "No contact submissions found",
55
57
  filterKeys: ["status"],
56
- defaultSort: "-createdAt",
58
+ defaultSort: sortBy("createdAt", "DESC"),
57
59
  queryKey: ["admin", "contact", "listing"],
58
60
  endpoint: ADMIN_ENDPOINTS.CONTACT_SUBMISSIONS,
59
61
  sortOptions: [
60
- { value: "-createdAt", label: "Newest" },
61
- { value: "createdAt", label: "Oldest" },
62
+ { value: sortBy("createdAt", "DESC"), label: "Newest" },
63
+ { value: sortBy("createdAt", "ASC"), label: "Oldest" },
62
64
  ],
63
65
  mapRows: (response) => toRecordArray(response.submissions).map((item, index) => ({
64
66
  id: toStringValue(item.id, `msg-${index}`),
@@ -77,7 +79,7 @@ export function AdminContactView({ children, onBulkMarkRead, onBulkArchive, onBu
77
79
  return response.meta.total;
78
80
  return mappedRows.length;
79
81
  },
80
- buildFilters: (f) => (f.status && f.status !== "All" ? `status==${f.status}` : undefined),
82
+ buildFilters: (f) => (f.status && f.status !== "All" ? sieveFilter("status", SIEVE_OP.EQ, f.status) : undefined),
81
83
  buildBulkActions: (selection) => [
82
84
  ...(onBulkMarkRead
83
85
  ? [
@@ -2,10 +2,18 @@
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 { Button, ConfirmDeleteModal, Form, Input, Select, StackedViewShell, Toggle, useToast, } from "../../../ui";
5
+ import { Button, ConfirmDeleteModal, Div, Form, Input, Label, Select, StackedViewShell, Span, Text, Toggle, useToast, } 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 { ProductInlineSelect } from "../../seller/components/ProductInlineSelect";
10
+ import { CategoryInlineSelect } from "../../seller/components/CategoryInlineSelect";
11
+ const __P = {
12
+ p4: "p-4",
13
+ };
14
+ const __O = {
15
+ yAuto: "overflow-y-auto",
16
+ };
9
17
  const TYPE_OPTIONS = [
10
18
  { label: "Percentage Discount", value: "percentage" },
11
19
  { label: "Fixed Amount Discount", value: "fixed" },
@@ -27,10 +35,10 @@ function toDateInputValue(val) {
27
35
  }
28
36
  }
29
37
  function CouponDiscountFields({ type, discountValue, setDiscountValue, maxDiscount, setMaxDiscount, minPurchase, setMinPurchase, buyQty, setBuyQty, getQty, setGetQty, discountLabel, }) {
30
- return (_jsxs(_Fragment, { children: [type !== "free_shipping" && type !== "buy_x_get_y" && (_jsx(Input, { label: discountLabel, value: discountValue, onChange: (e) => setDiscountValue(e.target.value), type: "number", min: 0, required: true, placeholder: type === "percentage" ? "e.g. 20" : "e.g. 5000" })), type === "percentage" && (_jsx(Input, { label: "Max discount cap (paise, optional)", value: maxDiscount, onChange: (e) => setMaxDiscount(e.target.value), type: "number", min: 0, placeholder: "e.g. 20000", helperText: "Leave blank for no cap." })), (type === "percentage" || type === "fixed") && (_jsx(Input, { label: "Min order value (paise, optional)", value: minPurchase, onChange: (e) => setMinPurchase(e.target.value), type: "number", min: 0, placeholder: "e.g. 50000", helperText: "Leave blank for no minimum." })), type === "buy_x_get_y" && (_jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Buy quantity", value: buyQty, onChange: (e) => setBuyQty(e.target.value), type: "number", min: 1, required: true }), _jsx(Input, { label: "Get quantity", value: getQty, onChange: (e) => setGetQty(e.target.value), type: "number", min: 1, required: true })] }))] }));
38
+ return (_jsxs(_Fragment, { children: [type !== "free_shipping" && type !== "buy_x_get_y" && (_jsx(Input, { label: discountLabel, value: discountValue, onChange: (e) => setDiscountValue(e.target.value), type: "number", min: 0, required: true, placeholder: type === "percentage" ? "e.g. 20" : "e.g. 5000" })), type === "percentage" && (_jsx(Input, { label: "Max discount cap (paise, optional)", value: maxDiscount, onChange: (e) => setMaxDiscount(e.target.value), type: "number", min: 0, placeholder: "e.g. 20000", helperText: "Leave blank for no cap." })), (type === "percentage" || type === "fixed") && (_jsx(Input, { label: "Min order value (paise, optional)", value: minPurchase, onChange: (e) => setMinPurchase(e.target.value), type: "number", min: 0, placeholder: "e.g. 50000", helperText: "Leave blank for no minimum." })), type === "buy_x_get_y" && (_jsxs(Div, { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Buy quantity", value: buyQty, onChange: (e) => setBuyQty(e.target.value), type: "number", min: 1, required: true }), _jsx(Input, { label: "Get quantity", value: getQty, onChange: (e) => setGetQty(e.target.value), type: "number", min: 1, required: true })] }))] }));
31
39
  }
32
40
  function CouponValidityFields({ startDate, setStartDate, endDate, setEndDate, isActive, setIsActive, totalLimit, setTotalLimit, perUserLimit, setPerUserLimit, isEdit, currentUsage, }) {
33
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Total usage limit (optional)", value: totalLimit, onChange: (e) => setTotalLimit(e.target.value), type: "number", min: 0, placeholder: "Unlimited" }), _jsx(Input, { label: "Per-user limit (optional)", value: perUserLimit, onChange: (e) => setPerUserLimit(e.target.value), type: "number", min: 0, placeholder: "Unlimited" })] }), isEdit && (_jsx(Input, { label: "Current usage", value: String(currentUsage), disabled: true, helperText: "Read-only \u2014 updated by orders." })), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Start date", value: startDate, onChange: (e) => setStartDate(e.target.value), type: "date", required: true }), _jsx(Input, { label: "End date (optional)", value: endDate, onChange: (e) => setEndDate(e.target.value), type: "date", helperText: "Leave blank for no expiry." })] }), _jsx(Toggle, { label: "Active", checked: isActive, onChange: setIsActive })] }));
41
+ return (_jsxs(_Fragment, { children: [_jsxs(Div, { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Total usage limit (optional)", value: totalLimit, onChange: (e) => setTotalLimit(e.target.value), type: "number", min: 0, placeholder: "Unlimited" }), _jsx(Input, { label: "Per-user limit (optional)", value: perUserLimit, onChange: (e) => setPerUserLimit(e.target.value), type: "number", min: 0, placeholder: "Unlimited" })] }), isEdit && (_jsx(Input, { label: "Current usage", value: String(currentUsage), disabled: true, helperText: "Read-only \u2014 updated by orders." })), _jsxs(Div, { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Start date", value: startDate, onChange: (e) => setStartDate(e.target.value), type: "date", required: true }), _jsx(Input, { label: "End date (optional)", value: endDate, onChange: (e) => setEndDate(e.target.value), type: "date", helperText: "Leave blank for no expiry." })] }), _jsx(Toggle, { label: "Active", checked: isActive, onChange: setIsActive })] }));
34
42
  }
35
43
  // --- Component ---------------------------------------------------------------
36
44
  export function AdminCouponEditorView({ couponId, onSaved, onDeleted, embedded, ...rest }) {
@@ -60,6 +68,8 @@ export function AdminCouponEditorView({ couponId, onSaved, onDeleted, embedded,
60
68
  const [firstTimeOnly, setFirstTimeOnly] = React.useState(false);
61
69
  const [combinable, setCombinable] = React.useState(false);
62
70
  const [appliesToAuctions, setAppliesToAuctions] = React.useState(false);
71
+ const [applicableProducts, setApplicableProducts] = React.useState([]);
72
+ const [applicableCategories, setApplicableCategories] = React.useState([]);
63
73
  const [deleteConfirmOpen, setDeleteConfirmOpen] = React.useState(false);
64
74
  const { showToast } = useToast();
65
75
  const { shellCtx, setFieldError, clearErrors } = useFormShellState();
@@ -94,6 +104,8 @@ export function AdminCouponEditorView({ couponId, onSaved, onDeleted, embedded,
94
104
  setIsActive(c.validity?.isActive ?? false);
95
105
  setFirstTimeOnly(c.restrictions?.firstTimeUserOnly ?? false);
96
106
  setCombinable(c.restrictions?.combineWithSellerCoupons ?? false);
107
+ setApplicableProducts(Array.isArray(c.restrictions?.applicableProducts) ? c.restrictions.applicableProducts : []);
108
+ setApplicableCategories(Array.isArray(c.restrictions?.applicableCategories) ? c.restrictions.applicableCategories : []);
97
109
  setAppliesToAuctions(c.applicableToAuctions ?? false);
98
110
  }, [couponQuery.data]);
99
111
  const handleNameChange = (value) => {
@@ -132,6 +144,8 @@ export function AdminCouponEditorView({ couponId, onSaved, onDeleted, embedded,
132
144
  restrictions: {
133
145
  firstTimeUserOnly: firstTimeOnly,
134
146
  combineWithSellerCoupons: combinable,
147
+ ...(applicableProducts.length > 0 && { applicableProducts }),
148
+ ...(applicableCategories.length > 0 && { applicableCategories }),
135
149
  },
136
150
  applicableToAuctions: appliesToAuctions,
137
151
  };
@@ -183,9 +197,13 @@ export function AdminCouponEditorView({ couponId, onSaved, onDeleted, embedded,
183
197
  }, className: "space-y-5", children: [_jsx(Select, { label: "Coupon type", options: TYPE_OPTIONS, value: type, onValueChange: (v) => setType(v), required: true }), _jsx(FieldInput, { name: "name", label: "Campaign name", value: name, onChange: (v) => handleNameChange(v), required: true, placeholder: "e.g. Summer Sale 20%" }), !isEdit && (_jsx(Input, { label: "Coupon code", value: code, onChange: (e) => {
184
198
  setCode(toCouponCode(e.target.value));
185
199
  setCodeManual(true);
186
- }, required: true, placeholder: "e.g. SUMMER20", helperText: "Auto-generated from name. Uppercase alphanumeric + hyphens only." })), isEdit && (_jsx(Input, { label: "Coupon code", value: code, disabled: true, helperText: "Code cannot be changed after creation." })), _jsx(Input, { label: "Description (optional)", value: description, onChange: (e) => setDescription(e.target.value), placeholder: "Internal notes about this coupon" }), _jsx(CouponDiscountFields, { type: type, discountValue: discountValue, setDiscountValue: setDiscountValue, maxDiscount: maxDiscount, setMaxDiscount: setMaxDiscount, minPurchase: minPurchase, setMinPurchase: setMinPurchase, buyQty: buyQty, setBuyQty: setBuyQty, getQty: getQty, setGetQty: setGetQty, discountLabel: discountLabel }), _jsx(CouponValidityFields, { startDate: startDate, setStartDate: setStartDate, endDate: endDate, setEndDate: setEndDate, isActive: isActive, setIsActive: setIsActive, totalLimit: totalLimit, setTotalLimit: setTotalLimit, perUserLimit: perUserLimit, setPerUserLimit: setPerUserLimit, isEdit: isEdit, currentUsage: currentUsage }), _jsx(Toggle, { label: "First-time users only", checked: firstTimeOnly, onChange: setFirstTimeOnly }), _jsx(Toggle, { label: "Allow stacking with seller coupons", checked: combinable, onChange: setCombinable }), _jsx(Toggle, { label: "Applies to auctions", checked: appliesToAuctions, onChange: setAppliesToAuctions }), _jsxs("div", { className: "flex gap-3 pt-2", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !canSave || isSubmitting, children: isEdit ? "Save changes" : "Create coupon" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => setDeleteConfirmOpen(true), children: "Delete coupon" }))] })] }, "coupon-form"), deleteConfirmOpen && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Coupon", message: "Delete this coupon? This cannot be undone.", onConfirm: () => { deleteMutation.mutate(); setDeleteConfirmOpen(false); }, onClose: () => setDeleteConfirmOpen(false), isDeleting: deleteMutation.isPending }))] }));
200
+ }, required: true, placeholder: "e.g. SUMMER20", helperText: "Auto-generated from name. Uppercase alphanumeric + hyphens only." })), isEdit && (_jsx(Input, { label: "Coupon code", value: code, disabled: true, helperText: "Code cannot be changed after creation." })), _jsx(Input, { label: "Description (optional)", value: description, onChange: (e) => setDescription(e.target.value), placeholder: "Internal notes about this coupon" }), _jsx(CouponDiscountFields, { type: type, discountValue: discountValue, setDiscountValue: setDiscountValue, maxDiscount: maxDiscount, setMaxDiscount: setMaxDiscount, minPurchase: minPurchase, setMinPurchase: setMinPurchase, buyQty: buyQty, setBuyQty: setBuyQty, getQty: getQty, setGetQty: setGetQty, discountLabel: discountLabel }), _jsx(CouponValidityFields, { startDate: startDate, setStartDate: setStartDate, endDate: endDate, setEndDate: setEndDate, isActive: isActive, setIsActive: setIsActive, totalLimit: totalLimit, setTotalLimit: setTotalLimit, perUserLimit: perUserLimit, setPerUserLimit: setPerUserLimit, isEdit: isEdit, currentUsage: currentUsage }), _jsx(Toggle, { label: "First-time users only", checked: firstTimeOnly, onChange: setFirstTimeOnly }), _jsx(Toggle, { label: "Allow stacking with seller coupons", checked: combinable, onChange: setCombinable }), _jsx(Toggle, { label: "Applies to auctions", checked: appliesToAuctions, onChange: setAppliesToAuctions }), _jsxs(Div, { className: "space-y-1", children: [_jsx(Label, { className: "text-sm font-medium text-zinc-800 dark:text-zinc-100", children: "Applicable products (optional)" }), _jsx(ProductInlineSelect, { scope: "admin", multiple: true, value: applicableProducts, onChange: setApplicableProducts, placeholder: "Restrict to specific products\u2026" }), _jsx(Text, { size: "xs", color: "muted", children: "Leave empty to apply the coupon to every eligible product." })] }), _jsxs(Div, { className: "space-y-1", children: [_jsx(Label, { className: "text-sm font-medium text-zinc-800 dark:text-zinc-100", children: "Applicable categories (optional)" }), _jsx(CategoryInlineSelect, { value: "", onChange: (id) => {
201
+ if (!id || applicableCategories.includes(id))
202
+ return;
203
+ setApplicableCategories([...applicableCategories, id]);
204
+ }, allowCreate: true, placeholder: "Add a category\u2026" }), applicableCategories.length > 0 && (_jsx(Div, { className: "flex flex-wrap gap-2 pt-1", children: applicableCategories.map((cid) => (_jsxs(Span, { className: "inline-flex items-center gap-1 rounded-full border border-zinc-300 bg-zinc-50 px-2.5 py-0.5 text-xs text-zinc-800 dark:border-zinc-600 dark:bg-zinc-800 dark:text-zinc-100", children: [cid, _jsx("button", { type: "button", "aria-label": `Remove ${cid}`, className: "text-zinc-500 hover:text-zinc-800 dark:text-zinc-400 dark:hover:text-zinc-100", onClick: () => setApplicableCategories(applicableCategories.filter((c) => c !== cid)), children: "\u00D7" })] }, cid))) })), _jsx(Text, { size: "xs", color: "muted", children: "Leave empty to apply the coupon to every category." })] }), _jsxs(Div, { className: "flex gap-3 pt-2", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !canSave || isSubmitting, children: isEdit ? "Save changes" : "Create coupon" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => setDeleteConfirmOpen(true), children: "Delete coupon" }))] })] }, "coupon-form"), deleteConfirmOpen && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Coupon", message: "Delete this coupon? This cannot be undone.", onConfirm: () => { deleteMutation.mutate(); setDeleteConfirmOpen(false); }, onClose: () => setDeleteConfirmOpen(false), isDeleting: deleteMutation.isPending }))] }));
187
205
  if (embedded) {
188
- return _jsx("div", { className: "overflow-y-auto p-4", children: formSection });
206
+ return _jsx(Div, { className: `${__O.yAuto} ${__P.p4}`, children: formSection });
189
207
  }
190
208
  return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Coupon" : "Create Coupon", sections: [formSection] }));
191
209
  }