@mohasinac/appkit 2.8.1 → 2.8.3

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 (434) 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 +1 -1
  14. package/dist/client.js +1 -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/core/hooks/useSiteSettings.d.ts +1 -1
  19. package/dist/features/about/components/AboutView.js +5 -2
  20. package/dist/features/about/components/FAQPageView.js +3 -3
  21. package/dist/features/about/components/FeesView.js +13 -5
  22. package/dist/features/about/components/HelpPageView.js +9 -5
  23. package/dist/features/about/components/HowAuctionsWorkView.js +9 -5
  24. package/dist/features/about/components/HowCheckoutWorksView.js +9 -5
  25. package/dist/features/about/components/HowOffersWorkView.js +10 -5
  26. package/dist/features/about/components/HowOrdersWorkView.js +10 -5
  27. package/dist/features/about/components/HowPayoutsWorkView.js +9 -5
  28. package/dist/features/about/components/HowPreOrdersWorkView.js +9 -5
  29. package/dist/features/about/components/HowReviewsWorkView.js +9 -5
  30. package/dist/features/about/components/PolicyPageView.js +3 -3
  31. package/dist/features/about/components/PublicProfileView.js +11 -4
  32. package/dist/features/about/components/SecurityPrivacyView.js +8 -4
  33. package/dist/features/about/components/ShippingPolicyView.js +3 -2
  34. package/dist/features/about/components/TrackOrderView.js +2 -2
  35. package/dist/features/about/components/UnauthorizedView.js +3 -3
  36. package/dist/features/account/components/AddressBook.js +1 -1
  37. package/dist/features/account/components/AddressForm.js +2 -2
  38. package/dist/features/account/components/AddressInlineSelect.d.ts +24 -0
  39. package/dist/features/account/components/AddressInlineSelect.js +78 -0
  40. package/dist/features/account/components/AddressSelectorCreate.d.ts +2 -1
  41. package/dist/features/account/components/AddressSelectorCreate.js +5 -32
  42. package/dist/features/account/components/AddressesIndexListing.js +3 -3
  43. package/dist/features/account/components/ChatWindow.js +2 -1
  44. package/dist/features/account/components/NotificationBell.js +13 -7
  45. package/dist/features/account/components/NotificationPreferencesPanel.js +4 -1
  46. package/dist/features/account/components/UserOffersPanel.js +2 -1
  47. package/dist/features/account/components/UserSidebar.js +11 -7
  48. package/dist/features/account/components/UserSupportView.js +13 -4
  49. package/dist/features/account/components/index.d.ts +2 -0
  50. package/dist/features/account/components/index.js +1 -0
  51. package/dist/features/account/hooks/useAccount.d.ts +2 -2
  52. package/dist/features/account/hooks/useAddressSelector.d.ts +1 -1
  53. package/dist/features/account/hooks/useAddresses.d.ts +2 -2
  54. package/dist/features/account/hooks/useNotifications.d.ts +1 -1
  55. package/dist/features/account/hooks/useProfile.d.ts +1 -1
  56. package/dist/features/account/hooks/usePublicProfile.d.ts +2 -2
  57. package/dist/features/addresses/repository/addresses.repository.d.ts +1 -0
  58. package/dist/features/addresses/repository/addresses.repository.js +13 -0
  59. package/dist/features/admin/components/AdminAdEditorView.js +8 -5
  60. package/dist/features/admin/components/AdminAddressEditorView.js +5 -5
  61. package/dist/features/admin/components/AdminAdsView.js +10 -7
  62. package/dist/features/admin/components/AdminBlogEditorView.js +15 -9
  63. package/dist/features/admin/components/AdminBrandEditorView.js +10 -4
  64. package/dist/features/admin/components/AdminBrandsView.js +4 -4
  65. package/dist/features/admin/components/AdminBundleEditorView.js +4 -5
  66. package/dist/features/admin/components/AdminBundlesView.js +3 -3
  67. package/dist/features/admin/components/AdminCarouselEditorView.js +6 -3
  68. package/dist/features/admin/components/AdminCarouselView.js +6 -6
  69. package/dist/features/admin/components/AdminCatalogGuideView.js +2 -1
  70. package/dist/features/admin/components/AdminCategoriesView.js +5 -5
  71. package/dist/features/admin/components/AdminCategoryEditorView.js +11 -5
  72. package/dist/features/admin/components/AdminContactEditorView.js +8 -1
  73. package/dist/features/admin/components/AdminCouponEditorView.js +23 -5
  74. package/dist/features/admin/components/AdminEmployeeEditorView.js +7 -4
  75. package/dist/features/admin/components/AdminFaqEditorView.js +9 -3
  76. package/dist/features/admin/components/AdminFaqsView.js +4 -4
  77. package/dist/features/admin/components/AdminFeatureEditorView.js +7 -1
  78. package/dist/features/admin/components/AdminFeatureFlagsView.js +4 -1
  79. package/dist/features/admin/components/AdminFilterBar.js +4 -4
  80. package/dist/features/admin/components/AdminGroupedListingsView.js +65 -30
  81. package/dist/features/admin/components/AdminGuideHubView.js +4 -1
  82. package/dist/features/admin/components/AdminMediaView.js +4 -1
  83. package/dist/features/admin/components/AdminNavigationView.js +7 -4
  84. package/dist/features/admin/components/AdminNotificationsView.js +2 -2
  85. package/dist/features/admin/components/AdminOrderEditorView.js +2 -2
  86. package/dist/features/admin/components/AdminPageHeader.js +5 -2
  87. package/dist/features/admin/components/AdminPrizeDrawsView.js +5 -5
  88. package/dist/features/admin/components/AdminProductEditorView.js +12 -5
  89. package/dist/features/admin/components/AdminProductsView.js +4 -4
  90. package/dist/features/admin/components/AdminReviewsView.js +2 -2
  91. package/dist/features/admin/components/AdminScammerEditorView.js +6 -2
  92. package/dist/features/admin/components/AdminScammersView.js +3 -3
  93. package/dist/features/admin/components/AdminSectionsView.js +20 -22
  94. package/dist/features/admin/components/AdminSessionsManager.js +2 -1
  95. package/dist/features/admin/components/AdminSessionsView.js +2 -2
  96. package/dist/features/admin/components/AdminSidebar.js +11 -7
  97. package/dist/features/admin/components/AdminSiteConfigGuideView.js +2 -1
  98. package/dist/features/admin/components/AdminSiteSettingsView.js +5 -1
  99. package/dist/features/admin/components/AdminStoreAddressesView.js +2 -2
  100. package/dist/features/admin/components/AdminStoreEditorView.js +5 -5
  101. package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +3 -3
  102. package/dist/features/admin/components/AdminSupportTicketDetailView.js +10 -3
  103. package/dist/features/admin/components/AdminSupportTicketsView.js +3 -3
  104. package/dist/features/admin/components/AdminTrustGuideView.js +3 -3
  105. package/dist/features/admin/components/AdminUsersGuideView.js +3 -3
  106. package/dist/features/admin/components/AdminViewCards.js +12 -6
  107. package/dist/features/admin/components/BrandQuickCreateForm.js +2 -2
  108. package/dist/features/admin/components/CategoryQuickCreateForm.js +2 -2
  109. package/dist/features/admin/components/DashboardStats.js +9 -3
  110. package/dist/features/admin/components/DataListingView.js +3 -3
  111. package/dist/features/admin/components/DataTable.js +11 -7
  112. package/dist/features/admin/components/DrawerFormFooter.js +2 -2
  113. package/dist/features/admin/components/QuickEditMenu.js +2 -1
  114. package/dist/features/admin/components/analytics/AdminAnalyticsCharts.js +5 -1
  115. package/dist/features/admin/hooks/useAdmin.d.ts +1 -1
  116. package/dist/features/admin/hooks/useAdminSectionsListing.d.ts +1 -1
  117. package/dist/features/admin/hooks/useChat.d.ts +1 -1
  118. package/dist/features/auctions/components/AuctionBidsTable.js +4 -1
  119. package/dist/features/auctions/components/AuctionDetailPageView.js +14 -6
  120. package/dist/features/auctions/components/CollapsibleBidHistory.js +5 -1
  121. package/dist/features/auctions/components/MarketplaceAuctionCard.js +9 -3
  122. package/dist/features/auctions/components/MarketplaceAuctionGrid.js +8 -2
  123. package/dist/features/auctions/components/PlaceBidFormClient.js +4 -1
  124. package/dist/features/auctions/hooks/useAuctions.d.ts +8 -8
  125. package/dist/features/auth/components/RegisterForm.js +2 -2
  126. package/dist/features/auth/components/VerifyEmailView.js +5 -2
  127. package/dist/features/auth/consent-otp.d.ts +2 -2
  128. package/dist/features/auth/hooks/useAuth.d.ts +2 -2
  129. package/dist/features/before-after/components/BeforeAfterSlider.js +1 -1
  130. package/dist/features/blog/components/BlogFeaturedCard.js +8 -1
  131. package/dist/features/blog/components/BlogIndexListing.js +11 -5
  132. package/dist/features/blog/components/BlogListView.js +11 -3
  133. package/dist/features/blog/components/BlogPostView.js +10 -3
  134. package/dist/features/cart/components/CartDrawer.js +11 -3
  135. package/dist/features/cart/components/CartSummary.js +2 -2
  136. package/dist/features/cart/components/CheckoutOtpModal.js +2 -1
  137. package/dist/features/cart/hooks/useCart.d.ts +1 -1
  138. package/dist/features/cart/hooks/useCartQuery.d.ts +1 -1
  139. package/dist/features/cart/hooks/useCheckoutReadQueries.d.ts +2 -2
  140. package/dist/features/cart/hooks/useOrder.d.ts +2 -2
  141. package/dist/features/categories/components/BrandDetailPageView.js +5 -2
  142. package/dist/features/categories/components/BrandDetailTabs.js +5 -1
  143. package/dist/features/categories/components/BundleDetailView.js +6 -3
  144. package/dist/features/categories/components/BundleDynamicRuleEditor.js +3 -1
  145. package/dist/features/categories/components/BundleItemsPicker.js +10 -3
  146. package/dist/features/categories/components/CategoriesIndexListing.js +12 -6
  147. package/dist/features/categories/components/CategoryBundlesListing.js +5 -2
  148. package/dist/features/categories/components/CategoryDetailPageView.js +6 -2
  149. package/dist/features/categories/components/CategoryDetailTabs.js +5 -1
  150. package/dist/features/categories/components/CategoryForm.js +6 -3
  151. package/dist/features/categories/components/CategoryGrid.js +9 -2
  152. package/dist/features/categories/components/CategoryProductsListing.js +10 -4
  153. package/dist/features/categories/components/CategorySelectorCreate.js +3 -3
  154. package/dist/features/categories/components/CategorySortSelect.js +1 -1
  155. package/dist/features/categories/components/CategoryStoresListing.js +3 -3
  156. package/dist/features/categories/components/CategoryTableColumns.js +10 -6
  157. package/dist/features/categories/components/CategoryTree.js +1 -1
  158. package/dist/features/categories/hooks/useCategories.d.ts +3 -3
  159. package/dist/features/categories/hooks/useCategorySelector.d.ts +3 -3
  160. package/dist/features/categories/hooks/useCategoryTree.d.ts +1 -1
  161. package/dist/features/checkout/hooks/useCheckoutApi.d.ts +2 -2
  162. package/dist/features/classified/components/ClassifiedFilters.js +2 -2
  163. package/dist/features/classified/components/ClassifiedIndexListing.js +9 -3
  164. package/dist/features/collections/components/CollectionCard.js +2 -1
  165. package/dist/features/collections/hooks/useCollections.d.ts +2 -2
  166. package/dist/features/contact/components/ContactForm.js +4 -2
  167. package/dist/features/contact/components/ContactInfoSidebar.js +4 -1
  168. package/dist/features/copilot/components/AdminCopilotView.js +13 -5
  169. package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +9 -3
  170. package/dist/features/events/components/AdminEventEditorView.js +62 -40
  171. package/dist/features/events/components/AdminEventEntriesView.js +9 -6
  172. package/dist/features/events/components/EventCard.js +7 -1
  173. package/dist/features/events/components/EventFormDrawer.js +2 -1
  174. package/dist/features/events/components/EventLeaderboard.js +4 -4
  175. package/dist/features/events/components/EventOfferCard.js +4 -1
  176. package/dist/features/events/components/EventParticipateView.js +3 -2
  177. package/dist/features/events/components/EventPollWidget.js +6 -5
  178. package/dist/features/events/components/EventRaffleEntryForm.js +5 -2
  179. package/dist/features/events/components/EventRaffleWinnerView.js +7 -1
  180. package/dist/features/events/components/EventRafflesSection.js +2 -2
  181. package/dist/features/events/components/EventSaleBanner.js +5 -2
  182. package/dist/features/events/components/EventsIndexListing.js +8 -2
  183. package/dist/features/events/components/EventsListView.js +4 -1
  184. package/dist/features/events/components/SpinWheelView.js +7 -2
  185. package/dist/features/events/hooks/useEvent.d.ts +3 -3
  186. package/dist/features/events/hooks/useEvents.d.ts +1 -1
  187. package/dist/features/events/schemas/firestore.d.ts +1 -0
  188. package/dist/features/events/types/index.d.ts +1 -0
  189. package/dist/features/faq/components/ContactCTA.js +4 -1
  190. package/dist/features/faq/components/FAQCategorySidebar.js +2 -2
  191. package/dist/features/faq/components/FAQHelpfulButtons.js +8 -5
  192. package/dist/features/faq/components/FAQPageContent.js +5 -5
  193. package/dist/features/faq/components/FAQSortDropdown.js +2 -2
  194. package/dist/features/faq/hooks/useFAQs.d.ts +1 -1
  195. package/dist/features/faq/hooks/useFaqList.d.ts +15 -15
  196. package/dist/features/filters/AsyncFacetSection.js +4 -2
  197. package/dist/features/filters/FilterFacetSection.js +14 -6
  198. package/dist/features/filters/RangeFilter.js +4 -2
  199. package/dist/features/filters/SwitchFilter.js +2 -1
  200. package/dist/features/forms/Checkbox.js +1 -1
  201. package/dist/features/forms/Radio.js +1 -1
  202. package/dist/features/forms/Slider.js +1 -1
  203. package/dist/features/homepage/components/AdSlot.js +4 -4
  204. package/dist/features/homepage/components/AdvertisementBanner.js +13 -4
  205. package/dist/features/homepage/components/AnnouncementBar.js +2 -1
  206. package/dist/features/homepage/components/BeforeAfterCard.js +8 -2
  207. package/dist/features/homepage/components/BrandsSection.js +6 -3
  208. package/dist/features/homepage/components/CTABannerSection.js +2 -2
  209. package/dist/features/homepage/components/CharacterHotspot.js +5 -2
  210. package/dist/features/homepage/components/CharacterHotspotForm.js +8 -4
  211. package/dist/features/homepage/components/CustomCardsSection.js +13 -7
  212. package/dist/features/homepage/components/CustomerReviewsSection.js +9 -3
  213. package/dist/features/homepage/components/FAQSection.js +7 -4
  214. package/dist/features/homepage/components/FeaturedBundlesSection.js +8 -2
  215. package/dist/features/homepage/components/FeaturedResultsSection.js +1 -1
  216. package/dist/features/homepage/components/GoogleReviewsSection.js +14 -8
  217. package/dist/features/homepage/components/HeroCarousel.js +1 -1
  218. package/dist/features/homepage/components/HomepageSkeleton.js +7 -1
  219. package/dist/features/homepage/components/HowItWorksInfoView.js +2 -2
  220. package/dist/features/homepage/components/HowItWorksSection.js +2 -2
  221. package/dist/features/homepage/components/NewsletterBanner.js +3 -2
  222. package/dist/features/homepage/components/NewsletterSection.js +5 -2
  223. package/dist/features/homepage/components/PromoGrid.js +4 -1
  224. package/dist/features/homepage/components/SectionCarousel.js +7 -4
  225. package/dist/features/homepage/components/SecurityHighlightsSection.js +3 -3
  226. package/dist/features/homepage/components/ShopByCategorySection.js +10 -4
  227. package/dist/features/homepage/components/SiteFeaturesSection.js +5 -2
  228. package/dist/features/homepage/components/SocialFeedSection.js +4 -4
  229. package/dist/features/homepage/components/SocialPostCard.js +6 -3
  230. package/dist/features/homepage/components/TrustFeaturesSection.js +5 -5
  231. package/dist/features/homepage/components/TrustIndicatorsSection.js +5 -2
  232. package/dist/features/homepage/components/WelcomeSection.js +1 -1
  233. package/dist/features/homepage/components/WhatsAppCommunitySection.js +3 -3
  234. package/dist/features/homepage/hooks/useBlogArticles.d.ts +1 -1
  235. package/dist/features/homepage/hooks/useFeaturedAuctions.d.ts +1 -1
  236. package/dist/features/homepage/hooks/useFeaturedPreOrders.d.ts +1 -1
  237. package/dist/features/homepage/hooks/useFeaturedProducts.d.ts +1 -1
  238. package/dist/features/homepage/hooks/useFeaturedStores.d.ts +1 -1
  239. package/dist/features/homepage/hooks/useHeroCarousel.d.ts +1 -1
  240. package/dist/features/homepage/hooks/useHomepageEvents.d.ts +1 -1
  241. package/dist/features/homepage/hooks/useHomepageReviews.d.ts +1 -1
  242. package/dist/features/homepage/hooks/useHomepageSections.d.ts +1 -1
  243. package/dist/features/homepage/hooks/useTopBrands.d.ts +1 -1
  244. package/dist/features/homepage/hooks/useTopCategories.d.ts +1 -1
  245. package/dist/features/layout/AppLayoutShell.js +2 -1
  246. package/dist/features/layout/BackToTop.js +1 -1
  247. package/dist/features/layout/BottomActions.js +4 -3
  248. package/dist/features/layout/BottomNavItem.js +1 -1
  249. package/dist/features/layout/BottomSheet.js +4 -1
  250. package/dist/features/layout/FooterLayout.js +1 -1
  251. package/dist/features/layout/NavbarLayout.js +4 -1
  252. package/dist/features/layout/SidebarLayout.js +5 -2
  253. package/dist/features/live/components/LiveItemFilters.js +2 -2
  254. package/dist/features/live/components/LiveItemsIndexListing.js +9 -3
  255. package/dist/features/loyalty/components/CoinsDisplay.js +4 -2
  256. package/dist/features/loyalty/hooks/useLoyaltyBalance.d.ts +1 -1
  257. package/dist/features/media/AvatarUpload.js +2 -2
  258. package/dist/features/media/MediaLightbox.js +3 -2
  259. package/dist/features/media/modals/VideoThumbnailSelector.js +4 -1
  260. package/dist/features/media/modals/VideoTrimModal.js +1 -1
  261. package/dist/features/media/upload/CameraCapture.js +1 -1
  262. package/dist/features/media/upload/ImageUpload.js +4 -1
  263. package/dist/features/media/upload/MediaUploadField.js +11 -2
  264. package/dist/features/media/upload/MediaUploadList.js +5 -1
  265. package/dist/features/orders/components/MarketplaceOrderCard.js +2 -2
  266. package/dist/features/orders/components/OrdersList.js +2 -1
  267. package/dist/features/orders/components/RefundHistoryTable.js +4 -1
  268. package/dist/features/orders/components/RefundRequestView.js +2 -1
  269. package/dist/features/orders/hooks/useOrders.d.ts +2 -2
  270. package/dist/features/payments/hooks/usePayments.d.ts +1 -1
  271. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +5 -1
  272. package/dist/features/pre-orders/components/PreOrderActionsClient.js +3 -3
  273. package/dist/features/pre-orders/components/PreOrderBadge.js +2 -1
  274. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +16 -7
  275. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +32 -24
  276. package/dist/features/pre-orders/hooks/usePreOrders.d.ts +2 -2
  277. package/dist/features/products/columns/productTableColumns.js +9 -4
  278. package/dist/features/products/components/AuctionsIndexListing.js +9 -3
  279. package/dist/features/products/components/BidHistory.js +4 -4
  280. package/dist/features/products/components/CompareOverlay.js +10 -2
  281. package/dist/features/products/components/CustomFieldsEditor.js +2 -1
  282. package/dist/features/products/components/CustomSectionTabContent.js +2 -2
  283. package/dist/features/products/components/CustomSectionsEditor.js +3 -2
  284. package/dist/features/products/components/GroupSettingsPanel.js +34 -26
  285. package/dist/features/products/components/MakeOfferButton.js +6 -2
  286. package/dist/features/products/components/MakeOfferForm.js +2 -1
  287. package/dist/features/products/components/MarketplaceBundleCard.js +6 -3
  288. package/dist/features/products/components/MarketplacePrizeDrawCard.js +3 -2
  289. package/dist/features/products/components/PlaceBidForm.js +2 -1
  290. package/dist/features/products/components/PrizeDrawCollage.js +6 -2
  291. package/dist/features/products/components/PrizeDrawDetailPageView.js +6 -1
  292. package/dist/features/products/components/PrizeDrawItemsEditor.js +4 -2
  293. package/dist/features/products/components/PrizeDrawsIndexListing.js +6 -3
  294. package/dist/features/products/components/PrizeDrawsSection.js +2 -2
  295. package/dist/features/products/components/PrizeRevealModal.js +5 -1
  296. package/dist/features/products/components/ProductDetailPageView.js +32 -16
  297. package/dist/features/products/components/ProductFeatureBadges.js +9 -9
  298. package/dist/features/products/components/ProductForm.d.ts +11 -1
  299. package/dist/features/products/components/ProductForm.js +10 -5
  300. package/dist/features/products/components/ProductGalleryClient.js +8 -4
  301. package/dist/features/products/components/ProductGradingTab.js +4 -1
  302. package/dist/features/products/components/ProductGrid.js +35 -14
  303. package/dist/features/products/components/ProductInfo.js +2 -1
  304. package/dist/features/products/components/ProductTabs.js +2 -1
  305. package/dist/features/products/components/ProductTabsShell.js +5 -1
  306. package/dist/features/products/components/ProductsIndexListing.js +32 -24
  307. package/dist/features/products/components/ProductsIndexPageView.js +2 -2
  308. package/dist/features/products/components/RelatedProducts.js +3 -3
  309. package/dist/features/products/components/ShowGroupSection.js +10 -6
  310. package/dist/features/products/components/SublistingCarouselSection.js +7 -3
  311. package/dist/features/products/components/SublistingCategorySelect.d.ts +3 -1
  312. package/dist/features/products/components/SublistingCategorySelect.js +4 -37
  313. package/dist/features/products/constants/action-defs.js +3 -3
  314. package/dist/features/products/hooks/useProductDetail.d.ts +1 -1
  315. package/dist/features/products/hooks/useRelatedProducts.d.ts +1 -1
  316. package/dist/features/promotions/components/CouponCard.js +5 -3
  317. package/dist/features/promotions/components/CouponsIndexListing.js +7 -3
  318. package/dist/features/promotions/hooks/usePromotions.d.ts +2 -2
  319. package/dist/features/promotions/repository/coupons.repository.d.ts +8 -0
  320. package/dist/features/promotions/repository/coupons.repository.js +2 -0
  321. package/dist/features/reviews/components/ReviewDetailPageView.js +3 -3
  322. package/dist/features/reviews/components/ReviewDetailShell.js +15 -3
  323. package/dist/features/reviews/components/ReviewSummary.js +4 -2
  324. package/dist/features/reviews/components/ReviewsIndexListing.js +8 -2
  325. package/dist/features/reviews/components/ReviewsList.js +1 -1
  326. package/dist/features/reviews/hooks/useReviews.d.ts +2 -2
  327. package/dist/features/scams/components/ScamAwarenessModal.js +2 -2
  328. package/dist/features/scams/components/ScamProfileView.js +3 -3
  329. package/dist/features/scams/components/ScamRegistryView.js +6 -4
  330. package/dist/features/search/components/Search.js +9 -6
  331. package/dist/features/search/components/SearchFiltersRow.js +1 -1
  332. package/dist/features/search/components/SearchResultsSection.js +1 -1
  333. package/dist/features/search/hooks/useSearch.d.ts +2 -2
  334. package/dist/features/seller/components/CouponInlineSelect.d.ts +22 -0
  335. package/dist/features/seller/components/CouponInlineSelect.js +103 -0
  336. package/dist/features/seller/components/GroupInlineSelect.d.ts +23 -0
  337. package/dist/features/seller/components/GroupInlineSelect.js +80 -0
  338. package/dist/features/seller/components/PhysicalLocationModal.js +2 -1
  339. package/dist/features/seller/components/PrintCenterView.js +2 -1
  340. package/dist/features/seller/components/ProductInlineSelect.d.ts +24 -0
  341. package/dist/features/seller/components/ProductInlineSelect.js +42 -0
  342. package/dist/features/seller/components/QuickProductForm.js +4 -1
  343. package/dist/features/seller/components/SellerAddressesView.js +8 -3
  344. package/dist/features/seller/components/SellerAnalyticsAlertsView.js +6 -3
  345. package/dist/features/seller/components/SellerAnalyticsView.js +2 -2
  346. package/dist/features/seller/components/SellerBidsView.js +7 -7
  347. package/dist/features/seller/components/SellerBundlesView.js +2 -1
  348. package/dist/features/seller/components/SellerCouponEditorView.d.ts +2 -0
  349. package/dist/features/seller/components/SellerCouponEditorView.js +15 -3
  350. package/dist/features/seller/components/SellerCouponsView.js +1 -1
  351. package/dist/features/seller/components/SellerDashboardView.js +2 -2
  352. package/dist/features/seller/components/SellerDigitalCodesView.js +2 -2
  353. package/dist/features/seller/components/SellerGoogleReviewsView.js +2 -2
  354. package/dist/features/seller/components/SellerGroupedListingsView.js +5 -5
  355. package/dist/features/seller/components/SellerOrdersView.js +13 -10
  356. package/dist/features/seller/components/SellerPayoutMethodsView.js +5 -4
  357. package/dist/features/seller/components/SellerPayoutRequestView.js +5 -1
  358. package/dist/features/seller/components/SellerPayoutSettingsView.js +5 -2
  359. package/dist/features/seller/components/SellerPreOrdersView.js +6 -6
  360. package/dist/features/seller/components/SellerPrizeDrawsView.js +6 -6
  361. package/dist/features/seller/components/SellerProductShell.js +1 -1
  362. package/dist/features/seller/components/SellerProductsCards.js +4 -1
  363. package/dist/features/seller/components/SellerProductsView.js +5 -5
  364. package/dist/features/seller/components/SellerReviewsView.js +7 -3
  365. package/dist/features/seller/components/SellerShippingConfigsView.js +4 -4
  366. package/dist/features/seller/components/SellerShippingView.js +1 -1
  367. package/dist/features/seller/components/SellerSidebar.js +15 -8
  368. package/dist/features/seller/components/SellerStoreCategoriesView.js +1 -1
  369. package/dist/features/seller/components/SellerStorefrontView.js +2 -2
  370. package/dist/features/seller/components/SellerTemplatesView.js +7 -4
  371. package/dist/features/seller/components/SublistingInlineSelect.d.ts +19 -0
  372. package/dist/features/seller/components/SublistingInlineSelect.js +83 -0
  373. package/dist/features/seller/components/analytics/SellerTopProducts.js +1 -1
  374. package/dist/features/seller/components/index.d.ts +8 -0
  375. package/dist/features/seller/components/index.js +4 -0
  376. package/dist/features/seller/hooks/useSellerPayouts.d.ts +3 -3
  377. package/dist/features/seller/hooks/useSellerStore.d.ts +6 -6
  378. package/dist/features/seller/hooks/useSellerStorefront.d.ts +2 -2
  379. package/dist/features/shell/FormShell.js +10 -2
  380. package/dist/features/shell/QuickFormDrawer.js +5 -5
  381. package/dist/features/shell/StepForm.js +6 -6
  382. package/dist/features/site-settings/components/ActionPermissionsManager.js +8 -4
  383. package/dist/features/site-settings/components/NavPermissionsManager.js +7 -4
  384. package/dist/features/stores/components/InteractiveStoreCard.js +5 -1
  385. package/dist/features/stores/components/StoreAboutView.js +4 -1
  386. package/dist/features/stores/components/StoreAddressSelectorCreate.d.ts +2 -1
  387. package/dist/features/stores/components/StoreAddressSelectorCreate.js +5 -31
  388. package/dist/features/stores/components/StoreAuctionsListing.js +6 -3
  389. package/dist/features/stores/components/StoreGuideHubView.js +5 -2
  390. package/dist/features/stores/components/StoreHeader.js +8 -1
  391. package/dist/features/stores/components/StorePreOrdersListing.js +6 -3
  392. package/dist/features/stores/components/StoreProductsListing.js +6 -3
  393. package/dist/features/stores/components/StoreReviewsListing.js +8 -2
  394. package/dist/features/stores/components/StoresIndexListing.js +12 -6
  395. package/dist/features/stores/hooks/useStoreAddressSelector.d.ts +1 -1
  396. package/dist/features/stores/hooks/useStores.d.ts +6 -6
  397. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +7 -1
  398. package/dist/features/whatsapp-bot/components/WhatsAppChatButton.js +2 -1
  399. package/dist/features/wishlist/components/WishlistPage.js +2 -1
  400. package/dist/features/wishlist/hooks/useUserWishlist.d.ts +15 -15
  401. package/dist/features/wishlist/hooks/useWishlist.d.ts +1 -1
  402. package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
  403. package/dist/index.d.ts +10 -0
  404. package/dist/index.js +13 -1
  405. package/dist/next/components/GlobalError.js +2 -2
  406. package/dist/next/routing/route-map.d.ts +2 -0
  407. package/dist/next/routing/route-map.js +1 -0
  408. package/dist/providers/db-firebase/base.repository.d.ts +1 -1
  409. package/dist/react/ErrorBoundary.js +2 -2
  410. package/dist/seed/actions/demo-seed-actions.d.ts +1 -1
  411. package/dist/seed/manifest.js +10 -0
  412. package/dist/styles.css +2 -1
  413. package/dist/tailwind-utilities.css +1 -1
  414. package/dist/ui/DataTable.js +17 -16
  415. package/dist/ui/components/DateInput.js +2 -2
  416. package/dist/ui/components/DetailPageGallery.js +4 -1
  417. package/dist/ui/components/DetailPageTabs.js +6 -2
  418. package/dist/ui/components/ImageLightbox.js +5 -3
  419. package/dist/ui/components/Input.js +6 -3
  420. package/dist/ui/components/Layout.d.ts +4 -0
  421. package/dist/ui/components/Layout.js +1 -1
  422. package/dist/ui/components/Layout.style.css +1 -0
  423. package/dist/ui/components/ListingFilterDrawer.js +4 -1
  424. package/dist/ui/components/ListingLayout.js +9 -8
  425. package/dist/ui/components/ListingToolbar.js +5 -1
  426. package/dist/ui/components/PaginatedSelect.d.ts +1 -2
  427. package/dist/ui/components/PaginatedSelect.js +1 -2
  428. package/dist/ui/components/Radio.js +1 -1
  429. package/dist/ui/components/Select.js +2 -1
  430. package/dist/ui/components/Slider.js +1 -1
  431. package/dist/ui/components/VacationBanner.js +2 -1
  432. package/dist/ui/components/surface-tokens.d.ts +1 -0
  433. package/dist/ui/components/surface-tokens.js +1 -0
  434. package/package.json +22 -4
@@ -17,7 +17,15 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
17
17
  * `GET /api/products?ids=<csv>` (BK3 listByIds endpoint).
18
18
  */
19
19
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
20
+ const __P = {
21
+ p4: "p-4",
22
+ };
23
+ const __O = {
24
+ auto: "overflow-auto",
25
+ hidden: "overflow-hidden",
26
+ };
20
27
  const REL_NOOPENER = "noopener noreferrer";
28
+ const CLS_REMOVE_BTN = "shrink-0 rounded-full p-1 text-zinc-400 hover:bg-zinc-100 hover:text-rose-500 dark:hover:bg-zinc-800";
21
29
  import Link from "next/link";
22
30
  import { X } from "lucide-react";
23
31
  import { Button, Div, Heading, Row, Stack, Text } from "../../../ui";
@@ -68,7 +76,7 @@ function FieldRow({ label, children }) {
68
76
  function CompareColumn({ item, productType, labels, onRemove, onClose }) {
69
77
  const href = detailHref(item, productType);
70
78
  const img = item.mainImage ?? item.images?.[0];
71
- return (_jsxs(Stack, { gap: "md", className: COLUMN_CARD_CLASS, children: [_jsxs(Row, { justify: "between", align: "start", gap: "sm", children: [_jsx(Link, { href: href, target: "_blank", rel: REL_NOOPENER, className: "text-sm font-semibold text-zinc-900 dark:text-zinc-100 hover:underline line-clamp-2", children: item.title ?? item.id }), onRemove && (_jsx("button", { type: "button", onClick: () => onRemove(item.id), "aria-label": `${labels.remove} ${item.title ?? item.id}`, className: "shrink-0 rounded-full p-1 text-zinc-400 hover:bg-zinc-100 hover:text-rose-500 dark:hover:bg-zinc-800", children: _jsx(X, { className: "h-4 w-4" }) }))] }), _jsx(FieldRow, { label: labels.field.image, children: _jsx(Link, { href: href, target: "_blank", rel: REL_NOOPENER, children: _jsx(Div, { className: "relative aspect-square overflow-hidden rounded-lg bg-zinc-100 dark:bg-zinc-800", children: img ? (
79
+ return (_jsxs(Stack, { gap: "md", className: COLUMN_CARD_CLASS, children: [_jsxs(Row, { justify: "between", align: "start", gap: "sm", children: [_jsx(Link, { href: href, target: "_blank", rel: REL_NOOPENER, className: "text-sm font-semibold text-zinc-900 dark:text-zinc-100 hover:underline line-clamp-2", children: item.title ?? item.id }), onRemove && (_jsx("button", { type: "button", onClick: () => onRemove(item.id), "aria-label": `${labels.remove} ${item.title ?? item.id}`, className: CLS_REMOVE_BTN, children: _jsx(X, { className: "h-4 w-4" }) }))] }), _jsx(FieldRow, { label: labels.field.image, children: _jsx(Link, { href: href, target: "_blank", rel: REL_NOOPENER, children: _jsx(Div, { className: `relative aspect-square ${__O.hidden} rounded-lg bg-zinc-100 dark:bg-zinc-800`, children: img ? (
72
80
  // eslint-disable-next-line @next/next/no-img-element
73
81
  _jsx("img", { src: img, alt: item.title ?? item.id, className: "h-full w-full object-cover" })) : null }) }) }), _jsx(FieldRow, { label: labels.field.price, children: _jsx(Text, { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: priceLabel(item) }) }), _jsx(FieldRow, { label: labels.field.condition, children: _jsx(Text, { children: item.condition ? _jsx("span", { className: CHIP_CLASS, children: item.condition }) : "—" }) }), _jsx(FieldRow, { label: labels.field.brand, children: _jsx(Text, { children: item.brand ? _jsx("span", { className: CHIP_CLASS, children: item.brand }) : "—" }) }), _jsx(FieldRow, { label: labels.field.category, children: _jsx(Text, { children: (Array.isArray(item.categoryNames) ? item.categoryNames[0] : item.categoryName) || (Array.isArray(item.categorySlugs) ? item.categorySlugs[0] : item.category) ? (_jsx("span", { className: CHIP_CLASS, children: (Array.isArray(item.categoryNames) ? item.categoryNames[0] : item.categoryName) ?? (Array.isArray(item.categorySlugs) ? item.categorySlugs[0] : item.category) })) : ("—") }) }), _jsx(FieldRow, { label: labels.field.store, children: _jsx(Text, { className: "text-sm text-zinc-700 dark:text-zinc-300", children: item.storeName ?? "—" }) }), _jsx(Button, { asChild: true, variant: "primary", size: "sm", className: "mt-auto", children: _jsx(Link, { href: href, target: "_blank", rel: REL_NOOPENER, onClick: onClose, children: labels.view }) })] }));
74
82
  }
@@ -147,7 +155,7 @@ export function CompareOverlay({ isOpen, items: passedItems, productIds, product
147
155
  }, [onRemove]);
148
156
  if (!isOpen)
149
157
  return null;
150
- return (_jsxs(Div, { className: OVERLAY_CLASS, style: OVERLAY_STYLE, role: "dialog", "aria-modal": "true", "aria-label": labels.title, children: [_jsxs(Row, { justify: "between", align: "center", className: HEADER_CLASS, children: [_jsx(Heading, { level: 2, className: "text-base font-semibold", children: labels.title }), _jsx("button", { type: "button", onClick: onClose, "aria-label": labels.close, className: "rounded-full p-2 text-zinc-500 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800", children: _jsx(X, { className: "h-5 w-5" }) })] }), _jsx(Div, { className: "flex-1 overflow-auto p-4", children: isLoading ? (_jsx(Text, { variant: "secondary", className: "text-center py-12", children: "Loading\u00E2\u20AC\u00A6" })) : trimmed.length === 0 ? (_jsx(Text, { variant: "secondary", className: "text-center py-12", children: labels.empty })) : (_jsxs(_Fragment, { children: [_jsx(Div, { className: "hidden md:grid gap-4", style: {
158
+ return (_jsxs(Div, { className: OVERLAY_CLASS, style: OVERLAY_STYLE, role: "dialog", "aria-modal": "true", "aria-label": labels.title, children: [_jsxs(Row, { justify: "between", align: "center", className: HEADER_CLASS, children: [_jsx(Heading, { level: 2, className: "text-base font-semibold", children: labels.title }), _jsx("button", { type: "button", onClick: onClose, "aria-label": labels.close, className: "rounded-full p-2 text-zinc-500 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800", children: _jsx(X, { className: "h-5 w-5" }) })] }), _jsx(Div, { className: `flex-1 ${__O.auto} ${__P.p4}`, children: isLoading ? (_jsx(Text, { variant: "secondary", className: "text-center py-12", children: "Loading\u00E2\u20AC\u00A6" })) : trimmed.length === 0 ? (_jsx(Text, { variant: "secondary", className: "text-center py-12", children: labels.empty })) : (_jsxs(_Fragment, { children: [_jsx(Div, { className: "hidden md:grid gap-4", style: {
151
159
  gridTemplateColumns: `repeat(${trimmed.length}, minmax(0, 1fr))`,
152
160
  }, children: trimmed.map((item) => (_jsx(CompareColumn, { item: item, productType: productType, labels: labels, onRemove: onRemove ? handleRemove : undefined, onClose: onClose }, item.id))) }), _jsxs(Div, { className: "md:hidden", children: [_jsx(Div, { ref: swipeRef, className: "touch-pan-y", children: trimmed[activeIndex] && (_jsx(CompareColumn, { item: trimmed[activeIndex], productType: productType, labels: labels, onRemove: onRemove ? handleRemove : undefined, onClose: onClose })) }), trimmed.length > 1 && (_jsx(Row, { justify: "center", gap: "xs", className: "mt-4", children: trimmed.map((it, idx) => (_jsx("button", { type: "button", "aria-label": `Show item ${idx + 1}`, onClick: () => setActiveIndex(idx), className: `h-2 w-2 rounded-full transition-colors ${idx === activeIndex
153
161
  ? "bg-primary"
@@ -2,6 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Button, Div, Input, Row, Select, Stack, Text } from "../../../ui";
4
4
  import { MAX_CUSTOM_FIELDS } from "../schemas/firestore";
5
+ const CLS_REMOVE = "text-zinc-400 hover:text-red-500 dark:hover:text-red-400 px-2";
5
6
  const TYPE_OPTIONS = [
6
7
  { value: "text", label: "Text" },
7
8
  { value: "number", label: "Number" },
@@ -29,5 +30,5 @@ export function CustomFieldsEditor({ fields, onChange, showUnit = false, }) {
29
30
  return;
30
31
  onChange([...fields, emptyField()]);
31
32
  }
32
- return (_jsxs(Stack, { gap: "xs", children: [fields.map((field, i) => (_jsxs(Div, { className: "grid grid-cols-[1fr_140px_1fr_auto] gap-2 items-start", children: [_jsx(Input, { value: field.key, onChange: (e) => update(i, { key: e.target.value }), placeholder: "Field name", "aria-label": `Custom field ${i + 1} name` }), _jsx(Select, { options: TYPE_OPTIONS, value: field.type, onChange: (e) => update(i, { type: e.target.value, value: "" }), "aria-label": `Custom field ${i + 1} type` }), field.type === "boolean" ? (_jsx(Select, { options: BOOL_OPTIONS, value: field.value, onChange: (e) => update(i, { value: e.target.value }), "aria-label": `Custom field ${i + 1} value` })) : (_jsxs(Div, { className: showUnit ? "flex gap-1" : "", children: [_jsx(Input, { type: field.type === "number" ? "number" : "text", value: field.value, onChange: (e) => update(i, { value: e.target.value }), placeholder: field.type === "url" ? "https://" : "Value", "aria-label": `Custom field ${i + 1} value`, className: "flex-1" }), showUnit && (_jsx(Input, { value: field.unit ?? "", onChange: (e) => update(i, { unit: e.target.value || undefined }), placeholder: "Unit", "aria-label": `Custom field ${i + 1} unit`, className: "w-20 flex-shrink-0" }))] })), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => remove(i), "aria-label": `Remove field ${i + 1}`, className: "text-zinc-400 hover:text-red-500 dark:hover:text-red-400 px-2", children: "\u2715" })] }, i))), _jsxs(Row, { align: "center", justify: "between", children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: add, disabled: fields.length >= MAX_CUSTOM_FIELDS, className: "text-primary-600 dark:text-primary-400", children: "+ Add field" }), fields.length > 0 && (_jsxs(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400", children: [fields.length, " / ", MAX_CUSTOM_FIELDS] }))] })] }));
33
+ return (_jsxs(Stack, { gap: "xs", children: [fields.map((field, i) => (_jsxs(Div, { className: "grid grid-cols-[1fr_140px_1fr_auto] gap-2 items-start", children: [_jsx(Input, { value: field.key, onChange: (e) => update(i, { key: e.target.value }), placeholder: "Field name", "aria-label": `Custom field ${i + 1} name` }), _jsx(Select, { options: TYPE_OPTIONS, value: field.type, onChange: (e) => update(i, { type: e.target.value, value: "" }), "aria-label": `Custom field ${i + 1} type` }), field.type === "boolean" ? (_jsx(Select, { options: BOOL_OPTIONS, value: field.value, onChange: (e) => update(i, { value: e.target.value }), "aria-label": `Custom field ${i + 1} value` })) : (_jsxs(Div, { className: showUnit ? "flex gap-1" : "", children: [_jsx(Input, { type: field.type === "number" ? "number" : "text", value: field.value, onChange: (e) => update(i, { value: e.target.value }), placeholder: field.type === "url" ? "https://" : "Value", "aria-label": `Custom field ${i + 1} value`, className: "flex-1" }), showUnit && (_jsx(Input, { value: field.unit ?? "", onChange: (e) => update(i, { unit: e.target.value || undefined }), placeholder: "Unit", "aria-label": `Custom field ${i + 1} unit`, className: "w-20 flex-shrink-0" }))] })), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => remove(i), "aria-label": `Remove field ${i + 1}`, className: CLS_REMOVE, children: "\u2715" })] }, i))), _jsxs(Row, { align: "center", justify: "between", children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: add, disabled: fields.length >= MAX_CUSTOM_FIELDS, className: "text-primary-600 dark:text-primary-400", children: "+ Add field" }), fields.length > 0 && (_jsxs(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400", children: [fields.length, " / ", MAX_CUSTOM_FIELDS] }))] })] }));
33
34
  }
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Div, RichText, Text } from "../../../ui";
2
+ import { Div, Dl, Dt, Dd, RichText, Text } from "../../../ui";
3
3
  import { normalizeRichTextHtml } from "../../../utils/string.formatter";
4
4
  function renderFieldValue(f) {
5
5
  if (f.type === "boolean")
@@ -9,5 +9,5 @@ function renderFieldValue(f) {
9
9
  export function CustomSectionTabContent({ section }) {
10
10
  const html = section.text ? normalizeRichTextHtml(section.text) : null;
11
11
  const fields = section.fields?.filter((f) => f.key && f.value) ?? [];
12
- return (_jsxs(Div, { className: "space-y-4", children: [html && (_jsx(RichText, { html: html, proseClass: "prose prose-sm sm:prose max-w-none dark:prose-invert", className: "text-zinc-700 dark:text-zinc-300" })), fields.length > 0 && (_jsx("dl", { className: "divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800 overflow-hidden text-sm", children: fields.map((f, i) => (_jsxs("div", { className: "flex gap-4 px-4 py-3 bg-white dark:bg-zinc-900 even:bg-zinc-50 dark:even:bg-zinc-800/50", children: [_jsx("dt", { className: "w-36 flex-shrink-0 font-medium text-zinc-700 dark:text-zinc-300 capitalize", children: f.key }), _jsx("dd", { className: "flex-1 text-zinc-600 dark:text-zinc-400", children: f.type === "url" ? (_jsx("a", { href: f.value, target: "_blank", rel: "noopener noreferrer", className: "text-primary-600 hover:underline dark:text-primary-400 break-all", children: f.value })) : (renderFieldValue(f)) })] }, i))) })), !html && fields.length === 0 && (_jsx(Text, { className: "text-sm text-zinc-400 dark:text-zinc-400", children: "No content in this section." }))] }));
12
+ return (_jsxs(Div, { className: "space-y-4", children: [html && (_jsx(RichText, { html: html, proseClass: "prose prose-sm sm:prose max-w-none dark:prose-invert", className: "text-zinc-700 dark:text-zinc-300" })), fields.length > 0 && (_jsx(Dl, { className: "divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800 overflow-hidden text-sm", children: fields.map((f, i) => (_jsxs(Div, { className: "flex gap-4 px-4 py-3 bg-white dark:bg-zinc-900 even:bg-zinc-50 dark:even:bg-zinc-800/50", children: [_jsx(Dt, { className: "w-36 flex-shrink-0 font-medium text-zinc-700 dark:text-zinc-300 capitalize", children: f.key }), _jsx(Dd, { className: "flex-1 text-zinc-600 dark:text-zinc-400", children: f.type === "url" ? (_jsx("a", { href: f.value, target: "_blank", rel: "noopener noreferrer", className: "text-primary-600 hover:underline dark:text-primary-400 break-all", children: f.value })) : (renderFieldValue(f)) })] }, i))) })), !html && fields.length === 0 && (_jsx(Text, { className: "text-sm text-zinc-400 dark:text-zinc-400", children: "No content in this section." }))] }));
13
13
  }
@@ -1,9 +1,10 @@
1
1
  "use client";
2
2
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
3
3
  import { useId } from "react";
4
- import { Button, Div, Heading, Input, Stack, Text } from "../../../ui";
4
+ import { Button, Div, Heading, Input, Span, Stack, Text } from "../../../ui";
5
5
  import { MAX_CUSTOM_SECTIONS } from "../schemas/firestore";
6
6
  import { CustomFieldsEditor } from "./CustomFieldsEditor";
7
+ const CLS_REMOVE = "text-zinc-400 hover:text-red-500 dark:hover:text-red-400 text-xs";
7
8
  function generateSectionId() {
8
9
  return `cs_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
9
10
  }
@@ -23,5 +24,5 @@ export function CustomSectionsEditor({ sections, onChange, }) {
23
24
  return;
24
25
  onChange([...sections, emptySection()]);
25
26
  }
26
- return (_jsxs(Stack, { gap: "md", children: [sections.map((section, i) => (_jsxs(Div, { className: "rounded-xl border border-zinc-200 dark:border-zinc-700 bg-zinc-50 dark:bg-zinc-900/40 p-4 space-y-3", children: [_jsxs(Div, { className: "flex items-center justify-between gap-2", children: [_jsxs(Heading, { level: 4, className: "text-sm font-semibold text-zinc-700 dark:text-zinc-200", children: ["Section ", i + 1] }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => remove(i), className: "text-zinc-400 hover:text-red-500 dark:hover:text-red-400 text-xs", children: "Remove" })] }), _jsxs(Div, { children: [_jsxs("label", { htmlFor: `${baseId}-title-${i}`, className: "mb-1 block text-xs font-medium text-zinc-600 dark:text-zinc-400", children: ["Section title ", _jsx("span", { className: "text-error", children: "*" })] }), _jsx(Input, { id: `${baseId}-title-${i}`, value: section.title, onChange: (e) => update(i, { title: e.target.value }), placeholder: 'e.g. "Box Contents", "Compatibility", "Grading Details"', maxLength: 80 })] }), _jsxs(Div, { children: [_jsxs("label", { htmlFor: `${baseId}-text-${i}`, className: "mb-1 block text-xs font-medium text-zinc-600 dark:text-zinc-400", children: ["Body text", " ", _jsx("span", { className: "text-zinc-400 font-normal", children: "(optional)" })] }), _jsx("textarea", { id: `${baseId}-text-${i}`, value: section.text ?? "", onChange: (e) => update(i, { text: e.target.value || undefined }), placeholder: "Additional details for this section\u2026", rows: 3, maxLength: 2000, className: "w-full rounded-lg border border-zinc-300 dark:border-zinc-600 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-800 dark:text-zinc-100 placeholder:text-zinc-400 focus:outline-none focus:ring-2 focus:ring-primary-500 resize-y" })] }), _jsxs(Div, { children: [_jsxs(Text, { className: "mb-2 text-xs font-medium text-zinc-600 dark:text-zinc-400", children: ["Fields", " ", _jsx("span", { className: "text-zinc-400 font-normal", children: "(optional)" })] }), _jsx(CustomFieldsEditor, { fields: section.fields ?? [], onChange: (fields) => update(i, { fields: fields.length > 0 ? fields : undefined }), showUnit: true })] })] }, section.id))), _jsxs(Div, { className: "flex items-center justify-between", children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: add, disabled: sections.length >= MAX_CUSTOM_SECTIONS, className: "text-primary-600 dark:text-primary-400", children: "+ Add section" }), _jsxs(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400", children: [sections.length, " / ", MAX_CUSTOM_SECTIONS, " sections"] })] })] }));
27
+ return (_jsxs(Stack, { gap: "md", children: [sections.map((section, i) => (_jsxs(Div, { className: "rounded-xl border border-zinc-200 dark:border-zinc-700 bg-zinc-50 dark:bg-zinc-900/40 p-4 space-y-3", children: [_jsxs(Div, { className: "flex items-center justify-between gap-2", children: [_jsxs(Heading, { level: 4, className: "text-sm font-semibold text-zinc-700 dark:text-zinc-200", children: ["Section ", i + 1] }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => remove(i), className: CLS_REMOVE, children: "Remove" })] }), _jsxs(Div, { children: [_jsxs("label", { htmlFor: `${baseId}-title-${i}`, className: "mb-1 block text-xs font-medium text-zinc-600 dark:text-zinc-400", children: ["Section title ", _jsx("span", { className: "text-error", children: "*" })] }), _jsx(Input, { id: `${baseId}-title-${i}`, value: section.title, onChange: (e) => update(i, { title: e.target.value }), placeholder: 'e.g. "Box Contents", "Compatibility", "Grading Details"', maxLength: 80 })] }), _jsxs(Div, { children: [_jsxs("label", { htmlFor: `${baseId}-text-${i}`, className: "mb-1 block text-xs font-medium text-zinc-600 dark:text-zinc-400", children: ["Body text", " ", _jsx(Span, { weight: "normal", className: "text-zinc-400", children: "(optional)" })] }), _jsx("textarea", { id: `${baseId}-text-${i}`, value: section.text ?? "", onChange: (e) => update(i, { text: e.target.value || undefined }), placeholder: "Additional details for this section\u2026", rows: 3, maxLength: 2000, className: "w-full rounded-lg border border-zinc-300 dark:border-zinc-600 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-800 dark:text-zinc-100 placeholder:text-zinc-400 focus:outline-none focus:ring-2 focus:ring-primary-500 resize-y" })] }), _jsxs(Div, { children: [_jsxs(Text, { className: "mb-2 text-xs font-medium text-zinc-600 dark:text-zinc-400", children: ["Fields", " ", _jsx(Span, { weight: "normal", className: "text-zinc-400", children: "(optional)" })] }), _jsx(CustomFieldsEditor, { fields: section.fields ?? [], onChange: (fields) => update(i, { fields: fields.length > 0 ? fields : undefined }), showUnit: true })] })] }, section.id))), _jsxs(Div, { className: "flex items-center justify-between", children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: add, disabled: sections.length >= MAX_CUSTOM_SECTIONS, className: "text-primary-600 dark:text-primary-400", children: "+ Add section" }), _jsxs(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400", children: [sections.length, " / ", MAX_CUSTOM_SECTIONS, " sections"] })] })] }));
27
28
  }
@@ -1,8 +1,13 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState } from "react";
4
- import { Button, ConfirmDeleteModal, Div, FormField, Heading, Modal, Row, Select, SideDrawer, Stack, Text, Tabs, TabsContent, TabsList, TabsTrigger, PaginatedSelect, useToast, } from "../../../ui";
4
+ import { Button, ConfirmDeleteModal, Div, FormField, Heading, Modal, Row, Select, SideDrawer, Span, Stack, Text, Tabs, TabsContent, TabsList, TabsTrigger, useToast, } from "../../../ui";
5
5
  import { apiClient } from "../../../http";
6
+ import { ProductInlineSelect } from "../../seller/components/ProductInlineSelect";
7
+ const __P = {
8
+ p4: "p-4",
9
+ };
10
+ const CLS_DELETE_LINK = "text-red-500 hover:text-red-600";
6
11
  const CONDITION_OPTIONS = [
7
12
  { value: "new", label: "New" },
8
13
  { value: "used", label: "Used" },
@@ -22,7 +27,7 @@ export function GroupSettingsPanel({ productId, productSlug, groupId, isGroupPar
22
27
  price: "",
23
28
  condition: "new",
24
29
  });
25
- const [linkTarget, setLinkTarget] = useState(null);
30
+ const [linkTargets, setLinkTargets] = useState([]);
26
31
  const [children, setChildren] = useState(null);
27
32
  const [confirmAction, setConfirmAction] = useState(null);
28
33
  if (isAuction)
@@ -143,21 +148,33 @@ export function GroupSettingsPanel({ productId, productSlug, groupId, isGroupPar
143
148
  }
144
149
  }
145
150
  async function addLinkChild() {
146
- if (!linkTarget) {
147
- showToast("Select a listing to link.", "error");
151
+ if (linkTargets.length === 0) {
152
+ showToast("Select at least one listing to link.", "error");
148
153
  return;
149
154
  }
150
155
  setLoading(true);
156
+ let succeeded = 0;
157
+ const failures = [];
151
158
  try {
152
- await apiClient.post(childrenEndpoint, { mode: "link", childId: linkTarget, parentId: productId });
153
- showToast("Listing linked to group.", "success");
154
- setShowAddModal(false);
155
- setLinkTarget(null);
156
- loadChildren();
157
- onGroupChanged();
158
- }
159
- catch (e) {
160
- showToast(e?.message ?? "Failed to link listing.", "error");
159
+ for (const childId of linkTargets) {
160
+ try {
161
+ await apiClient.post(childrenEndpoint, { mode: "link", childId, parentId: productId });
162
+ succeeded++;
163
+ }
164
+ catch (e) {
165
+ failures.push(e?.message ?? "Failed to link listing.");
166
+ }
167
+ }
168
+ if (succeeded > 0) {
169
+ showToast(succeeded === 1 ? "Listing linked to group." : `${succeeded} listings linked to group.`, "success");
170
+ setShowAddModal(false);
171
+ setLinkTargets([]);
172
+ loadChildren();
173
+ onGroupChanged();
174
+ }
175
+ if (failures.length > 0) {
176
+ showToast(failures[0] ?? "Some listings could not be linked.", "error");
177
+ }
161
178
  }
162
179
  finally {
163
180
  setLoading(false);
@@ -184,25 +201,16 @@ export function GroupSettingsPanel({ productId, productSlug, groupId, isGroupPar
184
201
  },
185
202
  });
186
203
  }
187
- async function loadLinkOptions(query, page) {
188
- const params = new URLSearchParams({ page: String(page), pageSize: "25" });
189
- if (query)
190
- params.set("q", query);
191
- params.set("filters", "listingType==standard");
192
- const res = (await apiClient.get(`${storeProductsEndpoint}?${params.toString()}`));
193
- const items = (res.products ?? res.items ?? []).map((p) => ({ value: p.id, label: p.title }));
194
- return { items, hasMore: false };
195
- }
196
204
  const childSlugsCount = groupChildSlugs?.length ?? 0;
197
205
  return (_jsxs(Div, { children: [_jsxs("button", { type: "button", onClick: () => {
198
206
  const next = !open;
199
207
  setOpen(next);
200
208
  if (next && isGroupParent && children === null)
201
209
  loadChildren();
202
- }, className: "w-full flex items-center justify-between py-2 text-left group", "aria-expanded": open, children: [_jsx(Heading, { level: 3, className: "text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Group Settings" }), _jsx("span", { className: "text-xs text-zinc-400 dark:text-zinc-400 group-hover:text-zinc-600 dark:group-hover:text-zinc-300 transition-colors", children: open ? "▲" : "▼" })] }), open && (_jsxs(Stack, { gap: "sm", className: "mt-3 p-4 rounded-lg border border-zinc-200 dark:border-zinc-700 bg-zinc-50/50 dark:bg-zinc-800/30", children: [!groupId && !groupParentSlug && (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Group related listings together \u2014 e.g. a set, bundle, or multi-part item. Parts can be sold individually but shown together." }), _jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: startGroup, isLoading: loading, children: "Start a group" })] })), isGroupParent && groupId && (_jsxs(Stack, { gap: "md", children: [_jsxs(Row, { align: "start", gap: "sm", className: "flex-wrap", children: [_jsx("div", { className: "flex-1 min-w-[200px]", children: _jsx(FormField, { name: "groupTitle", label: "Group title", type: "text", value: editTitle, onChange: setEditTitle, placeholder: "e.g. Human Toy Complete Set" }) }), _jsx("div", { className: "pt-6", children: _jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: saveTitle, isLoading: loading, children: "Save title" }) })] }), _jsxs(Div, { children: [_jsxs(Text, { className: "text-xs font-semibold text-zinc-600 dark:text-zinc-400 mb-2", children: ["Members (", childSlugsCount + 1, " \u2014 including this listing)"] }), loading && !children ? (_jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400", children: "Loading\u2026" })) : (_jsxs("div", { className: "divide-y divide-zinc-100 dark:divide-zinc-800", children: [_jsxs(Row, { align: "center", gap: "sm", className: "py-2", children: [_jsx("span", { className: "rounded bg-[var(--appkit-color-primary,#6366f1)]/10 text-[var(--appkit-color-primary,#6366f1)] text-[10px] font-semibold px-1.5 py-0.5", children: "Parent" }), _jsx(Text, { className: "text-sm text-zinc-800 dark:text-zinc-200 flex-1", children: productSlug })] }), (children ?? []).filter((c) => c.id !== productId).map((child) => (_jsxs(Row, { align: "center", gap: "sm", className: "py-2", children: [child.images?.[0] ? (
210
+ }, className: "w-full flex items-center justify-between py-2 text-left group", "aria-expanded": open, children: [_jsx(Heading, { level: 3, className: "text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Group Settings" }), _jsx(Span, { size: "xs", className: "text-zinc-400 dark:text-zinc-400 group-hover:text-zinc-600 dark:group-hover:text-zinc-300 transition-colors", children: open ? "▲" : "▼" })] }), open && (_jsxs(Stack, { gap: "sm", className: `mt-3 ${__P.p4} rounded-lg border border-zinc-200 dark:border-zinc-700 bg-zinc-50/50 dark:bg-zinc-800/30`, children: [!groupId && !groupParentSlug && (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Group related listings together \u2014 e.g. a set, bundle, or multi-part item. Parts can be sold individually but shown together." }), _jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: startGroup, isLoading: loading, children: "Start a group" })] })), isGroupParent && groupId && (_jsxs(Stack, { gap: "md", children: [_jsxs(Row, { align: "start", gap: "sm", className: "flex-wrap", children: [_jsx(Div, { className: "flex-1 min-w-[200px]", children: _jsx(FormField, { name: "groupTitle", label: "Group title", type: "text", value: editTitle, onChange: setEditTitle, placeholder: "e.g. Human Toy Complete Set" }) }), _jsx(Div, { className: "pt-6", children: _jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: saveTitle, isLoading: loading, children: "Save title" }) })] }), _jsxs(Div, { children: [_jsxs(Text, { className: "text-xs font-semibold text-zinc-600 dark:text-zinc-400 mb-2", children: ["Members (", childSlugsCount + 1, " \u2014 including this listing)"] }), loading && !children ? (_jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400", children: "Loading\u2026" })) : (_jsxs(Div, { className: "divide-y divide-zinc-100 dark:divide-zinc-800", children: [_jsxs(Row, { align: "center", gap: "sm", className: "py-2", children: [_jsx(Span, { weight: "semibold", className: "rounded bg-[var(--appkit-color-primary,#6366f1)]/10 text-[var(--appkit-color-primary,#6366f1)] text-[10px] px-1.5 py-0.5", children: "Parent" }), _jsx(Text, { className: "text-sm text-zinc-800 dark:text-zinc-200 flex-1", children: productSlug })] }), (children ?? []).filter((c) => c.id !== productId).map((child) => (_jsxs(Row, { align: "center", gap: "sm", className: "py-2", children: [child.images?.[0] ? (
203
211
  // eslint-disable-next-line @next/next/no-img-element
204
- _jsx("img", { src: child.images[0], alt: child.title, className: "w-8 h-8 rounded-full object-cover border border-zinc-200 dark:border-zinc-700" })) : (_jsx("div", { className: "w-8 h-8 rounded-full bg-zinc-100 dark:bg-zinc-800" })), _jsx(Text, { className: "text-sm text-zinc-800 dark:text-zinc-200 flex-1 truncate", children: child.title }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => requestUnlinkChild(child.id), isLoading: loading, className: "text-red-500 hover:text-red-600 text-xs", children: "Unlink" })] }, child.id)))] }))] }), _jsxs(Row, { gap: "sm", className: "flex-wrap", children: [_jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: () => setShowAddModal(true), children: "Add child listing" }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: requestDissolveGroup, isLoading: loading, className: "text-red-500 hover:text-red-600", children: "Dissolve group" })] })] })), !isGroupParent && groupParentSlug && (_jsxs(Stack, { gap: "xs", children: [_jsxs(Text, { className: "text-sm text-zinc-600 dark:text-zinc-400", children: ["Part of:", " ", _jsx("span", { className: "font-medium text-zinc-800 dark:text-zinc-200", children: groupTitle ?? groupParentSlug })] }), _jsxs(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: ["Parent listing: ", _jsx("code", { className: "font-mono", children: groupParentSlug })] }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: requestLeaveGroup, isLoading: loading, className: "text-red-500 hover:text-red-600 w-fit", children: "Leave group" })] }))] })), (groupChildSlugs?.length ?? 0) >= 4 ? (_jsx(SideDrawer, { isOpen: showAddModal, onClose: () => setShowAddModal(false), title: "Add child listing", children: _jsx(AddChildContent, { addTab: addTab, setAddTab: setAddTab, createForm: createForm, setCreateForm: setCreateForm, productSlug: productSlug, linkTarget: linkTarget, setLinkTarget: setLinkTarget, loadLinkOptions: loadLinkOptions, onAddCreate: addCreateChild, onAddLink: addLinkChild, loading: loading }) })) : (_jsx(Modal, { open: showAddModal, onClose: () => setShowAddModal(false), title: "Add child listing", size: "lg", children: _jsx(AddChildContent, { addTab: addTab, setAddTab: setAddTab, createForm: createForm, setCreateForm: setCreateForm, productSlug: productSlug, linkTarget: linkTarget, setLinkTarget: setLinkTarget, loadLinkOptions: loadLinkOptions, onAddCreate: addCreateChild, onAddLink: addLinkChild, loading: loading }) })), confirmAction && (_jsx(ConfirmDeleteModal, { isOpen: true, title: confirmAction.title, message: confirmAction.message, onConfirm: confirmAction.onConfirm, onClose: () => setConfirmAction(null), isDeleting: loading }))] }));
212
+ _jsx("img", { src: child.images[0], alt: child.title, className: "w-8 h-8 rounded-full object-cover border border-zinc-200 dark:border-zinc-700" })) : (_jsx(Div, { className: "w-8 h-8 rounded-full bg-zinc-100 dark:bg-zinc-800" })), _jsx(Text, { className: "text-sm text-zinc-800 dark:text-zinc-200 flex-1 truncate", children: child.title }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => requestUnlinkChild(child.id), isLoading: loading, className: `${CLS_DELETE_LINK} text-xs`, children: "Unlink" })] }, child.id)))] }))] }), _jsxs(Row, { gap: "sm", className: "flex-wrap", children: [_jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: () => setShowAddModal(true), children: "Add child listing" }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: requestDissolveGroup, isLoading: loading, className: CLS_DELETE_LINK, children: "Dissolve group" })] })] })), !isGroupParent && groupParentSlug && (_jsxs(Stack, { gap: "xs", children: [_jsxs(Text, { className: "text-sm text-zinc-600 dark:text-zinc-400", children: ["Part of:", " ", _jsx(Span, { weight: "medium", className: "text-zinc-800 dark:text-zinc-200", children: groupTitle ?? groupParentSlug })] }), _jsxs(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: ["Parent listing: ", _jsx("code", { className: "font-mono", children: groupParentSlug })] }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: requestLeaveGroup, isLoading: loading, className: `${CLS_DELETE_LINK} w-fit`, children: "Leave group" })] }))] })), (groupChildSlugs?.length ?? 0) >= 4 ? (_jsx(SideDrawer, { isOpen: showAddModal, onClose: () => setShowAddModal(false), title: "Add child listing", children: _jsx(AddChildContent, { addTab: addTab, setAddTab: setAddTab, createForm: createForm, setCreateForm: setCreateForm, productSlug: productSlug, storeProductsEndpoint: storeProductsEndpoint, linkTargets: linkTargets, setLinkTargets: setLinkTargets, onAddCreate: addCreateChild, onAddLink: addLinkChild, loading: loading }) })) : (_jsx(Modal, { open: showAddModal, onClose: () => setShowAddModal(false), title: "Add child listing", size: "lg", children: _jsx(AddChildContent, { addTab: addTab, setAddTab: setAddTab, createForm: createForm, setCreateForm: setCreateForm, productSlug: productSlug, storeProductsEndpoint: storeProductsEndpoint, linkTargets: linkTargets, setLinkTargets: setLinkTargets, onAddCreate: addCreateChild, onAddLink: addLinkChild, loading: loading }) })), confirmAction && (_jsx(ConfirmDeleteModal, { isOpen: true, title: confirmAction.title, message: confirmAction.message, onConfirm: confirmAction.onConfirm, onClose: () => setConfirmAction(null), isDeleting: loading }))] }));
205
213
  }
206
- function AddChildContent({ addTab, setAddTab, createForm, setCreateForm, productSlug, linkTarget, setLinkTarget, loadLinkOptions, onAddCreate, onAddLink, loading, }) {
207
- return (_jsx(Stack, { gap: "md", children: _jsxs(Tabs, { value: addTab, onChange: (v) => setAddTab(v), children: [_jsxs(TabsList, { children: [_jsx(TabsTrigger, { value: "create", children: "Create new child" }), _jsx(TabsTrigger, { value: "link", children: "Link existing" })] }), _jsx(TabsContent, { value: "create", children: _jsxs(Stack, { gap: "sm", className: "mt-4", children: [_jsx(FormField, { name: "childTitle", label: "Title *", type: "text", value: createForm.title, onChange: (v) => setCreateForm({ ...createForm, title: v }), placeholder: `${productSlug}-part` }), _jsx(FormField, { name: "childPrice", label: "Price (\u20B9) *", type: "number", value: createForm.price, onChange: (v) => setCreateForm({ ...createForm, price: v }), placeholder: "0" }), _jsx(Select, { label: "Condition", value: createForm.condition, onValueChange: (v) => setCreateForm({ ...createForm, condition: v }), options: CONDITION_OPTIONS }), _jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400/80", children: "Other fields (category, brand, shipping, return policy) are inherited from this parent listing. Need more control? Edit the full listing after saving." }), _jsx(Button, { type: "button", onClick: onAddCreate, isLoading: loading, disabled: !createForm.title || !createForm.price, children: "Create and link child" })] }) }), _jsx(TabsContent, { value: "link", children: _jsxs(Stack, { gap: "sm", className: "mt-4", children: [_jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Search your existing products or pre-orders. Auctions cannot be linked." }), _jsx(PaginatedSelect, { value: linkTarget, onChange: (v) => setLinkTarget(v), loadOptions: loadLinkOptions, placeholder: "Search listings\u2026", searchPlaceholder: "Type title or slug\u2026", noResultsText: "No matching listings found", ariaLabel: "Listing to link" }), _jsx(Button, { type: "button", onClick: onAddLink, isLoading: loading, disabled: !linkTarget, children: "Link to group" })] }) })] }) }));
214
+ function AddChildContent({ addTab, setAddTab, createForm, setCreateForm, productSlug, storeProductsEndpoint, linkTargets, setLinkTargets, onAddCreate, onAddLink, loading, }) {
215
+ return (_jsx(Stack, { gap: "md", children: _jsxs(Tabs, { value: addTab, onChange: (v) => setAddTab(v), children: [_jsxs(TabsList, { children: [_jsx(TabsTrigger, { value: "create", children: "Create new child" }), _jsx(TabsTrigger, { value: "link", children: "Link existing" })] }), _jsx(TabsContent, { value: "create", children: _jsxs(Stack, { gap: "sm", className: "mt-4", children: [_jsx(FormField, { name: "childTitle", label: "Title *", type: "text", value: createForm.title, onChange: (v) => setCreateForm({ ...createForm, title: v }), placeholder: `${productSlug}-part` }), _jsx(FormField, { name: "childPrice", label: "Price (\u20B9) *", type: "number", value: createForm.price, onChange: (v) => setCreateForm({ ...createForm, price: v }), placeholder: "0" }), _jsx(Select, { label: "Condition", value: createForm.condition, onValueChange: (v) => setCreateForm({ ...createForm, condition: v }), options: CONDITION_OPTIONS }), _jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400/80", children: "Other fields (category, brand, shipping, return policy) are inherited from this parent listing. Need more control? Edit the full listing after saving." }), _jsx(Button, { type: "button", onClick: onAddCreate, isLoading: loading, disabled: !createForm.title || !createForm.price, children: "Create and link child" })] }) }), _jsx(TabsContent, { value: "link", children: _jsxs(Stack, { gap: "sm", className: "mt-4", children: [_jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Search your existing products or pre-orders. Auctions cannot be linked. Select multiple to bulk-link." }), _jsx(ProductInlineSelect, { scope: "store", endpoint: storeProductsEndpoint, filters: "listingType==standard", multiple: true, value: linkTargets, onChange: setLinkTargets, placeholder: "Search listings\u2026" }), _jsx(Button, { type: "button", onClick: onAddLink, isLoading: loading, disabled: linkTargets.length === 0, children: linkTargets.length > 1 ? `Link ${linkTargets.length} to group` : "Link to group" })] }) })] }) }));
208
216
  }
@@ -4,6 +4,10 @@ import { useState, useTransition } from "react";
4
4
  import { Button, Div, Input, LoginRequiredModal, Modal, Span, Stack, Text } from "../../../ui";
5
5
  import { isAuthError } from "../../../utils/auth-error";
6
6
  import { formatCurrency } from "../../../utils/number.formatter";
7
+ const CLS_SUCCESS_BOX = "rounded-xl border border-emerald-200 dark:border-emerald-800 bg-success-surface p-4 text-center space-y-1";
8
+ const CLS_PENDING_BOX = "rounded-xl border border-amber-200 dark:border-amber-800 bg-amber-50 dark:bg-amber-900/20 p-4 text-center space-y-1";
9
+ const CLS_PENDING_TITLE = "text-sm font-medium text-amber-800 dark:text-amber-300";
10
+ const CLS_PENDING_BODY = "text-xs text-amber-700 dark:text-amber-400";
7
11
  function isActiveOfferError(msg) {
8
12
  return msg.includes("active offer") || msg.includes("ACTIVE_OFFER");
9
13
  }
@@ -67,10 +71,10 @@ export function MakeOfferButton({ productId, listedPrice, currency, minOfferPerc
67
71
  });
68
72
  }
69
73
  if (state === "success") {
70
- return (_jsxs(Div, { className: `rounded-xl border border-emerald-200 dark:border-emerald-800 bg-success-surface p-4 text-center space-y-1 ${className}`, children: [_jsx(Span, { className: "text-lg", children: "\uD83C\uDF89" }), _jsx(Text, { className: "text-sm font-medium text-success", children: "Offer sent!" }), _jsx(Text, { className: "text-xs text-success", children: "The seller will review your offer and respond shortly." })] }));
74
+ return (_jsxs(Div, { className: `${CLS_SUCCESS_BOX} ${className}`, children: [_jsx(Span, { size: "lg", children: "\uD83C\uDF89" }), _jsx(Text, { className: "text-sm font-medium text-success", children: "Offer sent!" }), _jsx(Text, { className: "text-xs text-success", children: "The seller will review your offer and respond shortly." })] }));
71
75
  }
72
76
  if (state === "pending") {
73
- return (_jsxs(Div, { className: `rounded-xl border border-amber-200 dark:border-amber-800 bg-amber-50 dark:bg-amber-900/20 p-4 text-center space-y-1 ${className}`, children: [_jsx(Span, { className: "text-lg", children: "\u23F3" }), _jsx(Text, { className: "text-sm font-medium text-amber-800 dark:text-amber-300", children: "Offer Pending" }), _jsx(Text, { className: "text-xs text-amber-700 dark:text-amber-400", children: "You already have an offer on this item. Check My Offers for updates." })] }));
77
+ return (_jsxs(Div, { className: `${CLS_PENDING_BOX} ${className}`, children: [_jsx(Span, { size: "lg", children: "\u23F3" }), _jsx(Text, { className: CLS_PENDING_TITLE, children: "Offer Pending" }), _jsx(Text, { className: CLS_PENDING_BODY, children: "You already have an offer on this item. Check My Offers for updates." })] }));
74
78
  }
75
79
  const modalOpen = state === "confirm" || state === "loading" || state === "error";
76
80
  return (_jsxs(_Fragment, { children: [_jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to make an offer. Please log in or create an account to continue." }), _jsx(Button, { variant: "ghost", size: "md", className: `w-full border border-zinc-300 dark:border-zinc-600 ${className}`, onClick: handleOpenConfirm, children: "Make Offer" }), _jsx(Modal, { isOpen: modalOpen, onClose: handleCancel, size: "md", title: "Make an offer", actions: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: handleCancel, disabled: isPending, children: "Cancel" }), _jsx(Button, { variant: "primary", size: "sm", onClick: handleSubmit, disabled: isPending || offerAmount < minOffer, children: isPending ? "Sending…" : `Send offer of ${fmt(offerAmount)}` })] }), children: _jsxs(Stack, { gap: "md", children: [_jsxs(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: ["Listed at ", fmt(listedPrice), " \u00B7 Minimum offer: ", fmt(minOffer)] }), _jsxs(Div, { className: "space-y-1", children: [_jsx(Text, { className: "text-xs font-medium text-zinc-600 dark:text-zinc-400", children: "Your offer amount" }), _jsx(Input, { type: "number", value: String(offerAmount), onChange: (e) => handleAmountChange(e.target.value), min: minOffer, max: listedPrice - 1, step: 1, "aria-label": "Offer amount" }), _jsxs(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400", children: ["Must be between ", fmt(minOffer), " and ", fmt(listedPrice - 1)] })] }), _jsxs(Div, { className: "space-y-1", children: [_jsx(Text, { className: "text-xs font-medium text-zinc-600 dark:text-zinc-400", children: "Note to seller (optional)" }), _jsx(Input, { type: "text", value: buyerNote, onChange: (e) => setBuyerNote(e.target.value), placeholder: "E.g. Bundle deal, long-time fan\u2026", maxLength: 300, "aria-label": "Note to seller" })] }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "The seller will accept, decline, or suggest a counter price." }), state === "error" && (_jsx(Text, { className: "text-xs text-error", children: errorMsg }))] }) })] }));
@@ -1,8 +1,9 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Div } from "../../../ui/components/Div";
2
3
  export function MakeOfferForm({ isSubmitted = false, renderInput, renderAction, renderTerms, renderSuccess, renderAuthGate, renderError, className = "", }) {
3
4
  if (renderAuthGate)
4
5
  return _jsx(_Fragment, { children: renderAuthGate() });
5
6
  if (isSubmitted && renderSuccess)
6
7
  return _jsx(_Fragment, { children: renderSuccess() });
7
- return (_jsxs("div", { className: `space-y-4 ${className}`, "data-section": "makeofferform-div-423", children: [renderError?.(), renderInput?.(), renderTerms?.(), renderAction?.()] }));
8
+ return (_jsxs(Div, { className: `space-y-4 ${className}`, children: [renderError?.(), renderInput?.(), renderTerms?.(), renderAction?.()] }));
8
9
  }
@@ -6,6 +6,9 @@ import { useLongPress } from "../../../react/hooks/useLongPress";
6
6
  import { ROUTES } from "../../../next";
7
7
  import { formatCurrency } from "../../../utils";
8
8
  import { getDefaultCurrency } from "../../../core/baseline-resolver";
9
+ const CLS_BUNDLE_PILL = "inline-flex items-center rounded-full bg-violet-600 px-2 py-0.5 text-white";
10
+ const CLS_STOCK_OK = "bg-emerald-600 text-white";
11
+ const CLS_VIEW_BTN = "mt-2 w-full cursor-pointer rounded-md bg-violet-600 py-1.5 text-center text-xs font-semibold text-white transition-colors hover:bg-violet-700 active:scale-[0.98]";
9
12
  import { BaseListingCard, Div, Row, Span, Text, TextLink, } from "../../../ui";
10
13
  import { THEME_CONSTANTS } from "../../../tokens";
11
14
  const DEFAULT_LABELS = {
@@ -42,15 +45,15 @@ export function MarketplaceBundleCard({ bundle, className = "", variant = "grid"
42
45
  }
43
46
  router.push(String(detailHref));
44
47
  }, [detailHref, onNavigate, router]);
45
- return (_jsxs(BaseListingCard, { isSelected: isSelected, variant: variant, className: className, onMouseDown: !isSelected ? longPress.onMouseDown : undefined, onMouseUp: !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: !isSelected ? longPress.onTouchEnd : undefined, children: [_jsxs(BaseListingCard.Hero, { aspect: "square", variant: variant, children: [_jsx(TextLink, { href: String(detailHref), className: "absolute inset-0 block", children: showCollage ? (_jsx(Div, { className: `grid h-full w-full gap-0.5 bg-[var(--appkit-color-surface-muted)] ${collageTiles.length === 2 ? "grid-cols-2 grid-rows-1" : "grid-cols-2 grid-rows-2"}`, children: collageTiles.map((tile, i) => (_jsxs(Div, { className: "relative overflow-hidden bg-[var(--appkit-color-surface-muted)]", children: [_jsx("img", { src: tile.imageURL, alt: tile.title ?? `${bundle.name} item ${i + 1}`, loading: "lazy", className: "absolute inset-0 h-full w-full object-cover" }), i === collageTiles.length - 1 && overflow > 0 && (_jsxs(Div, { className: "absolute inset-0 flex items-center justify-center bg-black/55 text-sm font-semibold text-white", children: ["+", overflow] }))] }, `${tile.productId}-${i}`))) })) : cover ? (_jsx(Div, { className: "absolute inset-0 bg-[var(--appkit-color-surface-muted)]", children: _jsx("img", { src: cover, alt: bundle.name, loading: "lazy", className: "h-full w-full object-cover" }) })) : (_jsx(Div, { className: "absolute inset-0 flex items-center justify-center bg-[var(--appkit-color-surface-muted)]", children: _jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)]", children: "No image" }) })) }), _jsxs(Div, { className: "absolute right-2 top-2 flex flex-col items-end gap-1", children: [_jsx(Span, { className: "inline-flex items-center rounded-full bg-violet-600 px-2 py-0.5 text-xs font-medium text-white", children: mergedLabels.bundleBadge }), _jsx(Span, { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${stock === "out_of_stock"
48
+ return (_jsxs(BaseListingCard, { isSelected: isSelected, variant: variant, className: className, onMouseDown: !isSelected ? longPress.onMouseDown : undefined, onMouseUp: !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: !isSelected ? longPress.onTouchEnd : undefined, children: [_jsxs(BaseListingCard.Hero, { aspect: "square", variant: variant, children: [_jsx(TextLink, { href: String(detailHref), className: "absolute inset-0 block", children: showCollage ? (_jsx(Div, { className: `grid h-full w-full gap-0.5 bg-[var(--appkit-color-surface-muted)] ${collageTiles.length === 2 ? "grid-cols-2 grid-rows-1" : "grid-cols-2 grid-rows-2"}`, children: collageTiles.map((tile, i) => (_jsxs(Div, { className: "relative overflow-hidden bg-[var(--appkit-color-surface-muted)]", children: [_jsx("img", { src: tile.imageURL, alt: tile.title ?? `${bundle.name} item ${i + 1}`, loading: "lazy", className: "absolute inset-0 h-full w-full object-cover" }), i === collageTiles.length - 1 && overflow > 0 && (_jsxs(Div, { className: "absolute inset-0 flex items-center justify-center bg-black/55 text-sm font-semibold text-white", children: ["+", overflow] }))] }, `${tile.productId}-${i}`))) })) : cover ? (_jsx(Div, { className: "absolute inset-0 bg-[var(--appkit-color-surface-muted)]", children: _jsx("img", { src: cover, alt: bundle.name, loading: "lazy", className: "h-full w-full object-cover" }) })) : (_jsx(Div, { className: "absolute inset-0 flex items-center justify-center bg-[var(--appkit-color-surface-muted)]", children: _jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)]", children: "No image" }) })) }), _jsxs(Div, { className: "absolute right-2 top-2 flex flex-col items-end gap-1", children: [_jsx(Span, { size: "xs", weight: "medium", className: CLS_BUNDLE_PILL, children: mergedLabels.bundleBadge }), _jsx(Span, { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${stock === "out_of_stock"
46
49
  ? "bg-zinc-500 text-white"
47
- : "bg-emerald-600 text-white"}`, children: stock === "out_of_stock" ? mergedLabels.outOfStockBadge : mergedLabels.inStockBadge })] }), stock === "out_of_stock" && (_jsx(Div, { className: "absolute inset-0 flex items-center justify-center bg-black/40", children: _jsx(Span, { className: "rounded bg-zinc-900/80 px-3 py-1 text-xs font-bold uppercase tracking-wider text-white", children: mergedLabels.outOfStockBadge }) })), onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (event) => {
50
+ : CLS_STOCK_OK}`, children: stock === "out_of_stock" ? mergedLabels.outOfStockBadge : mergedLabels.inStockBadge })] }), stock === "out_of_stock" && (_jsx(Div, { className: "absolute inset-0 flex items-center justify-center bg-black/40", children: _jsx(Span, { size: "xs", weight: "bold", className: "rounded bg-zinc-900/80 px-3 py-1 uppercase tracking-wider text-white", children: mergedLabels.outOfStockBadge }) })), onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (event) => {
48
51
  event.stopPropagation();
49
52
  onSelect(bundle.id, !isSelected);
50
53
  }, className: selectable || isSelected
51
54
  ? "opacity-100"
52
55
  : "opacity-0 group-hover:opacity-100 transition-opacity" }))] }), _jsxs(BaseListingCard.Info, { variant: variant, children: [_jsx(TextLink, { href: String(detailHref), children: _jsx(Text, { className: `${THEME_CONSTANTS.utilities.textClamp2} text-sm font-medium text-zinc-900 dark:text-zinc-100`, children: bundle.name }) }), _jsxs(Row, { justify: "between", className: "mt-1 gap-2", children: [_jsx(Text, { className: "text-sm font-semibold text-zinc-900 dark:text-zinc-100", children: price
53
56
  ? formatCurrency(price / 100, getDefaultCurrency())
54
- : "—" }), _jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)]", children: mergedLabels.itemsLabel(memberCount) })] }), _jsx("div", { className: "mt-2 w-full cursor-pointer rounded-md bg-violet-600 py-1.5 text-center text-xs font-semibold text-white transition-colors hover:bg-violet-700 active:scale-[0.98]", role: "button", tabIndex: 0, onClick: handleNavigate, onKeyDown: (e) => { if (e.key === "Enter" || e.key === " ")
57
+ : "—" }), _jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)]", children: mergedLabels.itemsLabel(memberCount) })] }), _jsx("div", { className: CLS_VIEW_BTN, role: "button", tabIndex: 0, onClick: handleNavigate, onKeyDown: (e) => { if (e.key === "Enter" || e.key === " ")
55
58
  handleNavigate(); }, children: "View Bundle" })] })] }));
56
59
  }
@@ -7,6 +7,7 @@ import { ROUTES } from "../../../next";
7
7
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
8
8
  import { formatCurrency } from "../../../utils";
9
9
  import { getDefaultCurrency } from "../../../core/baseline-resolver";
10
+ const CLS_PRIZE_PILL = "inline-flex items-center rounded-full bg-fuchsia-600 px-2 py-0.5 text-white";
10
11
  import { BaseListingCard, Button, Div, Row, Span, Text, TextLink, } from "../../../ui";
11
12
  import { THEME_CONSTANTS } from "../../../tokens";
12
13
  const DEFAULT_LABELS = {
@@ -94,10 +95,10 @@ export function MarketplacePrizeDrawCard({ product, className = "", variant = "g
94
95
  return (_jsx(Div, { className: "relative overflow-hidden bg-[var(--appkit-color-surface-muted)]", children: img ? (
95
96
  /* eslint-disable-next-line @next/next/no-raw-media-elements, @next/next/no-img-element */
96
97
  _jsx("img", { src: img, alt: it?.title ?? `Prize ${i + 1}`, loading: "lazy", className: "absolute inset-0 h-full w-full object-cover" })) : null }, `thumb-${i}`));
97
- }) })) : (_jsx(Div, { className: "absolute inset-0 flex items-center justify-center bg-[var(--appkit-color-surface-muted)]", children: _jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)]", children: "No prizes" }) })) }), _jsxs(Div, { className: "absolute right-2 top-2 flex flex-col items-end gap-1", children: [_jsx(Span, { className: "inline-flex items-center rounded-full bg-fuchsia-600 px-2 py-0.5 text-xs font-medium text-white", children: mergedLabels.prizeDrawBadge }), _jsx(Span, { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${statusVariant(status)}`, children: statusLabel(status, mergedLabels) })] }), status === "closed" ? (_jsx(Div, { className: "absolute inset-0 flex items-center justify-center bg-black/40", children: _jsx(Span, { className: "rounded bg-zinc-900/80 px-3 py-1 text-xs font-bold uppercase tracking-wider text-white", children: mergedLabels.closedBadge }) })) : null, onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (event) => {
98
+ }) })) : (_jsx(Div, { className: "absolute inset-0 flex items-center justify-center bg-[var(--appkit-color-surface-muted)]", children: _jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)]", children: "No prizes" }) })) }), _jsxs(Div, { className: "absolute right-2 top-2 flex flex-col items-end gap-1", children: [_jsx(Span, { size: "xs", weight: "medium", className: CLS_PRIZE_PILL, children: mergedLabels.prizeDrawBadge }), _jsx(Span, { size: "xs", weight: "medium", className: `inline-flex items-center rounded-full px-2 py-0.5 ${statusVariant(status)}`, children: statusLabel(status, mergedLabels) })] }), status === "closed" ? (_jsx(Div, { className: "absolute inset-0 flex items-center justify-center bg-black/40", children: _jsx(Span, { size: "xs", weight: "bold", className: "rounded bg-zinc-900/80 px-3 py-1 uppercase tracking-wider text-white", children: mergedLabels.closedBadge }) })) : null, onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (event) => {
98
99
  event.stopPropagation();
99
100
  onSelect(product.id, !isSelected);
100
101
  }, className: selectable || isSelected
101
102
  ? "opacity-100"
102
- : "opacity-0 group-hover:opacity-100 transition-opacity" }))] }), _jsxs(BaseListingCard.Info, { variant: variant, children: [_jsx(TextLink, { href: String(detailHref), children: _jsx(Text, { className: `${THEME_CONSTANTS.utilities.textClamp2} text-sm font-medium text-zinc-900 dark:text-zinc-100`, children: product.title }) }), _jsxs(Row, { justify: "between", className: "mt-1 gap-2", children: [_jsxs(Text, { className: "text-sm font-semibold text-zinc-900 dark:text-zinc-100", children: [formatCurrency(pricePerEntry, getDefaultCurrency()), " ", _jsx(Span, { className: "text-xs font-normal text-[var(--appkit-color-text-muted)]", children: mergedLabels.pricePerEntryLabel })] }), max > 0 ? (_jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)]", children: mergedLabels.entriesRemainingLabel(remaining, max) })) : null] }), countdown ? (_jsxs(Text, { className: "text-xs text-[var(--appkit-color-text-muted)]", children: [status === "pending" ? "Opens in" : "Closes in", " ", countdown] })) : null, _jsx(Button, { type: "button", variant: "primary", size: "sm", className: "mt-2 w-full text-xs", onClick: handleNavigate, disabled: status === "closed" || remaining === 0, children: mergedLabels.enterDraw })] })] }));
103
+ : "opacity-0 group-hover:opacity-100 transition-opacity" }))] }), _jsxs(BaseListingCard.Info, { variant: variant, children: [_jsx(TextLink, { href: String(detailHref), children: _jsx(Text, { className: `${THEME_CONSTANTS.utilities.textClamp2} text-sm font-medium text-zinc-900 dark:text-zinc-100`, children: product.title }) }), _jsxs(Row, { justify: "between", className: "mt-1 gap-2", children: [_jsxs(Text, { className: "text-sm font-semibold text-zinc-900 dark:text-zinc-100", children: [formatCurrency(pricePerEntry, getDefaultCurrency()), " ", _jsx(Span, { size: "xs", weight: "normal", className: "text-[var(--appkit-color-text-muted)]", children: mergedLabels.pricePerEntryLabel })] }), max > 0 ? (_jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)]", children: mergedLabels.entriesRemainingLabel(remaining, max) })) : null] }), countdown ? (_jsxs(Text, { className: "text-xs text-[var(--appkit-color-text-muted)]", children: [status === "pending" ? "Opens in" : "Closes in", " ", countdown] })) : null, _jsx(Button, { type: "button", variant: "primary", size: "sm", className: "mt-2 w-full text-xs", onClick: handleNavigate, disabled: status === "closed" || remaining === 0, children: mergedLabels.enterDraw })] })] }));
103
104
  }
@@ -1,6 +1,7 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Div } from "../../../ui/components/Div";
2
3
  export function PlaceBidForm({ renderInput, renderAction, renderBidInfo, renderError, renderAuthGate, renderCountdown, className = "", }) {
3
4
  if (renderAuthGate)
4
5
  return _jsx(_Fragment, { children: renderAuthGate() });
5
- return (_jsxs("div", { className: `space-y-4 ${className}`, "data-section": "placebidform-div-424", children: [renderCountdown?.(), renderBidInfo?.(), renderError?.(), renderInput?.(), renderAction?.()] }));
6
+ return (_jsxs(Div, { className: `space-y-4 ${className}`, children: [renderCountdown?.(), renderBidInfo?.(), renderError?.(), renderInput?.(), renderAction?.()] }));
6
7
  }
@@ -17,6 +17,10 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
17
17
  import { useState } from "react";
18
18
  import { Div, Text } from "../../../ui";
19
19
  import { ImageLightbox } from "../../../ui/components/ImageLightbox";
20
+ const __P = {
21
+ p6: "p-6",
22
+ };
23
+ const CLS_WON_STAMP = "rotate-[-12deg] rounded bg-red-600 px-3 py-1 text-xs font-bold uppercase tracking-wider text-white shadow";
20
24
  function makePrizeItemClickHandler(it, idx, onItemClick, setLightboxIndex) {
21
25
  return () => {
22
26
  if (onItemClick) {
@@ -42,7 +46,7 @@ function toGalleryImages(items) {
42
46
  export function PrizeDrawCollage({ items, highlightItemNumber, onItemClick, wonLabel = "Won", hideWonState = false, }) {
43
47
  const [lightboxIndex, setLightboxIndex] = useState(null);
44
48
  if (!items.length) {
45
- return (_jsx(Div, { className: "rounded border border-dashed border-[var(--appkit-color-border)] p-6 text-center", children: _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "No prizes configured yet." }) }));
49
+ return (_jsx(Div, { className: `rounded border border-dashed border-[var(--appkit-color-border)] ${__P.p6} text-center`, children: _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "No prizes configured yet." }) }));
46
50
  }
47
51
  const galleryImages = toGalleryImages(items);
48
52
  return (_jsxs(_Fragment, { children: [_jsx(Div, { className: "grid grid-cols-2 gap-3 sm:grid-cols-3 md:grid-cols-4", children: items.map((it, idx) => {
@@ -56,7 +60,7 @@ export function PrizeDrawCollage({ items, highlightItemNumber, onItemClick, wonL
56
60
  : "hover:scale-[1.01]",
57
61
  ].join(" "), "aria-label": `View ${it.title || `prize #${it.itemNumber}`} in lightbox`, children: [_jsxs(Div, { className: "relative aspect-square w-full", children: [cover ? (
58
62
  /* eslint-disable-next-line @next/next/no-img-element */
59
- _jsx("img", { src: cover, alt: it.title || `Prize #${it.itemNumber}`, className: "absolute inset-0 h-full w-full object-cover", loading: "lazy" })) : (_jsx(Div, { className: "absolute inset-0 flex items-center justify-center bg-[var(--appkit-color-surface-muted)]", children: _jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)]", children: "No image" }) })), _jsxs(Div, { className: "absolute left-2 top-2 rounded bg-black/70 px-1.5 py-0.5 text-xs font-semibold text-white", children: ["#", it.itemNumber] }), it.isWon && !hideWonState ? (_jsxs(_Fragment, { children: [_jsx(Div, { "aria-hidden": true, className: "absolute inset-0 bg-gradient-to-br from-black/60 via-black/30 to-black/60 mix-blend-multiply" }), _jsx(Div, { className: "absolute inset-0 flex items-center justify-center", children: _jsx(Text, { className: "rotate-[-12deg] rounded bg-red-600 px-3 py-1 text-xs font-bold uppercase tracking-wider text-white shadow", children: wonLabel }) })] })) : null] }), _jsxs(Div, { className: "p-2", children: [_jsx(Text, { className: "line-clamp-2 text-sm font-medium", children: it.title || `Prize #${it.itemNumber}` }), it.estimatedValue != null ? (_jsxs(Text, { className: "text-xs text-[var(--appkit-color-text-muted)]", children: ["est. \u20B9", (it.estimatedValue / 100).toLocaleString("en-IN")] })) : null] })] }, `collage-${it.itemNumber}`));
63
+ _jsx("img", { src: cover, alt: it.title || `Prize #${it.itemNumber}`, className: "absolute inset-0 h-full w-full object-cover", loading: "lazy" })) : (_jsx(Div, { className: "absolute inset-0 flex items-center justify-center bg-[var(--appkit-color-surface-muted)]", children: _jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)]", children: "No image" }) })), _jsxs(Div, { className: "absolute left-2 top-2 rounded bg-black/70 px-1.5 py-0.5 text-xs font-semibold text-white", children: ["#", it.itemNumber] }), it.isWon && !hideWonState ? (_jsxs(_Fragment, { children: [_jsx(Div, { "aria-hidden": true, className: "absolute inset-0 bg-gradient-to-br from-black/60 via-black/30 to-black/60 mix-blend-multiply" }), _jsx(Div, { className: "absolute inset-0 flex items-center justify-center", children: _jsx(Text, { className: CLS_WON_STAMP, children: wonLabel }) })] })) : null] }), _jsxs(Div, { className: "p-2", children: [_jsx(Text, { className: "line-clamp-2 text-sm font-medium", children: it.title || `Prize #${it.itemNumber}` }), it.estimatedValue != null ? (_jsxs(Text, { className: "text-xs text-[var(--appkit-color-text-muted)]", children: ["est. \u20B9", (it.estimatedValue / 100).toLocaleString("en-IN")] })) : null] })] }, `collage-${it.itemNumber}`));
60
64
  }) }), _jsx(ImageLightbox, { images: galleryImages, activeIndex: lightboxIndex, onClose: () => setLightboxIndex(null), onNavigate: (i) => setLightboxIndex(i), showThumbnails: true })] }));
61
65
  }
62
66
  export default PrizeDrawCollage;
@@ -1,6 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import Link from "next/link";
3
3
  import { orderRepository, productRepository } from "../../../repositories";
4
+ const __P = {
5
+ p3: "p-3",
6
+ p4: "p-4",
7
+ };
8
+ const CLS_PRIZE_BADGE = "inline-block rounded-full bg-fuchsia-100 dark:bg-fuchsia-900/30 px-2.5 py-0.5 text-fuchsia-700 dark:text-fuchsia-300";
4
9
  import { ROUTES } from "../../../next";
5
10
  import { getDefaultCurrency } from "../../../core/baseline-resolver";
6
11
  import { normalizeRichTextHtml } from "../../../utils/string.formatter";
@@ -113,5 +118,5 @@ export async function PrizeDrawDetailPageView({ id, initialPrizeDraw, currentUse
113
118
  price: pricePerEntry,
114
119
  storeId: typeof p.storeId === "string" ? p.storeId : undefined,
115
120
  storeName: storeName ?? undefined,
116
- } }), _jsxs(Container, { size: "xl", className: "px-4 py-6", children: [_jsxs("div", { className: "mb-4 flex items-center justify-between flex-wrap gap-2", children: [_jsxs("nav", { "aria-label": "Breadcrumb", className: "flex items-center gap-1.5 text-xs text-zinc-500 dark:text-zinc-400 flex-wrap", children: [_jsx(Link, { href: String(ROUTES.HOME), className: "hover:text-primary-600 transition-colors", children: "Home" }), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.PRIZE_DRAWS), className: "hover:text-primary-600 transition-colors", children: "Prize Draws" }), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Span, { className: "text-zinc-700 dark:text-zinc-300 truncate max-w-[200px]", children: title })] }), _jsx(ShareButton, { title: title })] }), _jsx(PreOrderDetailView, { renderGallery: () => (_jsx(PrizeDrawCollage, { items: items, hideWonState: true })), renderInfo: () => (_jsxs(Stack, { gap: "md", children: [_jsxs(Div, { children: [_jsxs(Row, { gap: "xs", className: "mb-2 flex-wrap", children: [_jsx(Span, { className: "inline-block rounded-full bg-fuchsia-100 dark:bg-fuchsia-900/30 px-2.5 py-0.5 text-xs font-semibold text-fuchsia-700 dark:text-fuchsia-300", children: "Prize Draw" }), _jsx(Span, { className: `inline-block rounded-full px-2.5 py-0.5 text-xs font-semibold ${statusClass(revealStatus)}`, children: statusLabel(revealStatus) }), maxPerUser !== null && (_jsxs(Span, { className: "inline-block rounded-full bg-zinc-100 dark:bg-zinc-800 px-2.5 py-0.5 text-xs font-medium text-zinc-700 dark:text-zinc-300", children: ["Limit: ", maxPerUser, " entries per customer"] })), maxPerUser !== null && userEntriesUsed !== null && (_jsxs(Span, { className: "inline-block rounded-full bg-fuchsia-100 dark:bg-fuchsia-900/30 px-2.5 py-0.5 text-xs font-semibold text-fuchsia-700 dark:text-fuchsia-300", children: ["You have used ", userEntriesUsed, "/", maxPerUser] }))] }), _jsx(Heading, { level: 1, className: "text-xl font-bold leading-snug text-zinc-900 dark:text-zinc-50 sm:text-2xl", children: title })] }), _jsx(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 p-4", children: _jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "Entries" }), _jsxs(Text, { className: "text-sm font-semibold", children: [current, " / ", max, " (", remaining, " left)"] })] }), revealStart && (_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "Reveal window opens" }), _jsx(Text, { className: "text-sm font-medium", children: revealStart.toLocaleString() })] })), revealEnd && (_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "Reveal window closes" }), _jsx(Text, { className: "text-sm font-medium", children: revealEnd.toLocaleString() })] }))] }) }), descriptionHtml && (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "text-sm leading-relaxed text-zinc-600 dark:text-zinc-400 line-clamp-4" })), safeSeller && (_jsx(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 p-3", children: _jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-[10px] uppercase tracking-wide text-zinc-400 dark:text-zinc-400 mb-0.5", children: "Sold by" }), _jsx(Text, { className: "text-sm font-semibold text-zinc-800 dark:text-zinc-200", children: safeSeller })] }), storeHref && (_jsx(Link, { href: storeHref, className: "shrink-0 rounded-lg bg-primary/10 dark:bg-primary/20 px-3 py-1.5 text-xs font-semibold text-primary-700 dark:text-primary-300 hover:bg-primary/20 dark:hover:bg-primary/30 transition-colors", children: "Visit Store \u2192" }))] }) }))] })), renderTabs: () => (_jsx(ProductTabsShell, { descriptionContent: descriptionHtml ? (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm sm:prose max-w-none dark:prose-invert", className: "text-zinc-700 dark:text-zinc-300" })) : undefined })), renderBuyBar: () => (_jsx(Div, { id: "prize-draw-buy-bar", className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 p-5", children: _jsx(PrizeDrawEntryActions, { productId: String(product.id), productSlug: slug, title: title, thumb: thumb, pricePerEntry: pricePerEntry, currency: currency, remainingEntries: remaining, revealStatus: revealStatus, prizeGithubFileUrl: githubUrl, storeId: typeof p.storeId === "string" ? p.storeId : undefined, storeName: storeName ?? undefined }) })) }), _jsx(PrizeDrawBottomActions, { pricePerEntry: pricePerEntry, currency: currency, closed: revealStatus === "closed" || remaining === 0 })] })] }));
121
+ } }), _jsxs(Container, { size: "xl", className: "px-4 py-6", children: [_jsxs(Div, { className: "mb-4 flex items-center justify-between flex-wrap gap-2", children: [_jsxs("nav", { "aria-label": "Breadcrumb", className: "flex items-center gap-1.5 text-xs text-zinc-500 dark:text-zinc-400 flex-wrap", children: [_jsx(Link, { href: String(ROUTES.HOME), className: "hover:text-primary-600 transition-colors", children: "Home" }), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.PRIZE_DRAWS), className: "hover:text-primary-600 transition-colors", children: "Prize Draws" }), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Span, { className: "text-zinc-700 dark:text-zinc-300 truncate max-w-[200px]", children: title })] }), _jsx(ShareButton, { title: title })] }), _jsx(PreOrderDetailView, { renderGallery: () => (_jsx(PrizeDrawCollage, { items: items, hideWonState: true })), renderInfo: () => (_jsxs(Stack, { gap: "md", children: [_jsxs(Div, { children: [_jsxs(Row, { gap: "xs", className: "mb-2 flex-wrap", children: [_jsx(Span, { size: "xs", weight: "semibold", className: CLS_PRIZE_BADGE, children: "Prize Draw" }), _jsx(Span, { size: "xs", weight: "semibold", className: `inline-block rounded-full px-2.5 py-0.5 ${statusClass(revealStatus)}`, children: statusLabel(revealStatus) }), maxPerUser !== null && (_jsxs(Span, { size: "xs", weight: "medium", className: "inline-block rounded-full bg-zinc-100 dark:bg-zinc-800 px-2.5 py-0.5 text-zinc-700 dark:text-zinc-300", children: ["Limit: ", maxPerUser, " entries per customer"] })), maxPerUser !== null && userEntriesUsed !== null && (_jsxs(Span, { size: "xs", weight: "semibold", className: CLS_PRIZE_BADGE, children: ["You have used ", userEntriesUsed, "/", maxPerUser] }))] }), _jsx(Heading, { level: 1, className: "text-xl font-bold leading-snug text-zinc-900 dark:text-zinc-50 sm:text-2xl", children: title })] }), _jsx(Div, { className: `rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 ${__P.p4}`, children: _jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "Entries" }), _jsxs(Text, { className: "text-sm font-semibold", children: [current, " / ", max, " (", remaining, " left)"] })] }), revealStart && (_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "Reveal window opens" }), _jsx(Text, { className: "text-sm font-medium", children: revealStart.toLocaleString() })] })), revealEnd && (_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "Reveal window closes" }), _jsx(Text, { className: "text-sm font-medium", children: revealEnd.toLocaleString() })] }))] }) }), descriptionHtml && (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "text-sm leading-relaxed text-zinc-600 dark:text-zinc-400 line-clamp-4" })), safeSeller && (_jsx(Div, { className: `rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 ${__P.p3}`, children: _jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-[10px] uppercase tracking-wide text-zinc-400 dark:text-zinc-400 mb-0.5", children: "Sold by" }), _jsx(Text, { className: "text-sm font-semibold text-zinc-800 dark:text-zinc-200", children: safeSeller })] }), storeHref && (_jsx(Link, { href: storeHref, className: "shrink-0 rounded-lg bg-primary/10 dark:bg-primary/20 px-3 py-1.5 text-xs font-semibold text-primary-700 dark:text-primary-300 hover:bg-primary/20 dark:hover:bg-primary/30 transition-colors", children: "Visit Store \u2192" }))] }) }))] })), renderTabs: () => (_jsx(ProductTabsShell, { descriptionContent: descriptionHtml ? (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm sm:prose max-w-none dark:prose-invert", className: "text-zinc-700 dark:text-zinc-300" })) : undefined })), renderBuyBar: () => (_jsx(Div, { id: "prize-draw-buy-bar", className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 p-5", children: _jsx(PrizeDrawEntryActions, { productId: String(product.id), productSlug: slug, title: title, thumb: thumb, pricePerEntry: pricePerEntry, currency: currency, remainingEntries: remaining, revealStatus: revealStatus, prizeGithubFileUrl: githubUrl, storeId: typeof p.storeId === "string" ? p.storeId : undefined, storeName: storeName ?? undefined }) })) }), _jsx(PrizeDrawBottomActions, { pricePerEntry: pricePerEntry, currency: currency, closed: revealStatus === "closed" || remaining === 0 })] })] }));
117
122
  }
@@ -12,6 +12,8 @@ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
12
12
  */
13
13
  import { useCallback } from "react";
14
14
  import { Button, Div, FormField, Heading, Row, Span, Stack, Text } from "../../../ui";
15
+ const CLS_WARN_BOX = "rounded border border-yellow-400/40 bg-yellow-50 px-3 py-2 text-sm text-yellow-900 dark:bg-yellow-900/30 dark:text-yellow-100";
16
+ const CLS_WON_BADGE = "rounded bg-red-600 px-3 py-1 text-xs font-semibold uppercase tracking-wide text-white";
15
17
  import { ImageUpload } from "../../media";
16
18
  const MIN_ITEMS = 3;
17
19
  const MAX_ITEMS = 16;
@@ -84,9 +86,9 @@ export function PrizeDrawItemsEditor({ items, onChange, onUploadImage, onUploadV
84
86
  const nextImgs = (cur.images ?? []).filter((_, i) => i !== slot);
85
87
  update(index, { images: nextImgs });
86
88
  };
87
- return (_jsxs(Stack, { gap: "md", children: [_jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Heading, { level: 3, children: ["Prize Items (", items.length, ")"] }), _jsxs(Button, { type: "button", variant: "secondary", onClick: addItem, disabled: anyWon || items.length >= MAX_ITEMS, children: ["+ Add prize (", items.length, "/", MAX_ITEMS, ")"] })] }), _jsxs(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: ["Add between ", MIN_ITEMS, " and ", MAX_ITEMS, " prizes. Each entry will reveal exactly one of these. Items marked won during a prior reveal cannot be edited or removed."] }), anyWon ? (_jsxs(Div, { className: "rounded border border-error/40 bg-error-surface px-3 py-2 text-sm text-error", children: [_jsx(Span, { weight: "bold", children: "Draw locked." }), " At least one prize has been revealed \u2014 this listing can no longer be edited. To run a similar draw, clone it into a new prize-draw listing."] })) : warning ? (_jsx(Div, { className: "rounded border border-yellow-400/40 bg-yellow-50 px-3 py-2 text-sm text-yellow-900 dark:bg-yellow-900/30 dark:text-yellow-100", children: warning })) : null, _jsx(Stack, { gap: "md", children: items.map((it, index) => {
89
+ return (_jsxs(Stack, { gap: "md", children: [_jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Heading, { level: 3, children: ["Prize Items (", items.length, ")"] }), _jsxs(Button, { type: "button", variant: "secondary", onClick: addItem, disabled: anyWon || items.length >= MAX_ITEMS, children: ["+ Add prize (", items.length, "/", MAX_ITEMS, ")"] })] }), _jsxs(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: ["Add between ", MIN_ITEMS, " and ", MAX_ITEMS, " prizes. Each entry will reveal exactly one of these. Items marked won during a prior reveal cannot be edited or removed."] }), anyWon ? (_jsxs(Div, { className: "rounded border border-error/40 bg-error-surface px-3 py-2 text-sm text-error", children: [_jsx(Span, { weight: "bold", children: "Draw locked." }), " At least one prize has been revealed \u2014 this listing can no longer be edited. To run a similar draw, clone it into a new prize-draw listing."] })) : warning ? (_jsx(Div, { className: CLS_WARN_BOX, children: warning })) : null, _jsx(Stack, { gap: "md", children: items.map((it, index) => {
88
90
  const locked = it.isWon || anyWon;
89
- return (_jsxs(Div, { className: `relative rounded-lg border border-[var(--appkit-color-border)] p-4 ${locked ? "opacity-60" : ""}`, children: [locked ? (_jsx(Div, { className: "absolute inset-0 z-10 flex items-center justify-center bg-black/10 dark:bg-black/40 rounded-lg pointer-events-none", children: _jsx(Text, { className: "rounded bg-red-600 px-3 py-1 text-xs font-semibold uppercase tracking-wide text-white", children: "Won \u2014 locked" }) })) : null, _jsxs(Row, { justify: "between", align: "center", className: "mb-3", children: [_jsxs(Heading, { level: 4, children: ["Prize #", it.itemNumber] }), _jsxs(Row, { gap: "xs", children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => move(index, -1), disabled: locked || index === 0, "aria-label": "Move up", children: "\u2191" }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => move(index, 1), disabled: locked || index === items.length - 1, "aria-label": "Move down", children: "\u2193" }), _jsx(Button, { type: "button", variant: "danger", size: "sm", onClick: () => removeItem(index), disabled: locked || items.length <= MIN_ITEMS, children: "Remove" })] })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(FormField, { name: `item-${index}-title`, label: "Title", type: "text", value: it.title, onChange: (v) => update(index, { title: v }), disabled: locked, placeholder: "e.g. PSA 9 Charizard Base Set Holo" }), _jsx(FormField, { name: `item-${index}-description`, label: "Description (optional)", type: "textarea", value: it.description ?? "", onChange: (v) => update(index, { description: v }), disabled: locked, placeholder: "What makes this prize special?" }), _jsxs(Row, { gap: "md", children: [_jsx(Div, { className: "flex-1", children: _jsx(FormField, { name: `item-${index}-condition`, label: "Condition", type: "select", value: it.condition, onChange: (v) => update(index, { condition: v }), disabled: locked, options: CONDITION_OPTIONS }) }), _jsx(Div, { className: "flex-1", children: _jsx(FormField, { name: `item-${index}-value`, label: "Estimated value (\u20B9)", type: "number", value: it.estimatedValue != null
91
+ return (_jsxs(Div, { className: `relative rounded-lg border border-[var(--appkit-color-border)] p-4 ${locked ? "opacity-60" : ""}`, children: [locked ? (_jsx(Div, { className: "absolute inset-0 z-10 flex items-center justify-center bg-black/10 dark:bg-black/40 rounded-lg pointer-events-none", children: _jsx(Text, { className: CLS_WON_BADGE, children: "Won \u2014 locked" }) })) : null, _jsxs(Row, { justify: "between", align: "center", className: "mb-3", children: [_jsxs(Heading, { level: 4, children: ["Prize #", it.itemNumber] }), _jsxs(Row, { gap: "xs", children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => move(index, -1), disabled: locked || index === 0, "aria-label": "Move up", children: "\u2191" }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => move(index, 1), disabled: locked || index === items.length - 1, "aria-label": "Move down", children: "\u2193" }), _jsx(Button, { type: "button", variant: "danger", size: "sm", onClick: () => removeItem(index), disabled: locked || items.length <= MIN_ITEMS, children: "Remove" })] })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(FormField, { name: `item-${index}-title`, label: "Title", type: "text", value: it.title, onChange: (v) => update(index, { title: v }), disabled: locked, placeholder: "e.g. PSA 9 Charizard Base Set Holo" }), _jsx(FormField, { name: `item-${index}-description`, label: "Description (optional)", type: "textarea", value: it.description ?? "", onChange: (v) => update(index, { description: v }), disabled: locked, placeholder: "What makes this prize special?" }), _jsxs(Row, { gap: "md", children: [_jsx(Div, { className: "flex-1", children: _jsx(FormField, { name: `item-${index}-condition`, label: "Condition", type: "select", value: it.condition, onChange: (v) => update(index, { condition: v }), disabled: locked, options: CONDITION_OPTIONS }) }), _jsx(Div, { className: "flex-1", children: _jsx(FormField, { name: `item-${index}-value`, label: "Estimated value (\u20B9)", type: "number", value: it.estimatedValue != null
90
92
  ? String(Math.round(it.estimatedValue / 100))
91
93
  : "", onChange: (v) => update(index, {
92
94
  estimatedValue: Math.round((parseFloat(v) || 0) * 100),
@@ -4,7 +4,7 @@ import { useState, useCallback } from "react";
4
4
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
5
5
  import { usePendingTable } from "../../../react/hooks/usePendingTable";
6
6
  import { useProducts } from "../hooks/useProducts";
7
- import { FilterDrawer, ListingToolbar, Pagination, Text } from "../../../ui";
7
+ import { Div, FilterDrawer, ListingToolbar, Pagination, Span, Text } from "../../../ui";
8
8
  import { useCategoryTree, categoriesToFacetOptions } from "../../categories/hooks/useCategoryTree";
9
9
  import { useBrands } from "../hooks/useBrands";
10
10
  import { MarketplacePrizeDrawCard } from "./MarketplacePrizeDrawCard";
@@ -12,6 +12,9 @@ import { ProductFilters } from "./ProductFilters";
12
12
  import { TABLE_KEYS, VIEW_MODE } from "../../../constants/table-keys";
13
13
  import { PRIZE_DRAW_SORT_OPTIONS } from "../constants/sieve";
14
14
  import { PRODUCT_FIELDS } from "../../../constants/field-names";
15
+ const __P = {
16
+ p3: "p-3",
17
+ };
15
18
  const DEFAULT_SORT = PRIZE_DRAW_SORT_OPTIONS[0].value;
16
19
  const FILTER_KEYS = [
17
20
  TABLE_KEYS.CATEGORY,
@@ -76,12 +79,12 @@ export function PrizeDrawsIndexListing({ initialData, categorySlug, brandName, s
76
79
  commitSearch();
77
80
  };
78
81
  const gridClass = "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4";
79
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search prize draws...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, onSearchKeyDown: handleSearchKeyDown, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: PRIZE_DRAW_SORT_OPTIONS, onSortChange: (v) => {
82
+ return (_jsxs(Div, { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search prize draws...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, onSearchKeyDown: handleSearchKeyDown, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: PRIZE_DRAW_SORT_OPTIONS, onSortChange: (v) => {
80
83
  table.set(TABLE_KEYS.SORT, v);
81
84
  }, view: view, onViewChange: (v) => {
82
85
  if (v === VIEW_MODE.TABLE)
83
86
  return;
84
87
  setView(v);
85
88
  table.set(TABLE_KEYS.VIEW, v);
86
- }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs("label", { className: "flex items-center gap-1.5 cursor-pointer select-none shrink-0", children: [_jsx("span", { className: "hidden sm:inline text-xs text-zinc-600 dark:text-zinc-300 whitespace-nowrap", children: "Show closed" }), _jsx("button", { type: "button", role: "switch", "aria-checked": showClosed, onClick: () => table.set("showClosed", showClosed ? "" : "true"), className: `relative inline-flex h-5 w-9 flex-shrink-0 items-center rounded-full transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1 ${showClosed ? "bg-primary" : "bg-zinc-300 dark:bg-slate-600"}`, children: _jsx("span", { className: `inline-block h-3.5 w-3.5 transform rounded-full bg-white shadow-sm transition-transform duration-200 ${showClosed ? "translate-x-[19px]" : "translate-x-[3px]"}` }) })] }) }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsx("div", { className: "py-6", children: isLoading ? (_jsx("div", { className: gridClass, children: Array.from({ length: 8 }).map((_, i) => (_jsxs("div", { className: "rounded-xl border border-zinc-100 dark:border-slate-700 overflow-hidden animate-pulse", children: [_jsx("div", { className: "aspect-square bg-zinc-200 dark:bg-slate-700" }), _jsxs("div", { className: "p-3 space-y-2", children: [_jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-3/4" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-1/2" }), _jsx("div", { className: "h-8 bg-zinc-200 dark:bg-slate-700 rounded" })] })] }, i))) })) : filteredDraws.length === 0 ? (_jsx(Text, { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: "No prize draws found." })) : (_jsx("div", { className: gridClass, children: filteredDraws.map((product) => (_jsx(MarketplacePrizeDrawCard, { product: product, variant: view }, product.id))) })) }), _jsx(FilterDrawer, { open: filterOpen, onOpen: openFilters, onClose: () => setFilterOpen(false), onApply: applyFilters, onReset: onFilterClear, activeCount: filterActiveCount, hideTrigger: true, children: _jsxs("div", { className: "space-y-4", children: [_jsxs(_Fragment, { children: [_jsx("label", { htmlFor: "prizeRevealStatusFilter", className: "block text-xs font-semibold text-zinc-700 dark:text-zinc-300 mb-1.5", children: "Reveal status" }), _jsxs("select", { id: "prizeRevealStatusFilter", value: pendingTable.get(TABLE_KEYS.PRIZE_REVEAL_STATUS) ?? "", onChange: (e) => pendingTable.set(TABLE_KEYS.PRIZE_REVEAL_STATUS, e.target.value), className: "w-full rounded border border-zinc-300 dark:border-slate-600 bg-white dark:bg-slate-800 px-2 py-1.5 text-sm", children: [_jsx("option", { value: "", children: "Any" }), _jsx("option", { value: "pending", children: "Reveal pending" }), _jsx("option", { value: "open", children: "Reveal open" }), _jsx("option", { value: "closed", children: "Closed" })] })] }), _jsx(ProductFilters, { table: pendingTable, currencyPrefix: "\u20B9", categoryOptions: categoryOptions, brandOptions: brandOptions })] }) })] }));
89
+ }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs("label", { className: "flex items-center gap-1.5 cursor-pointer select-none shrink-0", children: [_jsx(Span, { size: "xs", className: "hidden sm:inline text-zinc-600 dark:text-zinc-300 whitespace-nowrap", children: "Show closed" }), _jsx("button", { type: "button", role: "switch", "aria-checked": showClosed, onClick: () => table.set("showClosed", showClosed ? "" : "true"), className: `relative inline-flex h-5 w-9 flex-shrink-0 items-center rounded-full transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1 ${showClosed ? "bg-primary" : "bg-zinc-300 dark:bg-slate-600"}`, children: _jsx("span", { className: `inline-block h-3.5 w-3.5 transform rounded-full bg-white shadow-sm transition-transform duration-200 ${showClosed ? "translate-x-[19px]" : "translate-x-[3px]"}` }) })] }) }), totalPages > 1 && (_jsx(Div, { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsx(Div, { className: "py-6", children: isLoading ? (_jsx(Div, { className: gridClass, children: Array.from({ length: 8 }).map((_, i) => (_jsxs(Div, { className: "rounded-xl border border-zinc-100 dark:border-slate-700 overflow-hidden animate-pulse", children: [_jsx(Div, { className: "aspect-square bg-zinc-200 dark:bg-slate-700" }), _jsxs(Div, { className: `${__P.p3} space-y-2`, children: [_jsx(Div, { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-3/4" }), _jsx(Div, { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-1/2" }), _jsx(Div, { className: "h-8 bg-zinc-200 dark:bg-slate-700 rounded" })] })] }, i))) })) : filteredDraws.length === 0 ? (_jsx(Text, { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: "No prize draws found." })) : (_jsx(Div, { className: gridClass, children: filteredDraws.map((product) => (_jsx(MarketplacePrizeDrawCard, { product: product, variant: view }, product.id))) })) }), _jsx(FilterDrawer, { open: filterOpen, onOpen: openFilters, onClose: () => setFilterOpen(false), onApply: applyFilters, onReset: onFilterClear, activeCount: filterActiveCount, hideTrigger: true, children: _jsxs(Div, { className: "space-y-4", children: [_jsxs(_Fragment, { children: [_jsx("label", { htmlFor: "prizeRevealStatusFilter", className: "block text-xs font-semibold text-zinc-700 dark:text-zinc-300 mb-1.5", children: "Reveal status" }), _jsxs("select", { id: "prizeRevealStatusFilter", value: pendingTable.get(TABLE_KEYS.PRIZE_REVEAL_STATUS) ?? "", onChange: (e) => pendingTable.set(TABLE_KEYS.PRIZE_REVEAL_STATUS, e.target.value), className: "w-full rounded border border-zinc-300 dark:border-slate-600 bg-white dark:bg-slate-800 px-2 py-1.5 text-sm", children: [_jsx("option", { value: "", children: "Any" }), _jsx("option", { value: "pending", children: "Reveal pending" }), _jsx("option", { value: "open", children: "Reveal open" }), _jsx("option", { value: "closed", children: "Closed" })] })] }), _jsx(ProductFilters, { table: pendingTable, currencyPrefix: "\u20B9", categoryOptions: categoryOptions, brandOptions: brandOptions })] }) })] }));
87
90
  }
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import Link from "next/link";
3
- import { Container, Heading, Section, Stack, Text, } from "../../../ui";
3
+ import { Container, Div, Heading, Section, Stack, Text, } from "../../../ui";
4
4
  import { ROUTES } from "../../../next";
5
5
  import { productRepository } from "../repository/products.repository";
6
6
  import { InteractiveProductCard } from "./InteractiveProductCard";
@@ -24,5 +24,5 @@ export async function PrizeDrawsSection({ config, }) {
24
24
  catch {
25
25
  draws = [];
26
26
  }
27
- return (_jsx(Section, { className: "py-10", children: _jsx(Container, { size: "xl", children: _jsxs(Stack, { gap: "md", children: [_jsxs(Stack, { gap: "xs", children: [_jsx(Heading, { level: 2, className: "text-2xl font-semibold text-zinc-900 dark:text-zinc-50", children: title }), subtitle ? (_jsx(Text, { className: "text-sm text-zinc-500 dark:text-zinc-400", children: subtitle })) : null] }), draws.length === 0 ? (_jsxs(Stack, { align: "center", gap: "sm", className: "rounded-2xl border border-dashed border-zinc-300 px-6 py-12 text-center dark:border-slate-700", children: [_jsx(Text, { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "No active prize draws \u2014 new draws are announced regularly." }), _jsx(Link, { href: String(ROUTES.PUBLIC.AUCTIONS), className: "text-sm font-medium text-primary hover:underline", children: "Browse live auctions \u2192" })] })) : (_jsx("div", { className: "fluid-grid-card gap-3", children: draws.map((draw) => (_jsx(InteractiveProductCard, { product: draw, href: String(ROUTES.PUBLIC.PRODUCT_DETAIL(draw.slug ?? draw.id ?? "")) }, draw.id))) }))] }) }) }));
27
+ return (_jsx(Section, { className: "py-10", children: _jsx(Container, { size: "xl", children: _jsxs(Stack, { gap: "md", children: [_jsxs(Stack, { gap: "xs", children: [_jsx(Heading, { level: 2, className: "text-2xl font-semibold text-zinc-900 dark:text-zinc-50", children: title }), subtitle ? (_jsx(Text, { className: "text-sm text-zinc-500 dark:text-zinc-400", children: subtitle })) : null] }), draws.length === 0 ? (_jsxs(Stack, { align: "center", gap: "sm", className: "rounded-2xl border border-dashed border-zinc-300 px-6 py-12 text-center dark:border-slate-700", children: [_jsx(Text, { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "No active prize draws \u2014 new draws are announced regularly." }), _jsx(Link, { href: String(ROUTES.PUBLIC.AUCTIONS), className: "text-sm font-medium text-primary hover:underline", children: "Browse live auctions \u2192" })] })) : (_jsx(Div, { className: "fluid-grid-card gap-3", children: draws.map((draw) => (_jsx(InteractiveProductCard, { product: draw, href: String(ROUTES.PUBLIC.PRODUCT_DETAIL(draw.slug ?? draw.id ?? "")) }, draw.id))) }))] }) }) }));
28
28
  }