@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
@@ -18,6 +18,10 @@ import { useCallback, useEffect, useRef, useState } from "react";
18
18
  import { Button, Div, Heading, LoginRequiredModal, Modal, Span, Stack, Text, useToast } from "../../../ui";
19
19
  import { isAuthError } from "../../../utils/auth-error";
20
20
  import { PrizeDrawCollage } from "./PrizeDrawCollage";
21
+ const __P = {
22
+ p4: "p-4",
23
+ };
24
+ const CLS_REFUND_NOTE = "rounded border border-yellow-400/40 bg-yellow-50 px-4 py-3 text-yellow-900 dark:bg-yellow-900/30 dark:text-yellow-100";
21
25
  const REVEAL_DURATION_MS = 3200; // total animation length
22
26
  const CYCLE_INTERVAL_FAST = 80;
23
27
  const CYCLE_INTERVAL_SLOW = 360;
@@ -143,7 +147,7 @@ export function PrizeRevealModal({ open, onClose, items, orderId, productId, onR
143
147
  }, REVEAL_DURATION_MS);
144
148
  }, [onReveal, orderId, phase, productId, startAnimation]);
145
149
  const winnerImg = winner?.images?.[0];
146
- return (_jsxs(Modal, { isOpen: open, onClose: onClose, title: "Prize Reveal", size: "lg", children: [_jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to reveal your prize. Please log in or create an account to continue." }), _jsxs(Stack, { gap: "md", children: [phase === "refunded" ? (_jsxs(Div, { className: "rounded border border-yellow-400/40 bg-yellow-50 px-4 py-3 text-yellow-900 dark:bg-yellow-900/30 dark:text-yellow-100", children: [_jsx(Heading, { level: 3, className: "mb-1", children: "Pool exhausted \u2014 you've been refunded" }), _jsx(Text, { className: "text-sm", children: "Every prize in this draw was already claimed by the time your entry rolled. Your order has been marked refunded automatically." })] })) : null, phase === "error" ? (_jsxs(Div, { className: "rounded border border-error/40 bg-error-surface px-4 py-3 text-error", children: [_jsx(Text, { className: "text-sm font-semibold", children: "Something went wrong" }), _jsx(Text, { className: "text-sm", children: errorMessage })] })) : null, _jsx(PrizeDrawCollage, { items: items, hideWonState: true, highlightItemNumber: highlight }), phase === "idle" ? (_jsx(Button, { type: "button", variant: "primary", size: "lg", onClick: handleRevealClick, children: "\u2728 Reveal my prize" })) : null, phase === "revealing" ? (_jsxs(Div, { className: "rounded bg-[var(--appkit-color-surface-muted)] p-4 text-center", children: [_jsx(Text, { className: "text-lg font-semibold", children: "Rolling\u2026" }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "The winner was locked by the server before this animation started. Hang tight \u2014 we're just making it look pretty." })] })) : null, phase === "won" && winner ? (_jsxs(Div, { className: "rounded-lg border-2 border-[var(--appkit-color-primary)] bg-[var(--appkit-color-surface)] p-4 text-center", children: [_jsx(Text, { className: "text-xs uppercase tracking-wider text-[var(--appkit-color-text-muted)]", children: "You won" }), _jsxs(Heading, { level: 2, className: "my-2", children: ["#", winner.itemNumber, " \u2014 ", winner.title] }), winnerImg ? (
150
+ return (_jsxs(Modal, { isOpen: open, onClose: onClose, title: "Prize Reveal", size: "lg", children: [_jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to reveal your prize. Please log in or create an account to continue." }), _jsxs(Stack, { gap: "md", children: [phase === "refunded" ? (_jsxs(Div, { className: CLS_REFUND_NOTE, children: [_jsx(Heading, { level: 3, className: "mb-1", children: "Pool exhausted \u2014 you've been refunded" }), _jsx(Text, { className: "text-sm", children: "Every prize in this draw was already claimed by the time your entry rolled. Your order has been marked refunded automatically." })] })) : null, phase === "error" ? (_jsxs(Div, { className: "rounded border border-error/40 bg-error-surface px-4 py-3 text-error", children: [_jsx(Text, { className: "text-sm font-semibold", children: "Something went wrong" }), _jsx(Text, { className: "text-sm", children: errorMessage })] })) : null, _jsx(PrizeDrawCollage, { items: items, hideWonState: true, highlightItemNumber: highlight }), phase === "idle" ? (_jsx(Button, { type: "button", variant: "primary", size: "lg", onClick: handleRevealClick, children: "\u2728 Reveal my prize" })) : null, phase === "revealing" ? (_jsxs(Div, { className: `rounded bg-[var(--appkit-color-surface-muted)] ${__P.p4} text-center`, children: [_jsx(Text, { className: "text-lg font-semibold", children: "Rolling\u2026" }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "The winner was locked by the server before this animation started. Hang tight \u2014 we're just making it look pretty." })] })) : null, phase === "won" && winner ? (_jsxs(Div, { className: `rounded-lg border-2 border-[var(--appkit-color-primary)] bg-[var(--appkit-color-surface)] ${__P.p4} text-center`, children: [_jsx(Text, { className: "text-xs uppercase tracking-wider text-[var(--appkit-color-text-muted)]", children: "You won" }), _jsxs(Heading, { level: 2, className: "my-2", children: ["#", winner.itemNumber, " \u2014 ", winner.title] }), winnerImg ? (
147
151
  /* eslint-disable-next-line @next/next/no-img-element */
148
152
  _jsx("img", { src: winnerImg, alt: winner.title, className: "mx-auto max-h-64 rounded" })) : null, winner.estimatedValue != null ? (_jsxs(Text, { className: "mt-2 text-sm text-[var(--appkit-color-text-muted)]", children: ["Estimated value: \u20B9", (winner.estimatedValue / 100).toLocaleString("en-IN")] })) : null] })) : null, _jsxs(Div, { className: "rounded border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-muted)] px-3 py-2 text-xs text-[var(--appkit-color-text-muted)]", children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Fairness guarantee:" }), " ", "Winners are picked by ", _jsx("code", { children: "crypto.randomInt" }), " running on LetItRip's server before the animation starts. The animation is theatrical \u2014 neither the store nor LetItRip staff can influence the outcome.", " ", effectiveRngUrl ? (_jsx("a", { href: effectiveRngUrl, target: "_blank", rel: "noreferrer noopener", className: "underline", children: "View RNG source code \u2192" })) : null] })] })] }));
149
153
  }
@@ -1,11 +1,29 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import Link from "next/link";
3
3
  import { productRepository, reviewRepository } from "../../../repositories";
4
+ const __P = {
5
+ p3: "p-3",
6
+ p5: "p-5",
7
+ };
4
8
  const CLS_BREADCRUMB_LINK = "hover:text-primary-600 transition-colors";
5
9
  const ACTION_NOT_WIRED = "Action not wired";
10
+ const CLS_STAR_FULL = "text-yellow-400 text-sm";
11
+ const CLS_STAR_HALF = "text-yellow-300 text-sm";
12
+ const CLS_STAR_EMPTY = "text-zinc-300 dark:text-zinc-600 text-sm";
13
+ const CLS_STOCK_IN = "bg-emerald-50 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400";
14
+ const CLS_STOCK_OUT = "bg-red-50 text-red-700 dark:bg-red-900/30 dark:text-red-400";
15
+ const CLS_BUNDLE_PILL = "inline-flex items-center gap-1 rounded-full border border-teal-300 bg-teal-50 px-2.5 py-1 text-xs font-semibold text-teal-700 transition-colors hover:border-teal-500 hover:bg-teal-100 dark:border-teal-800/60 dark:bg-teal-900/30 dark:text-teal-300 dark:hover:border-teal-600 dark:hover:bg-teal-900/50";
16
+ const CLS_DISCOUNT_BADGE = "rounded-full bg-red-500 px-2 py-0.5 text-white";
17
+ const CLS_FREE_SHIPPING_ICON = "mt-0.5 flex-shrink-0 text-emerald-500";
18
+ const CLS_BUNDLE_BOX = "rounded-xl border border-teal-200 dark:border-teal-800/60 bg-teal-50/60 dark:bg-teal-900/20 p-5";
19
+ const CLS_BUNDLE_ICON = "text-teal-600 dark:text-teal-400";
20
+ const CLS_BUNDLE_TITLE = "text-sm font-semibold text-teal-800 dark:text-teal-200";
21
+ const CLS_BUNDLE_ROW = "flex items-center justify-between gap-4 rounded-lg border border-teal-200 dark:border-teal-800/50 bg-white dark:bg-teal-900/30 px-4 py-3";
22
+ const CLS_BUNDLE_LABEL = "text-xs text-teal-600 dark:text-teal-400 font-medium uppercase tracking-wide mb-0.5";
23
+ const CLS_BUNDLE_CTA = "flex-shrink-0 rounded-lg bg-teal-600 hover:bg-teal-700 px-3 py-1.5 text-xs font-semibold text-white transition-colors";
6
24
  import { ROUTES } from "../../../next";
7
25
  import { getDefaultCurrency } from "../../../core/baseline-resolver";
8
- import { Button, Container, Div, Heading, Main, RichText, Row, Section, Span, Stack, Text, } from "../../../ui";
26
+ import { Button, Container, Div, Heading, Main, Nav, RichText, Row, Section, Span, Stack, Text, Ul, Ol, Li, Dl, Dt, Dd, } from "../../../ui";
9
27
  import { normalizeRichTextHtml } from "../../../utils/string.formatter";
10
28
  import { formatCurrency } from "../../../utils/number.formatter";
11
29
  import { safeDisplayName } from "../../../security";
@@ -80,10 +98,10 @@ function StarRating({ value }) {
80
98
  const full = Math.floor(value);
81
99
  const half = value - full >= 0.5;
82
100
  return (_jsx(Row, { align: "center", gap: "xs", children: Array.from({ length: 5 }).map((_, i) => (_jsx(Span, { className: i < full
83
- ? "text-yellow-400 text-sm"
101
+ ? CLS_STAR_FULL
84
102
  : i === full && half
85
- ? "text-yellow-300 text-sm"
86
- : "text-zinc-300 dark:text-zinc-600 text-sm", children: "\u2605" }, i))) }));
103
+ ? CLS_STAR_HALF
104
+ : CLS_STAR_EMPTY, children: "\u2605" }, i))) }));
87
105
  }
88
106
  // ---------------------------------------------------------------------------
89
107
  // Component
@@ -232,7 +250,7 @@ export async function ProductDetailPageView({ slug, initialProduct, renderOfferA
232
250
  price: product.price,
233
251
  storeId: product.storeId,
234
252
  storeName: product.storeName,
235
- } }), _jsxs(Container, { size: "xl", className: "px-4 py-6", children: [_jsx(ProductDetailView, { renderBreadcrumb: () => (_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: CLS_BREADCRUMB_LINK, children: "Home" }), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.PRODUCTS), className: CLS_BREADCRUMB_LINK, children: "Products" }), category && (_jsxs(_Fragment, { children: [_jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(category)), className: CLS_BREADCRUMB_LINK, children: categoryName || category })] })), subcategory && (_jsxs(_Fragment, { children: [_jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Span, { className: "capitalize", children: subcategory })] }))] }), _jsx(ShareButton, { title: title || undefined })] })), renderGallery: () => (_jsx(ProductGalleryClient, { images: images, productName: title || undefined })), renderInfo: () => (_jsxs(Stack, { gap: "md", children: [_jsxs(Div, { children: [condition && (_jsx(Span, { className: "mb-2 inline-block rounded-full bg-zinc-100 dark:bg-zinc-800 px-2.5 py-0.5 text-xs font-medium capitalize text-zinc-600 dark:text-zinc-300", children: condition === "new"
253
+ } }), _jsxs(Container, { size: "xl", className: "px-4 py-6", children: [_jsx(ProductDetailView, { renderBreadcrumb: () => (_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: CLS_BREADCRUMB_LINK, children: "Home" }), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.PRODUCTS), className: CLS_BREADCRUMB_LINK, children: "Products" }), category && (_jsxs(_Fragment, { children: [_jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(category)), className: CLS_BREADCRUMB_LINK, children: categoryName || category })] })), subcategory && (_jsxs(_Fragment, { children: [_jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Span, { className: "capitalize", children: subcategory })] }))] }), _jsx(ShareButton, { title: title || undefined })] })), renderGallery: () => (_jsx(ProductGalleryClient, { images: images, productName: title || undefined })), renderInfo: () => (_jsxs(Stack, { gap: "md", children: [_jsxs(Div, { children: [condition && (_jsx(Span, { size: "xs", weight: "medium", className: "mb-2 inline-block rounded-full bg-zinc-100 dark:bg-zinc-800 px-2.5 py-0.5 capitalize text-zinc-600 dark:text-zinc-300", children: condition === "new"
236
254
  ? "Brand New"
237
255
  : condition === "like_new"
238
256
  ? "Like New"
@@ -240,15 +258,13 @@ export async function ProductDetailPageView({ slug, initialProduct, renderOfferA
240
258
  ? "Refurbished"
241
259
  : condition === "used"
242
260
  ? "Used"
243
- : condition })), _jsx(Heading, { level: 1, className: "text-xl font-bold leading-snug text-zinc-900 dark:text-zinc-50 sm:text-2xl", children: title || "Untitled Product" })] }), avgRating !== null ? (_jsxs(Row, { align: "center", gap: "sm", children: [_jsx(StarRating, { value: avgRating }), _jsxs(Span, { className: "text-sm text-zinc-600 dark:text-zinc-400", children: [avgRating.toFixed(1), reviewCount ? ` (${reviewCount} reviews)` : ""] }), _jsxs(Span, { className: `ml-auto rounded-full px-2.5 py-0.5 text-xs font-medium ${inStock
261
+ : condition })), _jsx(Heading, { level: 1, className: "text-xl font-bold leading-snug text-zinc-900 dark:text-zinc-50 sm:text-2xl", children: title || "Untitled Product" })] }), avgRating !== null ? (_jsxs(Row, { align: "center", gap: "sm", children: [_jsx(StarRating, { value: avgRating }), _jsxs(Span, { size: "sm", className: "text-zinc-600 dark:text-zinc-400", children: [avgRating.toFixed(1), reviewCount ? ` (${reviewCount} reviews)` : ""] }), _jsxs(Span, { size: "xs", weight: "medium", className: `ml-auto rounded-full px-2.5 py-0.5 ${inStock
244
262
  ? "bg-success-surface text-success"
245
263
  : "bg-error-surface text-error"}`, children: [inStock ? "✓ In Stock" : "✗ Out of Stock", inStock && effectiveStock !== null && effectiveStock <= 10
246
264
  ? ` — only ${effectiveStock} left`
247
- : ""] })] })) : (_jsxs(Span, { className: `inline-flex w-fit items-center gap-1.5 rounded-full px-3 py-1 text-xs font-medium ${inStock
248
- ? "bg-emerald-50 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400"
249
- : "bg-red-50 text-red-700 dark:bg-red-900/30 dark:text-red-400"}`, children: [inStock ? "✓ In Stock" : "✗ Out of Stock", inStock && effectiveStock !== null && effectiveStock <= 10
265
+ : ""] })] })) : (_jsxs(Span, { className: `inline-flex w-fit items-center gap-1.5 rounded-full px-3 py-1 text-xs font-medium ${inStock ? CLS_STOCK_IN : CLS_STOCK_OUT}`, children: [inStock ? "✓ In Stock" : "✗ Out of Stock", inStock && effectiveStock !== null && effectiveStock <= 10
250
266
  ? ` — only ${effectiveStock} left`
251
- : ""] })), (categorySlugs.length > 0 || subcategory || brand) && (_jsxs(Row, { gap: "sm", wrap: true, children: [categorySlugs.map((slug, i) => (_jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(slug)), className: "inline-flex items-center rounded-full border border-zinc-200 dark:border-zinc-700 bg-zinc-50 dark:bg-zinc-800/50 px-2.5 py-1 text-xs font-medium text-zinc-600 dark:text-zinc-300 transition-colors hover:border-primary-300 hover:bg-primary-50 hover:text-primary-700 dark:hover:border-primary-700/60 dark:hover:bg-primary-900/20 dark:hover:text-primary-400", children: categoryNames[i] ?? slug }, slug))), subcategory && (_jsx(Span, { className: "inline-flex items-center rounded-full border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-800/50 px-2.5 py-1 text-xs font-medium text-zinc-500 dark:text-zinc-400 capitalize", children: subcategory })), brand && brandSlug && (_jsx(Link, { href: String(ROUTES.PUBLIC.BRAND_DETAIL(brandSlug)), className: "inline-flex items-center rounded-full border border-zinc-200 dark:border-zinc-700 bg-zinc-50 dark:bg-zinc-800/50 px-2.5 py-1 text-xs font-medium text-zinc-600 dark:text-zinc-300 transition-colors hover:border-primary-300 hover:bg-primary-50 hover:text-primary-700 dark:hover:border-primary-700/60 dark:hover:bg-primary-900/20 dark:hover:text-primary-400", children: brand })), brand && !brandSlug && (_jsx(Span, { className: "inline-flex items-center rounded-full border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-800/50 px-2.5 py-1 text-xs font-medium text-zinc-500 dark:text-zinc-400", children: brand }))] })), bundleMemberships.length > 0 && (_jsx(Row, { gap: "sm", wrap: true, children: bundleMemberships.map((b) => (_jsxs(Link, { href: String(ROUTES.PUBLIC.BUNDLE_DETAIL(b.id)), className: "inline-flex items-center gap-1 rounded-full border border-teal-300 bg-teal-50 px-2.5 py-1 text-xs font-semibold text-teal-700 transition-colors hover:border-teal-500 hover:bg-teal-100 dark:border-teal-800/60 dark:bg-teal-900/30 dark:text-teal-300 dark:hover:border-teal-600 dark:hover:bg-teal-900/50", children: [_jsx(Span, { "aria-hidden": "true", children: "\uD83D\uDCE6" }), "In bundle: ", b.title] }, b.id))) })), _jsx(ProductFeatureBadges, { featured: featured, freeShipping: freeShipping, condition: condition ?? undefined, returnable: returnPolicy != null && returnPolicy.length > 0, labels: {
267
+ : ""] })), (categorySlugs.length > 0 || subcategory || brand) && (_jsxs(Row, { gap: "sm", wrap: true, children: [categorySlugs.map((slug, i) => (_jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(slug)), className: "inline-flex items-center rounded-full border border-zinc-200 dark:border-zinc-700 bg-zinc-50 dark:bg-zinc-800/50 px-2.5 py-1 text-xs font-medium text-zinc-600 dark:text-zinc-300 transition-colors hover:border-primary-300 hover:bg-primary-50 hover:text-primary-700 dark:hover:border-primary-700/60 dark:hover:bg-primary-900/20 dark:hover:text-primary-400", children: categoryNames[i] ?? slug }, slug))), subcategory && (_jsx(Span, { size: "xs", weight: "medium", className: "inline-flex items-center rounded-full border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-800/50 px-2.5 py-1 text-zinc-500 dark:text-zinc-400 capitalize", children: subcategory })), brand && brandSlug && (_jsx(Link, { href: String(ROUTES.PUBLIC.BRAND_DETAIL(brandSlug)), className: "inline-flex items-center rounded-full border border-zinc-200 dark:border-zinc-700 bg-zinc-50 dark:bg-zinc-800/50 px-2.5 py-1 text-xs font-medium text-zinc-600 dark:text-zinc-300 transition-colors hover:border-primary-300 hover:bg-primary-50 hover:text-primary-700 dark:hover:border-primary-700/60 dark:hover:bg-primary-900/20 dark:hover:text-primary-400", children: brand })), brand && !brandSlug && (_jsx(Span, { size: "xs", weight: "medium", className: "inline-flex items-center rounded-full border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-800/50 px-2.5 py-1 text-zinc-500 dark:text-zinc-400", children: brand }))] })), bundleMemberships.length > 0 && (_jsx(Row, { gap: "sm", wrap: true, children: bundleMemberships.map((b) => (_jsxs(Link, { href: String(ROUTES.PUBLIC.BUNDLE_DETAIL(b.id)), className: CLS_BUNDLE_PILL, children: [_jsx(Span, { "aria-hidden": "true", children: "\uD83D\uDCE6" }), "In bundle: ", b.title] }, b.id))) })), _jsx(ProductFeatureBadges, { featured: featured, freeShipping: freeShipping, condition: condition ?? undefined, returnable: returnPolicy != null && returnPolicy.length > 0, labels: {
252
268
  featured: "Featured",
253
269
  fasterDelivery: "Faster Delivery",
254
270
  ratedSeller: "Rated Seller",
@@ -262,9 +278,9 @@ export async function ProductDetailPageView({ slug, initialProduct, renderOfferA
262
278
  codAvailable: "Cash on Delivery",
263
279
  wishlistCount: (n) => `${n} wishlisted`,
264
280
  categoryProductCount: (n, cat) => `${n} in ${cat}`,
265
- } }), productFeatures && features.length > 0 && (_jsx(FeatureBadgeList, { productFeatureIds: features, features: productFeatures })), !productFeatures && features.length > 0 && (_jsxs(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 px-4 py-3", children: [_jsx(Text, { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "About this product" }), _jsx("ul", { className: "space-y-1.5", children: features.map((f, i) => (_jsxs("li", { className: "flex items-start gap-2 text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx(Span, { className: "mt-0.5 flex-shrink-0 text-primary-500", children: "\u2022" }), f] }, i))) })] })), 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 }), typeof p.storeRating === "number" && p.storeRating > 0 && (_jsx(Row, { gap: "xs", align: "center", className: "mt-0.5", children: _jsxs(Text, { size: "xs", color: "muted", children: [_jsx("span", { className: "text-warning", "aria-hidden": "true", children: "\u2605" }), " ", p.storeRating.toFixed(1), typeof p.storeReviewCount === "number" &&
281
+ } }), productFeatures && features.length > 0 && (_jsx(FeatureBadgeList, { productFeatureIds: features, features: productFeatures })), !productFeatures && features.length > 0 && (_jsxs(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 px-4 py-3", children: [_jsx(Text, { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "About this product" }), _jsx(Ul, { className: "space-y-1.5", children: features.map((f, i) => (_jsxs(Li, { className: "flex items-start gap-2 text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx(Span, { className: "mt-0.5 flex-shrink-0 text-primary-500", children: "\u2022" }), f] }, i))) })] })), 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 }), typeof p.storeRating === "number" && p.storeRating > 0 && (_jsx(Row, { gap: "xs", align: "center", className: "mt-0.5", children: _jsxs(Text, { size: "xs", color: "muted", children: [_jsx("span", { className: "text-warning", "aria-hidden": "true", children: "\u2605" }), " ", p.storeRating.toFixed(1), typeof p.storeReviewCount === "number" &&
266
282
  p.storeReviewCount > 0 &&
267
- ` · ${p.storeReviewCount} reviews`] }) }))] }), 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" }))] }) }))] })), renderActions: () => (_jsxs(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 p-5 space-y-4", children: [formattedPrice && (_jsxs(Div, { children: [_jsxs(Row, { align: "baseline", gap: "sm", wrap: true, children: [_jsx(Text, { className: "text-2xl font-bold text-zinc-900 dark:text-zinc-50", children: formattedPrice }), formattedOriginal && discount && (_jsxs(_Fragment, { children: [_jsx(Span, { className: "text-sm text-zinc-400 line-through dark:text-zinc-400", children: formattedOriginal }), _jsxs(Span, { className: "rounded-full bg-red-500 px-2 py-0.5 text-xs font-bold text-white", children: ["-", discount, "%"] })] }))] }), inStock && effectiveStock !== null && effectiveStock <= 10 && (_jsxs(Text, { className: "mt-1 text-xs text-warning", children: ["Only ", effectiveStock, " left \u2014 order soon!"] }))] })), _jsxs(Stack, { gap: "sm", children: [renderPrimaryActions ? (renderPrimaryActions({
283
+ ` · ${p.storeReviewCount} reviews`] }) }))] }), 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" }))] }) }))] })), renderActions: () => (_jsxs(Div, { className: `rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 ${__P.p5} space-y-4`, children: [formattedPrice && (_jsxs(Div, { children: [_jsxs(Row, { align: "baseline", gap: "sm", wrap: true, children: [_jsx(Text, { className: "text-2xl font-bold text-zinc-900 dark:text-zinc-50", children: formattedPrice }), formattedOriginal && discount && (_jsxs(_Fragment, { children: [_jsx(Span, { size: "sm", className: "text-zinc-400 line-through dark:text-zinc-400", children: formattedOriginal }), _jsxs(Span, { size: "xs", weight: "bold", className: CLS_DISCOUNT_BADGE, children: ["-", discount, "%"] })] }))] }), inStock && effectiveStock !== null && effectiveStock <= 10 && (_jsxs(Text, { className: "mt-1 text-xs text-warning", children: ["Only ", effectiveStock, " left \u2014 order soon!"] }))] })), _jsxs(Stack, { gap: "sm", children: [renderPrimaryActions ? (renderPrimaryActions({
268
284
  productId: product.id,
269
285
  productSlug: product.slug ?? slug,
270
286
  productTitle: product.title,
@@ -280,20 +296,20 @@ export async function ProductDetailPageView({ slug, initialProduct, renderOfferA
280
296
  price,
281
297
  currency,
282
298
  minOfferPercent,
283
- })] }), (shippingInfo || returnPolicy || freeShipping) && (_jsxs(Div, { className: "border-t border-zinc-200 dark:border-zinc-700 pt-4 space-y-2.5", children: [freeShipping && (_jsxs(Row, { align: "start", gap: "sm", children: [_jsx(Span, { className: "mt-0.5 flex-shrink-0 text-emerald-500", children: "\uD83D\uDE9A" }), _jsxs(Div, { children: [_jsx(Text, { className: "text-xs font-medium text-zinc-700 dark:text-zinc-300", children: "Free Delivery" }), shippingInfo && (_jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: shippingInfo }))] })] })), !freeShipping && shippingInfo && (_jsxs(Row, { align: "start", gap: "sm", children: [_jsx(Span, { className: "mt-0.5 flex-shrink-0 text-zinc-400", children: "\uD83D\uDCE6" }), _jsx(Text, { className: "text-xs text-zinc-600 dark:text-zinc-400", children: shippingInfo })] })), returnPolicy && (_jsxs(Row, { align: "start", gap: "sm", children: [_jsx(Span, { className: "mt-0.5 flex-shrink-0 text-zinc-400", children: "\u21BA" }), _jsx(Text, { className: "text-xs text-zinc-600 dark:text-zinc-400", children: returnPolicy })] }))] })), tags.length > 0 && (_jsxs(Div, { className: "border-t border-zinc-200 dark:border-zinc-700 pt-4", children: [_jsx(Text, { className: "mb-2 text-xs font-medium text-zinc-500 dark:text-zinc-400", children: "Tags" }), _jsx(Row, { wrap: true, gap: "xs", children: tags.map((tag) => (_jsx(Span, { className: "rounded-full bg-zinc-100 dark:bg-zinc-800 px-2.5 py-1 text-xs text-zinc-600 dark:text-zinc-300", children: tag }, tag))) })] })), _jsx(Div, { className: "border-t border-zinc-200 dark:border-zinc-700 pt-4", children: _jsx(Row, { wrap: true, gap: "sm", justify: "center", className: "text-center", children: [
299
+ })] }), (shippingInfo || returnPolicy || freeShipping) && (_jsxs(Div, { className: "border-t border-zinc-200 dark:border-zinc-700 pt-4 space-y-2.5", children: [freeShipping && (_jsxs(Row, { align: "start", gap: "sm", children: [_jsx(Span, { className: CLS_FREE_SHIPPING_ICON, children: "\uD83D\uDE9A" }), _jsxs(Div, { children: [_jsx(Text, { className: "text-xs font-medium text-zinc-700 dark:text-zinc-300", children: "Free Delivery" }), shippingInfo && (_jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: shippingInfo }))] })] })), !freeShipping && shippingInfo && (_jsxs(Row, { align: "start", gap: "sm", children: [_jsx(Span, { className: "mt-0.5 flex-shrink-0 text-zinc-400", children: "\uD83D\uDCE6" }), _jsx(Text, { className: "text-xs text-zinc-600 dark:text-zinc-400", children: shippingInfo })] })), returnPolicy && (_jsxs(Row, { align: "start", gap: "sm", children: [_jsx(Span, { className: "mt-0.5 flex-shrink-0 text-zinc-400", children: "\u21BA" }), _jsx(Text, { className: "text-xs text-zinc-600 dark:text-zinc-400", children: returnPolicy })] }))] })), tags.length > 0 && (_jsxs(Div, { className: "border-t border-zinc-200 dark:border-zinc-700 pt-4", children: [_jsx(Text, { className: "mb-2 text-xs font-medium text-zinc-500 dark:text-zinc-400", children: "Tags" }), _jsx(Row, { wrap: true, gap: "xs", children: tags.map((tag) => (_jsx(Span, { className: "rounded-full bg-zinc-100 dark:bg-zinc-800 px-2.5 py-1 text-xs text-zinc-600 dark:text-zinc-300", children: tag }, tag))) })] })), _jsx(Div, { className: "border-t border-zinc-200 dark:border-zinc-700 pt-4", children: _jsx(Row, { wrap: true, gap: "sm", justify: "center", className: "text-center", children: [
284
300
  { icon: "🔒", label: "Secure\nPayment" },
285
301
  { icon: "✓", label: "Verified\nSeller" },
286
302
  { icon: "⭐", label: "Quality\nGuarantee" },
287
- ].map(({ icon, label }) => (_jsxs(Div, { className: "flex flex-col items-center gap-1 text-xs text-zinc-500 dark:text-zinc-400 min-w-[60px]", children: [_jsx(Span, { className: "text-base", children: icon }), _jsx(Span, { className: "whitespace-pre-line leading-tight", children: label })] }, label))) }) })] })), renderSublistingSection: sublistingCategoryId
303
+ ].map(({ icon, label }) => (_jsxs(Div, { className: "flex flex-col items-center gap-1 text-xs text-zinc-500 dark:text-zinc-400 min-w-[60px]", children: [_jsx(Span, { size: "base", children: icon }), _jsx(Span, { className: "whitespace-pre-line leading-tight", children: label })] }, label))) }) })] })), renderSublistingSection: sublistingCategoryId
288
304
  ? () => (_jsx(SublistingCarouselSection, { sublistingCategoryId: sublistingCategoryId, currentListingId: String(product.id) }))
289
305
  : undefined, renderGroupSection: groupId
290
306
  ? () => (_jsx(ShowGroupSection, { groupId: groupId, currentSlug: String(p.slug ?? product.id), isParent: isGroupParent, groupTitle: groupTitle }))
291
- : undefined, 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, specsContent: allSpecs.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: allSpecs.map((s, 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", children: s.name }), _jsxs("dd", { className: "flex-1 text-zinc-600 dark:text-zinc-400", children: [s.value, s.unit ? ` ${s.unit}` : ""] })] }, i))) })) : undefined, ingredientsContent: ingredients.length > 0 ? (_jsx("ul", { className: "space-y-2", children: ingredients.map((item, i) => (_jsxs("li", { className: "flex items-start gap-2 text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx(Span, { className: "mt-1 flex-shrink-0 h-1.5 w-1.5 rounded-full bg-primary-400" }), item] }, i))) })) : undefined, howToUseContent: howToUse.length > 0 ? (_jsx("ol", { className: "space-y-3", children: howToUse.map((step, i) => (_jsxs("li", { className: "flex items-start gap-3 text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx(Span, { className: "flex-shrink-0 flex h-6 w-6 items-center justify-center rounded-full bg-primary-100 dark:bg-primary-900/30 text-xs font-bold text-primary-700 dark:text-primary-300", children: i + 1 }), step] }, i))) })) : undefined, reviewsContent: _jsx(ReviewsList, { reviews: reviews, context: "listing", emptyLabel: "No reviews yet \u2014 be the first to review this product." }), customTabs: customSections.map((s) => ({
307
+ : undefined, 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, specsContent: allSpecs.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: allSpecs.map((s, 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", children: s.name }), _jsxs(Dd, { className: "flex-1 text-zinc-600 dark:text-zinc-400", children: [s.value, s.unit ? ` ${s.unit}` : ""] })] }, i))) })) : undefined, ingredientsContent: ingredients.length > 0 ? (_jsx(Ul, { className: "space-y-2", children: ingredients.map((item, i) => (_jsxs(Li, { className: "flex items-start gap-2 text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx(Span, { className: "mt-1 flex-shrink-0 h-1.5 w-1.5 rounded-full bg-primary-400" }), item] }, i))) })) : undefined, howToUseContent: howToUse.length > 0 ? (_jsx(Ol, { className: "space-y-3", children: howToUse.map((step, i) => (_jsxs(Li, { className: "flex items-start gap-3 text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx(Span, { size: "xs", weight: "bold", className: "flex-shrink-0 flex h-6 w-6 items-center justify-center rounded-full bg-primary-100 dark:bg-primary-900/30 text-primary-700 dark:text-primary-300", children: i + 1 }), step] }, i))) })) : undefined, reviewsContent: _jsx(ReviewsList, { reviews: reviews, context: "listing", emptyLabel: "No reviews yet \u2014 be the first to review this product." }), customTabs: customSections.map((s) => ({
292
308
  id: s.id,
293
309
  label: s.title,
294
310
  content: _jsx(CustomSectionTabContent, { section: s }),
295
311
  })) })), renderBundleSection: bundleMemberships.length > 0
296
- ? () => (_jsxs("div", { className: "rounded-xl border border-teal-200 dark:border-teal-800/60 bg-teal-50/60 dark:bg-teal-900/20 p-5", children: [_jsxs("div", { className: "flex items-center gap-2 mb-3", children: [_jsx(Span, { className: "text-teal-600 dark:text-teal-400 text-base", "aria-hidden": "true", children: "\uD83D\uDCE6" }), _jsxs(Text, { className: "text-sm font-semibold text-teal-800 dark:text-teal-200", children: ["Part of ", bundleMemberships.length === 1 ? "a bundle" : `${bundleMemberships.length} bundles`] })] }), _jsx("div", { className: "flex flex-col gap-3", children: bundleMemberships.map((b) => (_jsxs("div", { className: "flex items-center justify-between gap-4 rounded-lg border border-teal-200 dark:border-teal-800/50 bg-white dark:bg-teal-900/30 px-4 py-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx(Text, { className: "text-xs text-teal-600 dark:text-teal-400 font-medium uppercase tracking-wide mb-0.5", children: "Included in bundle" }), _jsx(Text, { className: "text-sm font-semibold text-zinc-800 dark:text-zinc-100 truncate", children: b.title })] }), _jsx(Link, { href: String(ROUTES.PUBLIC.BUNDLE_DETAIL(b.id)), className: "flex-shrink-0 rounded-lg bg-teal-600 hover:bg-teal-700 px-3 py-1.5 text-xs font-semibold text-white transition-colors", children: "View Bundle \u2192" })] }, b.id))) })] }))
312
+ ? () => (_jsxs(Div, { className: CLS_BUNDLE_BOX, children: [_jsxs(Div, { className: "flex items-center gap-2 mb-3", children: [_jsx(Span, { size: "base", className: CLS_BUNDLE_ICON, "aria-hidden": "true", children: "\uD83D\uDCE6" }), _jsxs(Text, { className: CLS_BUNDLE_TITLE, children: ["Part of ", bundleMemberships.length === 1 ? "a bundle" : `${bundleMemberships.length} bundles`] })] }), _jsx(Div, { className: "flex flex-col gap-3", children: bundleMemberships.map((b) => (_jsxs(Div, { className: CLS_BUNDLE_ROW, children: [_jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { className: CLS_BUNDLE_LABEL, children: "Included in bundle" }), _jsx(Text, { className: "text-sm font-semibold text-zinc-800 dark:text-zinc-100 truncate", children: b.title })] }), _jsx(Link, { href: String(ROUTES.PUBLIC.BUNDLE_DETAIL(b.id)), className: CLS_BUNDLE_CTA, children: "View Bundle \u2192" })] }, b.id))) })] }))
297
313
  : undefined, renderRelated: () => relatedItems.length > 0 ? (_jsx(RelatedProductsCarousel, { items: relatedItems })) : null }), renderPrimaryActions
298
314
  ? renderPrimaryActions({
299
315
  productId: product.id,
@@ -5,7 +5,7 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
5
5
  if (featured) {
6
6
  badges.push({
7
7
  key: "featured",
8
- icon: _jsx(Span, { className: "text-xs", children: "\u2605" }),
8
+ icon: _jsx(Span, { size: "xs", children: "\u2605" }),
9
9
  label: labels.featured,
10
10
  colorClass: "text-amber-700 dark:text-amber-300",
11
11
  bgClass: "bg-amber-50 dark:bg-amber-900/30 border-amber-200 dark:border-amber-800",
@@ -14,7 +14,7 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
14
14
  if (fasterDelivery) {
15
15
  badges.push({
16
16
  key: "fasterDelivery",
17
- icon: _jsx(Span, { className: "text-xs", children: "\u26A1" }),
17
+ icon: _jsx(Span, { size: "xs", children: "\u26A1" }),
18
18
  label: labels.fasterDelivery,
19
19
  colorClass: "text-orange-700 dark:text-orange-300",
20
20
  bgClass: "bg-orange-50 dark:bg-orange-900/30 border-orange-200 dark:border-orange-800",
@@ -23,7 +23,7 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
23
23
  if (ratedSeller) {
24
24
  badges.push({
25
25
  key: "ratedSeller",
26
- icon: _jsx(Span, { className: "text-xs", children: "\u2713" }),
26
+ icon: _jsx(Span, { size: "xs", children: "\u2713" }),
27
27
  label: labels.ratedSeller,
28
28
  colorClass: "text-primary",
29
29
  bgClass: "bg-primary/5 dark:bg-primary/10 border-primary/20",
@@ -41,7 +41,7 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
41
41
  : labels.conditionNew;
42
42
  badges.push({
43
43
  key: "condition",
44
- icon: _jsx(Span, { className: "text-xs", children: "\u25A3" }),
44
+ icon: _jsx(Span, { size: "xs", children: "\u25A3" }),
45
45
  label: `${labels.condition}: ${conditionLabel}`,
46
46
  colorClass: "text-primary",
47
47
  bgClass: "bg-primary/5 dark:bg-primary/10 border-primary/20 dark:border-primary/30",
@@ -50,7 +50,7 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
50
50
  if (returnable && condition === "new") {
51
51
  badges.push({
52
52
  key: "returnable",
53
- icon: _jsx(Span, { className: "text-xs", children: "\u21BA" }),
53
+ icon: _jsx(Span, { size: "xs", children: "\u21BA" }),
54
54
  label: labels.returnable,
55
55
  colorClass: "text-teal-700 dark:text-teal-300",
56
56
  bgClass: "bg-teal-50 dark:bg-teal-900/30 border-teal-200 dark:border-teal-800",
@@ -59,7 +59,7 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
59
59
  if (freeShipping) {
60
60
  badges.push({
61
61
  key: "freeShipping",
62
- icon: _jsx(Span, { className: "text-xs", children: "\uD83D\uDE9A" }),
62
+ icon: _jsx(Span, { size: "xs", children: "\uD83D\uDE9A" }),
63
63
  label: labels.freeShipping,
64
64
  colorClass: "text-emerald-700 dark:text-emerald-300",
65
65
  bgClass: "bg-emerald-50 dark:bg-emerald-900/30 border-emerald-200 dark:border-emerald-800",
@@ -68,7 +68,7 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
68
68
  if (codAvailable) {
69
69
  badges.push({
70
70
  key: "cod",
71
- icon: _jsx(Span, { className: "text-xs", children: "\u20B9" }),
71
+ icon: _jsx(Span, { size: "xs", children: "\u20B9" }),
72
72
  label: labels.codAvailable,
73
73
  colorClass: "text-purple-700 dark:text-purple-300",
74
74
  bgClass: "bg-purple-50 dark:bg-purple-900/30 border-purple-200 dark:border-purple-800",
@@ -77,7 +77,7 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
77
77
  if (wishlistCount && wishlistCount > 0) {
78
78
  badges.push({
79
79
  key: "wishlist",
80
- icon: _jsx(Span, { className: "text-xs", children: "\u2665" }),
80
+ icon: _jsx(Span, { size: "xs", children: "\u2665" }),
81
81
  label: labels.wishlistCount(wishlistCount),
82
82
  colorClass: "text-pink-700 dark:text-pink-300",
83
83
  bgClass: "bg-pink-50 dark:bg-pink-900/30 border-pink-200 dark:border-pink-800",
@@ -89,7 +89,7 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
89
89
  : String(categoryProductCount);
90
90
  badges.push({
91
91
  key: "categoryCount",
92
- icon: _jsx(Span, { className: "text-xs", children: "\u25A6" }),
92
+ icon: _jsx(Span, { size: "xs", children: "\u25A6" }),
93
93
  label: labels.categoryProductCount(formattedCount, categoryName),
94
94
  colorClass: "text-zinc-700 dark:text-zinc-300",
95
95
  bgClass: categoryBadgeClassName ??
@@ -65,6 +65,16 @@ export interface ProductFormProps {
65
65
  * non-auction product. Returns null/undefined to omit.
66
66
  */
67
67
  renderGroupSettings?: (product: ProductFormValue) => React.ReactNode;
68
+ /**
69
+ * Render a "join existing group" picker (create + edit). When omitted, the
70
+ * groupId field is hidden. Receives current groupId and an onChange handler.
71
+ */
72
+ renderGroupJoinField?: (args: {
73
+ label: string;
74
+ value: string | undefined;
75
+ onChange: (id: string | undefined) => void;
76
+ disabled: boolean;
77
+ }) => React.ReactNode;
68
78
  }
69
- export declare function ProductForm({ product, onChange, isReadonly, renderDescriptionEditor, renderCategorySelector, renderBrandSelector, renderStoreAddressSelector, onMediaAbort, currencyPrefix, renderGroupSettings, }: ProductFormProps): import("react/jsx-runtime").JSX.Element;
79
+ export declare function ProductForm({ product, onChange, isReadonly, renderDescriptionEditor, renderCategorySelector, renderBrandSelector, renderStoreAddressSelector, onMediaAbort, currencyPrefix, renderGroupSettings, renderGroupJoinField, }: ProductFormProps): import("react/jsx-runtime").JSX.Element;
70
80
  export {};
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useRef } from "react";
4
4
  import { useTranslations } from "next-intl";
5
- import { Alert, Checkbox, Div, FormField, FormGroup, Heading, RichTextEditor, Stack, Text, } from "../../../ui";
5
+ import { Alert, Checkbox, Div, FormField, FormGroup, Heading, Label, RichTextEditor, Stack, Text, } from "../../../ui";
6
6
  import { CustomSectionsEditor } from "./CustomSectionsEditor";
7
7
  import { SublistingCategorySelect } from "./SublistingCategorySelect";
8
8
  import { ProductFeaturesSelector } from "./ProductFeaturesSelector";
@@ -25,7 +25,7 @@ function readFileAsDataUrl(file) {
25
25
  reader.readAsDataURL(file);
26
26
  });
27
27
  }
28
- export function ProductForm({ product, onChange, isReadonly = false, renderDescriptionEditor, renderCategorySelector, renderBrandSelector, renderStoreAddressSelector, onMediaAbort, currencyPrefix = "", renderGroupSettings, }) {
28
+ export function ProductForm({ product, onChange, isReadonly = false, renderDescriptionEditor, renderCategorySelector, renderBrandSelector, renderStoreAddressSelector, onMediaAbort, currencyPrefix = "", renderGroupSettings, renderGroupJoinField, }) {
29
29
  const t = useTranslations("adminProducts");
30
30
  const { upload } = useMediaUpload();
31
31
  const galleryIndexRef = useRef(0);
@@ -65,7 +65,7 @@ export function ProductForm({ product, onChange, isReadonly = false, renderDescr
65
65
  value: (product.categorySlugs?.[0] ?? product.category) || "",
66
66
  onChange: (value) => update({ categorySlugs: value ? [value] : [] }),
67
67
  disabled: isReadonly,
68
- }) })) : (_jsx(FormField, { name: "category", label: t("formCategory"), type: "text", value: (product.categorySlugs?.[0] ?? product.category) || "", onChange: (value) => update({ categorySlugs: value ? [value] : [] }), disabled: isReadonly })), _jsx(FormField, { name: "subcategory", label: t("formSubcategory"), type: "text", value: product.subcategory || "", onChange: (value) => update({ subcategory: value }), disabled: isReadonly, placeholder: "e.g. Smartphones" })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { className: "text-sm font-medium text-zinc-900 dark:text-zinc-100", children: t("formBrand") }), _jsx("div", { className: "flex gap-3 flex-wrap", children: ["single", "unbranded", "mixed"].map((mode) => (_jsxs("label", { className: "flex items-center gap-1.5 cursor-pointer select-none text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx("input", { type: "radio", name: "brandMode", value: mode, checked: (product.brandMode ?? "single") === mode, onChange: () => {
68
+ }) })) : (_jsx(FormField, { name: "category", label: t("formCategory"), type: "text", value: (product.categorySlugs?.[0] ?? product.category) || "", onChange: (value) => update({ categorySlugs: value ? [value] : [] }), disabled: isReadonly })), _jsx(FormField, { name: "subcategory", label: t("formSubcategory"), type: "text", value: product.subcategory || "", onChange: (value) => update({ subcategory: value }), disabled: isReadonly, placeholder: "e.g. Smartphones" })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { className: "text-sm font-medium text-zinc-900 dark:text-zinc-100", children: t("formBrand") }), _jsx(Div, { className: "flex gap-3 flex-wrap", children: ["single", "unbranded", "mixed"].map((mode) => (_jsxs(Label, { className: "flex items-center gap-1.5 cursor-pointer select-none text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx("input", { type: "radio", name: "brandMode", value: mode, checked: (product.brandMode ?? "single") === mode, onChange: () => {
69
69
  if (mode === "unbranded") {
70
70
  update({ brandMode: "unbranded", brand: undefined, brands: [] });
71
71
  }
@@ -83,7 +83,7 @@ export function ProductForm({ product, onChange, isReadonly = false, renderDescr
83
83
  onValueChange: (value) => update({ brand: value }),
84
84
  onValuesChange: (values) => update({ brands: values }),
85
85
  disabled: isReadonly,
86
- })) : product.brandMode === "mixed" ? (_jsx(FormField, { name: "brands", label: "Brands (comma-separated)", type: "text", value: (product.brands || []).join(", "), onChange: (value) => update({ brands: value.split(",").map((b) => b.trim()).filter(Boolean) }), disabled: isReadonly, placeholder: "e.g. Nike, Adidas, Puma" })) : (_jsx(FormField, { name: "brand", label: t("formBrand"), type: "text", value: product.brand || "", onChange: (value) => update({ brand: value }), disabled: isReadonly, placeholder: "e.g. Apple" })) }))] }), _jsxs(FormGroup, { columns: 2, children: [_jsx("div", {}), " ", _jsx(FormField, { name: "status", label: t("formStatus"), type: "select", value: product.status || "draft", onChange: (value) => update({ status: value }), disabled: isReadonly, options: PRODUCT_STATUS_OPTIONS })] }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "price", label: t("formPrice"), type: "number", value: String(product.price ?? ""), onChange: (value) => update({ price: Number(value) }), disabled: isReadonly, placeholder: "0" }), _jsx(FormField, { name: "stockQuantity", label: t("formStock"), type: "number", value: String(product.stockQuantity ?? ""), onChange: (value) => update({ stockQuantity: Number(value) }), disabled: isReadonly, placeholder: "0" })] }), !isReadonly && (_jsx(ImageUpload, { currentImage: product.mainImage, onUpload: (file) => upload(file, "products", true, {
86
+ })) : product.brandMode === "mixed" ? (_jsx(FormField, { name: "brands", label: "Brands (comma-separated)", type: "text", value: (product.brands || []).join(", "), onChange: (value) => update({ brands: value.split(",").map((b) => b.trim()).filter(Boolean) }), disabled: isReadonly, placeholder: "e.g. Nike, Adidas, Puma" })) : (_jsx(FormField, { name: "brand", label: t("formBrand"), type: "text", value: product.brand || "", onChange: (value) => update({ brand: value }), disabled: isReadonly, placeholder: "e.g. Apple" })) }))] }), _jsxs(FormGroup, { columns: 2, children: [_jsx(Div, {}), " ", _jsx(FormField, { name: "status", label: t("formStatus"), type: "select", value: product.status || "draft", onChange: (value) => update({ status: value }), disabled: isReadonly, options: PRODUCT_STATUS_OPTIONS })] }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "price", label: t("formPrice"), type: "number", value: String(product.price ?? ""), onChange: (value) => update({ price: Number(value) }), disabled: isReadonly, placeholder: "0" }), _jsx(FormField, { name: "stockQuantity", label: t("formStock"), type: "number", value: String(product.stockQuantity ?? ""), onChange: (value) => update({ stockQuantity: Number(value) }), disabled: isReadonly, placeholder: "0" })] }), !isReadonly && (_jsx(ImageUpload, { currentImage: product.mainImage, onUpload: (file) => upload(file, "products", true, {
87
87
  type: "product-image",
88
88
  index: 1,
89
89
  name: product.title || "product",
@@ -173,7 +173,12 @@ export function ProductForm({ product, onChange, isReadonly = false, renderDescr
173
173
  value: product.pickupAddressId || "",
174
174
  onChange: (value) => update({ pickupAddressId: value }),
175
175
  disabled: isReadonly,
176
- }) })) : (_jsx(FormField, { name: "pickupAddressId", label: t("formPickupAddress"), type: "text", value: product.pickupAddressId || "", onChange: (value) => update({ pickupAddressId: value }), disabled: isReadonly })), _jsx(SublistingCategorySelect, { value: product.sublistingCategoryId ?? "", onChange: (id) => update({ sublistingCategoryId: id || undefined }), disabled: isReadonly }), !isAuctionListing(product) && renderGroupSettings?.(product), _jsx(ProductFeaturesSelector, { value: product.features ?? [], onChange: (features) => update({ features }), productType: (isAuctionListing(product)
176
+ }) })) : (_jsx(FormField, { name: "pickupAddressId", label: t("formPickupAddress"), type: "text", value: product.pickupAddressId || "", onChange: (value) => update({ pickupAddressId: value }), disabled: isReadonly })), _jsx(SublistingCategorySelect, { value: product.sublistingCategoryId ?? "", onChange: (id) => update({ sublistingCategoryId: id || undefined }), disabled: isReadonly }), !isAuctionListing(product) && renderGroupJoinField?.({
177
+ label: "Group (optional)",
178
+ value: product.groupId,
179
+ onChange: (id) => update({ groupId: id || undefined }),
180
+ disabled: isReadonly,
181
+ }), !isAuctionListing(product) && renderGroupSettings?.(product), _jsx(ProductFeaturesSelector, { value: product.features ?? [], onChange: (features) => update({ features }), productType: (isAuctionListing(product)
177
182
  ? "auction"
178
183
  : isPreOrderListing(product)
179
184
  ? "preorder"
@@ -2,7 +2,11 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState } from "react";
4
4
  import { ImageLightbox } from "../../../ui/components/ImageLightbox";
5
- import { Text } from "../../../ui";
5
+ import { Div, Text } from "../../../ui";
6
+ const __O = {
7
+ hidden: "overflow-hidden",
8
+ xAuto: "overflow-x-auto",
9
+ };
6
10
  const PlaceholderSvg = () => (_jsxs("svg", { width: "64", height: "64", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", "aria-hidden": "true", children: [_jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }), _jsx("circle", { cx: "8.5", cy: "8.5", r: "1.5" }), _jsx("path", { d: "M21 15l-5-5L5 21" })] }));
7
11
  export function ProductGalleryClient({ images, productName }) {
8
12
  const [activeIndex, setActiveIndex] = useState(0);
@@ -12,13 +16,13 @@ export function ProductGalleryClient({ images, productName }) {
12
16
  alt: productName ? `${productName} — image ${i + 1}` : `Product image ${i + 1}`,
13
17
  }));
14
18
  if (images.length === 0) {
15
- return (_jsx("div", { className: "overflow-hidden rounded-xl border border-zinc-100 bg-zinc-50 dark:border-zinc-800 dark:bg-zinc-900", children: _jsx("div", { className: "flex aspect-square items-center justify-center text-zinc-300 dark:text-zinc-700", children: _jsx(PlaceholderSvg, {}) }) }));
19
+ return (_jsx(Div, { className: `${__O.hidden} rounded-xl border border-zinc-100 bg-zinc-50 dark:border-zinc-800 dark:bg-zinc-900`, children: _jsx(Div, { className: "flex aspect-square items-center justify-center text-zinc-300 dark:text-zinc-700", children: _jsx(PlaceholderSvg, {}) }) }));
16
20
  }
17
21
  const mainImage = images[activeIndex] ?? images[0];
18
- return (_jsxs("div", { className: "space-y-3", children: [_jsx("div", { className: "overflow-hidden rounded-xl border border-zinc-100 dark:border-zinc-800 cursor-zoom-in", onClick: () => setLightboxIndex(activeIndex), role: "button", tabIndex: 0, onKeyDown: (e) => {
22
+ return (_jsxs(Div, { className: "space-y-3", children: [_jsx("div", { className: "overflow-hidden rounded-xl border border-zinc-100 dark:border-zinc-800 cursor-zoom-in", onClick: () => setLightboxIndex(activeIndex), role: "button", tabIndex: 0, onKeyDown: (e) => {
19
23
  if (e.key === "Enter" || e.key === " ")
20
24
  setLightboxIndex(activeIndex);
21
- }, "aria-label": `View ${productName ?? "product"} image in full screen`, children: _jsx("img", { src: mainImage, alt: productName ? `${productName} — image ${activeIndex + 1}` : `Product image ${activeIndex + 1}`, className: "aspect-square w-full object-cover transition-transform duration-300 hover:scale-105" }) }), images.length > 1 && (_jsx("div", { className: "flex gap-2 overflow-x-auto pb-1", children: images.map((src, i) => (_jsx("button", { type: "button", onClick: () => setActiveIndex(i), className: `flex-shrink-0 h-16 w-16 overflow-hidden rounded-lg border-2 transition-all${i === activeIndex
25
+ }, "aria-label": `View ${productName ?? "product"} image in full screen`, children: _jsx("img", { src: mainImage, alt: productName ? `${productName} — image ${activeIndex + 1}` : `Product image ${activeIndex + 1}`, className: "aspect-square w-full object-cover transition-transform duration-300 hover:scale-105" }) }), images.length > 1 && (_jsx(Div, { className: `flex gap-2 ${__O.xAuto} pb-1`, children: images.map((src, i) => (_jsx("button", { type: "button", onClick: () => setActiveIndex(i), className: `flex-shrink-0 h-16 w-16 overflow-hidden rounded-lg border-2 transition-all${i === activeIndex
22
26
  ? " border-primary-500"
23
27
  : " border-transparent opacity-60 hover:opacity-100"}`, "aria-label": `View image ${i + 1}`, "aria-current": i === activeIndex ? "true" : undefined, children: _jsx("img", { src: src, alt: "", className: "h-full w-full object-cover" }) }, i))) })), images.length > 1 && (_jsxs(Text, { className: "text-center text-xs text-zinc-400 dark:text-zinc-400", children: [activeIndex + 1, " / ", images.length] })), _jsx(ImageLightbox, { images: lightboxImages, activeIndex: lightboxIndex, onClose: () => setLightboxIndex(null), onNavigate: (i) => setLightboxIndex(i) })] }));
24
28
  }
@@ -2,6 +2,9 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { Div, Heading, Stack, Text } from "../../../ui";
4
4
  import { Badge } from "../../../ui/components/Badge";
5
+ const __O = {
6
+ hidden: "overflow-hidden",
7
+ };
5
8
  const PSA_CERT_URL = (cert) => `https://www.psacard.com/cert/${cert}`;
6
9
  const BGS_CERT_URL = (cert) => `https://www.beckett.com/grading/card-lookup/${cert}`;
7
10
  function buildCertLookupUrl(service, certNumber) {
@@ -21,5 +24,5 @@ function buildCertLookupUrl(service, certNumber) {
21
24
  */
22
25
  export function ProductGradingTab({ grading, slabImageUrl }) {
23
26
  const lookupUrl = buildCertLookupUrl(grading.service, grading.certNumber);
24
- return (_jsxs(Stack, { gap: "lg", children: [_jsxs(Div, { className: "flex items-center gap-4", children: [_jsxs(Div, { className: "flex flex-col items-center justify-center rounded-2xl border-2 border-[var(--appkit-color-primary)] px-6 py-4 min-w-[120px]", children: [_jsx(Text, { className: "text-xs font-bold uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: grading.service }), _jsx(Text, { className: "text-4xl font-extrabold", children: grading.grade })] }), _jsxs(Stack, { gap: "xs", className: "flex-1", children: [_jsxs(Heading, { level: 3, className: "text-base font-semibold", children: ["Graded by ", grading.service] }), grading.certNumber ? (_jsxs(Text, { className: "text-sm text-zinc-600 dark:text-zinc-400", children: ["Cert #", grading.certNumber, lookupUrl ? (_jsxs(_Fragment, { children: [" — ", _jsx("a", { href: lookupUrl, target: "_blank", rel: "noopener noreferrer", className: "text-[var(--appkit-color-primary)] hover:underline", children: "Verify" })] })) : null] })) : null] })] }), slabImageUrl ? (_jsx(Div, { className: "overflow-hidden rounded-2xl border border-zinc-200 dark:border-zinc-700", children: _jsx("img", { src: slabImageUrl, alt: "Slab certificate image", className: "w-full h-auto" }) })) : null, grading.attributes && Object.keys(grading.attributes).length > 0 ? (_jsxs(Stack, { gap: "sm", children: [_jsx(Heading, { level: 3, className: "text-sm font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "Subgrades & attributes" }), _jsx(Div, { className: "flex flex-wrap gap-2", children: Object.entries(grading.attributes).map(([key, value]) => (_jsxs(Badge, { variant: "default", children: [key, ": ", value] }, key))) })] })) : null] }));
27
+ return (_jsxs(Stack, { gap: "lg", children: [_jsxs(Div, { className: "flex items-center gap-4", children: [_jsxs(Div, { className: "flex flex-col items-center justify-center rounded-2xl border-2 border-[var(--appkit-color-primary)] px-6 py-4 min-w-[120px]", children: [_jsx(Text, { className: "text-xs font-bold uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: grading.service }), _jsx(Text, { className: "text-4xl font-extrabold", children: grading.grade })] }), _jsxs(Stack, { gap: "xs", className: "flex-1", children: [_jsxs(Heading, { level: 3, className: "text-base font-semibold", children: ["Graded by ", grading.service] }), grading.certNumber ? (_jsxs(Text, { className: "text-sm text-zinc-600 dark:text-zinc-400", children: ["Cert #", grading.certNumber, lookupUrl ? (_jsxs(_Fragment, { children: [" — ", _jsx("a", { href: lookupUrl, target: "_blank", rel: "noopener noreferrer", className: "text-[var(--appkit-color-primary)] hover:underline", children: "Verify" })] })) : null] })) : null] })] }), slabImageUrl ? (_jsx(Div, { className: `${__O.hidden} rounded-2xl border border-zinc-200 dark:border-zinc-700`, children: _jsx("img", { src: slabImageUrl, alt: "Slab certificate image", className: "w-full h-auto" }) })) : null, grading.attributes && Object.keys(grading.attributes).length > 0 ? (_jsxs(Stack, { gap: "sm", children: [_jsx(Heading, { level: 3, className: "text-sm font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "Subgrades & attributes" }), _jsx(Div, { className: "flex flex-wrap gap-2", children: Object.entries(grading.attributes).map(([key, value]) => (_jsxs(Badge, { variant: "default", children: [key, ": ", value] }, key))) })] })) : null] }));
25
28
  }
@@ -13,6 +13,27 @@ import { FeatureBadgeList } from "./FeatureBadge";
13
13
  import { useProductFeatures } from "./ProductFeaturesContext";
14
14
  import { PRODUCT_FEATURE_CARD_MAX_VISIBLE } from "../constants/product-features.constants";
15
15
  import { isAuctionListing, isPreOrderListing } from "../utils/listing-type";
16
+ const __P = {
17
+ p3: "p-3",
18
+ };
19
+ const __O = {
20
+ hidden: "overflow-hidden",
21
+ };
22
+ const CLS_BADGE_AUCTION = "bg-amber-500 text-white";
23
+ const CLS_BADGE_PREORDER = "bg-violet-600 text-white";
24
+ const CLS_BADGE_NEW = "rounded-full bg-rose-500 px-2 py-0.5 text-[10px] text-white shadow-sm";
25
+ const CLS_BADGE_SALE = "rounded-full bg-teal-600 px-2 py-0.5 text-[10px] font-bold text-white shadow-sm";
26
+ const CLS_BADGE_TRENDING = "rounded-full bg-indigo-600 px-2 py-0.5 text-[10px] font-bold text-white shadow-sm";
27
+ const CLS_BADGE_LIMITED = "rounded-full bg-sky-600 px-2 py-0.5 text-[10px] font-bold text-white shadow-sm";
28
+ const CLS_HEART_ACTIVE = "bg-rose-500 text-white hover:bg-rose-600";
29
+ const CLS_HEART_IDLE = "bg-white/90 dark:bg-slate-800/90 text-zinc-500 dark:text-zinc-400 hover:text-rose-500 hover:bg-white dark:hover:bg-slate-800";
30
+ const CLS_STAR = "text-[11px] text-amber-400";
31
+ const CLS_DISCOUNT_TEXT = "mt-1 text-[11px] font-semibold text-rose-500";
32
+ const CLS_DISCOUNT_TEXT_BARE = "text-[10px] text-rose-500";
33
+ const CLS_STAR_BARE = "text-amber-400";
34
+ const CLS_BID_TEXT = "text-[11px] text-rose-500";
35
+ const CLS_HEART_ROSE_ACTIVE = "text-rose-500";
36
+ const CLS_HEART_ROSE_IDLE = "text-zinc-300 dark:text-zinc-600 hover:text-rose-400";
16
37
  export function ProductCard({ product, href, onClick, onAddToWishlist, isWishlisted, onAddToCart, onBuyNow, className = "", selectionMode = false, isSelected = false, onSelect, }) {
17
38
  const discount = product.originalPrice && product.originalPrice > product.price
18
39
  ? Math.round(((product.originalPrice - product.price) / product.originalPrice) *
@@ -22,9 +43,9 @@ export function ProductCard({ product, href, onClick, onAddToWishlist, isWishlis
22
43
  const isAuction = isAuctionListing(product);
23
44
  const isPreOrder = isPreOrderListing(product);
24
45
  const typeBadge = isAuction
25
- ? { label: "Auction", cls: "bg-amber-500 text-white" }
46
+ ? { label: "Auction", cls: CLS_BADGE_AUCTION }
26
47
  : isPreOrder
27
- ? { label: "Pre-Order", cls: "bg-violet-600 text-white" }
48
+ ? { label: "Pre-Order", cls: CLS_BADGE_PREORDER }
28
49
  : null;
29
50
  const longPress = useLongPress(() => onSelect?.(product.id));
30
51
  const featuresList = useProductFeatures();
@@ -48,9 +69,9 @@ export function ProductCard({ product, href, onClick, onAddToWishlist, isWishlis
48
69
  className,
49
70
  ]
50
71
  .filter(Boolean)
51
- .join(" "), children: [_jsxs(Div, { className: "relative overflow-hidden bg-zinc-100 dark:bg-slate-800 aspect-square", children: [product.mainImage ? (_jsx(MediaImage, { src: product.mainImage, alt: product.title, size: "card", className: "transition-transform duration-500 group-hover:scale-105" })) : (_jsx(Div, { className: "h-full w-full flex items-center justify-center bg-gradient-to-br from-zinc-100 to-zinc-200 dark:from-slate-800 dark:to-slate-700", children: _jsx(Span, { className: "text-4xl opacity-30", children: "\uD83D\uDECD\uFE0F" }) })), onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (e) => { e.preventDefault(); onSelect(product.id); }, label: isSelected ? "Deselect" : "Select", position: "top-2 left-2", className: selectionMode || isSelected ? "opacity-100" : "opacity-0 group-hover:opacity-100 transition-opacity" })), _jsx(Div, { className: `absolute top-2 flex flex-col gap-1 ${onSelect ? "left-10" : "left-2"}`, children: !selectionMode && !isSelected && (_jsxs(_Fragment, { children: [discount && (_jsxs(Span, { className: "rounded-full bg-rose-500 px-2 py-0.5 text-[10px] font-bold text-white shadow-sm", children: ["-", discount, "%"] })), typeBadge && (_jsx(Span, { className: `rounded-full px-2 py-0.5 text-[10px] font-bold shadow-sm ${typeBadge.cls}`, children: typeBadge.label })), product.partOfBundleIds && product.partOfBundleIds.length > 0 && (_jsx(Span, { className: "rounded-full bg-teal-600 px-2 py-0.5 text-[10px] font-bold text-white shadow-sm", title: product.partOfBundleTitles && product.partOfBundleTitles.length > 0
72
+ .join(" "), children: [_jsxs(Div, { className: `relative ${__O.hidden} bg-zinc-100 dark:bg-slate-800 aspect-square`, children: [product.mainImage ? (_jsx(MediaImage, { src: product.mainImage, alt: product.title, size: "card", className: "transition-transform duration-500 group-hover:scale-105" })) : (_jsx(Div, { className: "h-full w-full flex items-center justify-center bg-gradient-to-br from-zinc-100 to-zinc-200 dark:from-slate-800 dark:to-slate-700", children: _jsx(Span, { className: "text-4xl opacity-30", children: "\uD83D\uDECD\uFE0F" }) })), onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (e) => { e.preventDefault(); onSelect(product.id); }, label: isSelected ? "Deselect" : "Select", position: "top-2 left-2", className: selectionMode || isSelected ? "opacity-100" : "opacity-0 group-hover:opacity-100 transition-opacity" })), _jsx(Div, { className: `absolute top-2 flex flex-col gap-1 ${onSelect ? "left-10" : "left-2"}`, children: !selectionMode && !isSelected && (_jsxs(_Fragment, { children: [discount && (_jsxs(Span, { weight: "bold", className: CLS_BADGE_NEW, children: ["-", discount, "%"] })), typeBadge && (_jsx(Span, { weight: "bold", className: `rounded-full px-2 py-0.5 text-[10px] shadow-sm ${typeBadge.cls}`, children: typeBadge.label })), product.partOfBundleIds && product.partOfBundleIds.length > 0 && (_jsx(Span, { className: CLS_BADGE_SALE, title: product.partOfBundleTitles && product.partOfBundleTitles.length > 0
52
73
  ? `In bundle: ${product.partOfBundleTitles[0]}`
53
- : "In a bundle", children: "Bundled" })), product.groupId && (_jsx(Span, { className: "rounded-full bg-indigo-600 px-2 py-0.5 text-[10px] font-bold text-white shadow-sm", title: product.groupTitle ? `Part of set: ${product.groupTitle}` : "Part of a set", children: product.isGroupParent ? "Set Parent" : "In Set" })), product.sublistingCategoryId && (_jsx(Span, { className: "rounded-full bg-sky-600 px-2 py-0.5 text-[10px] font-bold text-white shadow-sm", title: "Has variants or sub-listings", children: "Has Variants" }))] })) }), _jsx(BaseListingCard.IconOverlay, { groupIcon: product.groupIcon, sublistingIcon: product.sublistingIcon, position: "bottom-2 right-2" }), onAddToWishlist && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: (e) => {
74
+ : "In a bundle", children: "Bundled" })), product.groupId && (_jsx(Span, { className: CLS_BADGE_TRENDING, title: product.groupTitle ? `Part of set: ${product.groupTitle}` : "Part of a set", children: product.isGroupParent ? "Set Parent" : "In Set" })), product.sublistingCategoryId && (_jsx(Span, { className: CLS_BADGE_LIMITED, title: "Has variants or sub-listings", children: "Has Variants" }))] })) }), _jsx(BaseListingCard.IconOverlay, { groupIcon: product.groupIcon, sublistingIcon: product.sublistingIcon, position: "bottom-2 right-2" }), onAddToWishlist && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: (e) => {
54
75
  e.stopPropagation();
55
76
  e.preventDefault();
56
77
  onAddToWishlist(product.id);
@@ -58,9 +79,9 @@ export function ProductCard({ product, href, onClick, onAddToWishlist, isWishlis
58
79
  "absolute right-2 top-2 flex h-8 w-8 items-center justify-center rounded-full shadow-sm",
59
80
  "transition-all duration-150",
60
81
  isWishlisted
61
- ? "bg-rose-500 text-white hover:bg-rose-600"
62
- : "bg-white/90 dark:bg-slate-800/90 text-zinc-500 dark:text-zinc-400 hover:text-rose-500 hover:bg-white dark:hover:bg-slate-800",
63
- ].join(" "), children: _jsx("svg", { className: "h-4 w-4", fill: isWishlisted ? "currentColor" : "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z" }) }) }))] }), _jsxs(Div, { className: "flex flex-1 flex-col p-3 pt-2.5", children: [_jsx(Text, { className: `${THEME_CONSTANTS.utilities.textClamp2} text-sm font-semibold text-zinc-900 dark:text-white leading-snug`, children: product.title }), (() => {
82
+ ? CLS_HEART_ACTIVE
83
+ : CLS_HEART_IDLE,
84
+ ].join(" "), children: _jsx("svg", { className: "h-4 w-4", fill: isWishlisted ? "currentColor" : "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z" }) }) }))] }), _jsxs(Div, { className: `flex flex-1 flex-col ${__P.p3} pt-2.5`, children: [_jsx(Text, { className: `${THEME_CONSTANTS.utilities.textClamp2} text-sm font-semibold text-zinc-900 dark:text-white leading-snug`, children: product.title }), (() => {
64
85
  const categories = Array.isArray(product.categoryNames)
65
86
  ? product.categoryNames.filter(Boolean)
66
87
  : product.categoryName
@@ -71,16 +92,16 @@ export function ProductCard({ product, href, onClick, onAddToWishlist, isWishlis
71
92
  const MAX_CHIPS = 3;
72
93
  const visible = categories.slice(0, MAX_CHIPS);
73
94
  const overflow = Math.max(0, categories.length - MAX_CHIPS);
74
- return (_jsxs(Row, { className: "mt-1 gap-1 flex-wrap", children: [visible.map((name) => (_jsxs(Span, { className: "inline-flex items-center gap-0.5 rounded-full bg-zinc-100 dark:bg-zinc-800 px-1.5 py-0.5 text-[10px] text-zinc-600 dark:text-zinc-400 truncate max-w-[100px]", children: [_jsx("svg", { className: "h-2.5 w-2.5 flex-shrink-0", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 7a2 2 0 012-2h14a2 2 0 012 2v10a2 2 0 01-2 2H5a2 2 0 01-2-2V7z" }) }), name] }, name))), overflow > 0 && (_jsxs(Span, { className: "inline-flex items-center rounded-full bg-zinc-100 dark:bg-zinc-800 px-1.5 py-0.5 text-[10px] font-medium text-zinc-600 dark:text-zinc-400", title: categories.slice(MAX_CHIPS).join(", "), children: ["+", overflow] })), product.brand && (_jsxs(Span, { className: "inline-flex items-center gap-0.5 rounded-full bg-zinc-100 dark:bg-zinc-800 px-1.5 py-0.5 text-[10px] text-zinc-600 dark:text-zinc-400 truncate max-w-[90px]", children: [_jsx("svg", { className: "h-2.5 w-2.5 flex-shrink-0", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" }) }), product.brand] }))] }));
95
+ return (_jsxs(Row, { className: "mt-1 gap-1 flex-wrap", children: [visible.map((name) => (_jsxs(Span, { className: "inline-flex items-center gap-0.5 rounded-full bg-zinc-100 dark:bg-zinc-800 px-1.5 py-0.5 text-[10px] text-zinc-600 dark:text-zinc-400 truncate max-w-[100px]", children: [_jsx("svg", { className: "h-2.5 w-2.5 flex-shrink-0", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 7a2 2 0 012-2h14a2 2 0 012 2v10a2 2 0 01-2 2H5a2 2 0 01-2-2V7z" }) }), name] }, name))), overflow > 0 && (_jsxs(Span, { weight: "medium", className: "inline-flex items-center rounded-full bg-zinc-100 dark:bg-zinc-800 px-1.5 py-0.5 text-[10px] text-zinc-600 dark:text-zinc-400", title: categories.slice(MAX_CHIPS).join(", "), children: ["+", overflow] })), product.brand && (_jsxs(Span, { className: "inline-flex items-center gap-0.5 rounded-full bg-zinc-100 dark:bg-zinc-800 px-1.5 py-0.5 text-[10px] text-zinc-600 dark:text-zinc-400 truncate max-w-[90px]", children: [_jsx("svg", { className: "h-2.5 w-2.5 flex-shrink-0", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" }) }), product.brand] }))] }));
75
96
  })(), (() => {
76
97
  const seller = safeDisplayName(product.storeName, "");
77
98
  return seller ? (_jsxs(Text, { className: "mt-0.5 text-[11px] text-zinc-400 dark:text-zinc-400 truncate", children: ["by ", seller] })) : null;
78
- })(), product.rating !== undefined && (_jsxs(Row, { className: "mt-1 gap-1", children: [_jsx(Span, { className: "text-[11px] text-amber-400", children: "\u2605" }), _jsxs(Span, { className: "text-[11px] text-zinc-500 dark:text-zinc-400", children: [product.rating.toFixed(1), product.reviewCount ? ` (${product.reviewCount})` : ""] })] })), _jsxs(Div, { className: "mt-auto pt-2", children: [_jsxs(Row, { align: "baseline", className: "gap-2", children: [_jsx(Span, { className: "text-base font-bold text-primary dark:text-primary-400", children: formatCurrency(product.price, getDefaultCurrency()) }), product.originalPrice && product.originalPrice > product.price && (_jsx(Span, { className: "text-xs text-zinc-400 line-through dark:text-zinc-400", children: formatCurrency(product.originalPrice, getDefaultCurrency()) }))] }), (() => {
99
+ })(), product.rating !== undefined && (_jsxs(Row, { className: "mt-1 gap-1", children: [_jsx(Span, { className: CLS_STAR, children: "\u2605" }), _jsxs(Span, { className: "text-[11px] text-zinc-500 dark:text-zinc-400", children: [product.rating.toFixed(1), product.reviewCount ? ` (${product.reviewCount})` : ""] })] })), _jsxs(Div, { className: "mt-auto pt-2", children: [_jsxs(Row, { align: "baseline", className: "gap-2", children: [_jsx(Span, { size: "base", weight: "bold", className: "text-primary dark:text-primary-400", children: formatCurrency(product.price, getDefaultCurrency()) }), product.originalPrice && product.originalPrice > product.price && (_jsx(Span, { size: "xs", className: "text-zinc-400 line-through dark:text-zinc-400", children: formatCurrency(product.originalPrice, getDefaultCurrency()) }))] }), (() => {
79
100
  const stock = product.stockCount ?? product.stockQuantity ?? product.availableQuantity;
80
101
  if (stock === undefined || isAuction)
81
102
  return null;
82
103
  if (stock <= 0) {
83
- return (_jsx(Text, { className: "mt-1 text-[11px] font-semibold text-rose-500", children: "Out of stock" }));
104
+ return (_jsx(Text, { className: CLS_DISCOUNT_TEXT, children: "Out of stock" }));
84
105
  }
85
106
  const low = stock <= 5;
86
107
  return (_jsx(Text, { className: `mt-1 text-[11px] font-medium ${low
@@ -117,21 +138,21 @@ function ProductListRow({ product, onClick, onAddToWishlist, isWishlisted, }) {
117
138
  onClick ? "cursor-pointer" : "",
118
139
  ]
119
140
  .filter(Boolean)
120
- .join(" "), children: [_jsx(Div, { className: "flex-shrink-0 w-16 h-16 sm:w-20 sm:h-20 rounded-lg overflow-hidden bg-neutral-100 dark:bg-zinc-800", children: product.mainImage ? (_jsx(MediaImage, { src: product.mainImage, alt: product.title, size: "thumbnail" })) : (_jsx(Div, { className: "w-full h-full bg-neutral-200 dark:bg-zinc-700" })) }), _jsxs(Div, { className: "flex flex-1 flex-col min-w-0 gap-0.5", children: [_jsx(Text, { className: `${THEME_CONSTANTS.utilities.textClamp2} text-sm font-medium text-zinc-900 dark:text-zinc-100`, children: product.title }), (product.categoryName || product.brand) && (_jsx(Span, { className: "text-[11px] text-zinc-400 dark:text-zinc-400 truncate", children: [product.categoryName, product.brand].filter(Boolean).join(" · ") })), _jsxs(Div, { className: "flex items-center gap-2 flex-wrap mt-0.5", children: [_jsx(Span, { className: "text-sm font-semibold text-primary", children: formatCurrency(product.price, getDefaultCurrency()) }), discount && (_jsxs(Span, { className: "text-[10px] font-bold text-rose-500", children: ["-", discount, "%"] })), product.rating !== undefined && (_jsxs(Span, { className: "text-[11px] text-zinc-400 dark:text-zinc-400 flex items-center gap-0.5", children: [_jsx(Span, { className: "text-amber-400", children: "\u2605" }), product.rating.toFixed(1)] })), (() => {
141
+ .join(" "), children: [_jsx(Div, { className: `flex-shrink-0 w-16 h-16 sm:w-20 sm:h-20 rounded-lg ${__O.hidden} bg-neutral-100 dark:bg-zinc-800`, children: product.mainImage ? (_jsx(MediaImage, { src: product.mainImage, alt: product.title, size: "thumbnail" })) : (_jsx(Div, { className: "w-full h-full bg-neutral-200 dark:bg-zinc-700" })) }), _jsxs(Div, { className: "flex flex-1 flex-col min-w-0 gap-0.5", children: [_jsx(Text, { className: `${THEME_CONSTANTS.utilities.textClamp2} text-sm font-medium text-zinc-900 dark:text-zinc-100`, children: product.title }), (product.categoryName || product.brand) && (_jsx(Span, { className: "text-[11px] text-zinc-400 dark:text-zinc-400 truncate", children: [product.categoryName, product.brand].filter(Boolean).join(" · ") })), _jsxs(Div, { className: "flex items-center gap-2 flex-wrap mt-0.5", children: [_jsx(Span, { size: "sm", weight: "semibold", className: "text-primary", children: formatCurrency(product.price, getDefaultCurrency()) }), discount && (_jsxs(Span, { weight: "bold", className: CLS_DISCOUNT_TEXT_BARE, children: ["-", discount, "%"] })), product.rating !== undefined && (_jsxs(Span, { className: "text-[11px] text-zinc-400 dark:text-zinc-400 flex items-center gap-0.5", children: [_jsx(Span, { className: CLS_STAR_BARE, children: "\u2605" }), product.rating.toFixed(1)] })), (() => {
121
142
  const stock = product.stockCount ?? product.stockQuantity ?? product.availableQuantity;
122
143
  if (stock === undefined)
123
144
  return null;
124
145
  if (stock <= 0) {
125
- return (_jsx(Span, { className: "text-[11px] font-semibold text-rose-500", children: "Out of stock" }));
146
+ return (_jsx(Span, { weight: "semibold", className: CLS_BID_TEXT, children: "Out of stock" }));
126
147
  }
127
148
  const low = stock <= 5;
128
- return (_jsx(Span, { className: `text-[11px] font-medium ${low
149
+ return (_jsx(Span, { weight: "medium", className: `text-[11px] ${low
129
150
  ? "text-warning"
130
151
  : "text-zinc-400 dark:text-zinc-400"}`, children: low ? `Only ${stock} left` : `${stock} in stock` }));
131
152
  })()] })] }), onAddToWishlist && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: (e) => {
132
153
  e.stopPropagation();
133
154
  onAddToWishlist(product.id);
134
- }, "aria-label": isWishlisted ? "Remove from wishlist" : "Add to wishlist", className: `flex-shrink-0 h-8 w-8 flex items-center justify-center rounded-full text-base leading-none ${isWishlisted ? "text-rose-500" : "text-zinc-300 dark:text-zinc-600 hover:text-rose-400"}`, children: isWishlisted ? "♥" : "♡" }))] }));
155
+ }, "aria-label": isWishlisted ? "Remove from wishlist" : "Add to wishlist", className: `flex-shrink-0 h-8 w-8 flex items-center justify-center rounded-full text-base leading-none ${isWishlisted ? CLS_HEART_ROSE_ACTIVE : CLS_HEART_ROSE_IDLE}`, children: isWishlisted ? "♥" : "♡" }))] }));
135
156
  }
136
157
  function safeHref(href) {
137
158
  if (!href)
@@ -1,4 +1,5 @@
1
1
  import { jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Div } from "../../../ui/components/Div";
2
3
  export function ProductInfo({ isLoading = false, renderTitle, renderPrice, renderBadges, renderDescription, renderVariants, renderSeller, renderRating, className = "", }) {
3
- return (_jsxs("div", { className: `space-y-4 ${className}`, "data-section": "productinfo-div-425", children: [renderTitle?.(isLoading), renderRating?.(), renderPrice?.(isLoading), renderBadges?.(), renderVariants?.(), renderDescription?.(), renderSeller?.()] }));
4
+ return (_jsxs(Div, { className: `space-y-4 ${className}`, children: [renderTitle?.(isLoading), renderRating?.(), renderPrice?.(isLoading), renderBadges?.(), renderVariants?.(), renderDescription?.(), renderSeller?.()] }));
4
5
  }
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import React from "react";
4
+ import { Div } from "../../../ui/components/Div";
4
5
  const DEFAULT_TABS = [
5
6
  { value: "description", label: "Description" },
6
7
  { value: "specs", label: "Specifications" },
@@ -17,7 +18,7 @@ export function ProductTabs({ renderDescription, renderSpecs, renderReviews, ext
17
18
  ...extraTabs,
18
19
  ];
19
20
  const tabs = allTabs.length > 0 ? allTabs : DEFAULT_TABS;
20
- return (_jsxs("div", { className: className, "data-section": "producttabs-div-426", children: [renderTabBar ? (renderTabBar(activeTab, setActiveTab, tabs)) : (_jsx("div", { className: "flex gap-4 border-b mb-4", "data-section": "producttabs-div-427", children: tabs.map((t) => (_jsx("button", { onClick: () => setActiveTab(t.value), className: `pb-2 text-sm font-medium border-b-2 transition-colors ${activeTab === t.value
21
+ return (_jsxs(Div, { className: className, children: [renderTabBar ? (renderTabBar(activeTab, setActiveTab, tabs)) : (_jsx(Div, { className: "flex gap-4 border-b mb-4", children: tabs.map((t) => (_jsx("button", { onClick: () => setActiveTab(t.value), className: `pb-2 text-sm font-medium border-b-2 transition-colors ${activeTab === t.value
21
22
  ? "border-current text-current"
22
23
  : "border-transparent text-zinc-500 dark:text-zinc-400"}`, children: t.label }, t.value))) })), activeTab === "description" && renderDescription?.(), activeTab === "specs" && renderSpecs?.(), activeTab === "reviews" && renderReviews?.(), renderExtraTab?.(activeTab)] }));
23
24
  }