@mohasinac/appkit 2.7.27 → 2.7.31

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 (397) hide show
  1. package/dist/_internal/client/features/filters/filter-load-options.d.ts +29 -0
  2. package/dist/_internal/client/features/filters/filter-load-options.js +98 -0
  3. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +1 -1
  4. package/dist/_internal/server/features/checkout/actions.js +42 -35
  5. package/dist/_internal/server/features/classified/adapters.d.ts +21 -0
  6. package/dist/_internal/server/features/classified/adapters.js +24 -0
  7. package/dist/_internal/server/features/classified/index.d.ts +3 -0
  8. package/dist/_internal/server/features/classified/index.js +3 -0
  9. package/dist/_internal/server/features/classified/metadata.d.ts +8 -0
  10. package/dist/_internal/server/features/classified/metadata.js +43 -0
  11. package/dist/_internal/server/features/classified/og.d.ts +30 -0
  12. package/dist/_internal/server/features/classified/og.js +76 -0
  13. package/dist/_internal/server/features/digital-code/adapters.d.ts +21 -0
  14. package/dist/_internal/server/features/digital-code/adapters.js +29 -0
  15. package/dist/_internal/server/features/digital-code/index.d.ts +3 -0
  16. package/dist/_internal/server/features/digital-code/index.js +3 -0
  17. package/dist/_internal/server/features/digital-code/metadata.d.ts +8 -0
  18. package/dist/_internal/server/features/digital-code/metadata.js +36 -0
  19. package/dist/_internal/server/features/digital-code/og.d.ts +27 -0
  20. package/dist/_internal/server/features/digital-code/og.js +77 -0
  21. package/dist/_internal/server/features/live/adapters.d.ts +21 -0
  22. package/dist/_internal/server/features/live/adapters.js +34 -0
  23. package/dist/_internal/server/features/live/index.d.ts +3 -0
  24. package/dist/_internal/server/features/live/index.js +3 -0
  25. package/dist/_internal/server/features/live/metadata.d.ts +8 -0
  26. package/dist/_internal/server/features/live/metadata.js +39 -0
  27. package/dist/_internal/server/features/live/og.d.ts +27 -0
  28. package/dist/_internal/server/features/live/og.js +72 -0
  29. package/dist/_internal/server/features/promotions/actions.js +4 -3
  30. package/dist/_internal/server/jobs/core/onOrderCreate.js +19 -16
  31. package/dist/_internal/server/jobs/core/onOrderStatusChange.js +25 -22
  32. package/dist/_internal/server/jobs/core/onProductWrite.js +48 -58
  33. package/dist/_internal/shared/actions/action-registry.js +504 -9
  34. package/dist/_internal/shared/features/blog/schema.d.ts +4 -4
  35. package/dist/_internal/shared/features/brands/schema.d.ts +5 -5
  36. package/dist/_internal/shared/features/cart/schema.d.ts +18 -18
  37. package/dist/_internal/shared/features/categories/bundle-copy.d.ts +1 -1
  38. package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +38 -38
  39. package/dist/_internal/shared/features/events/schema.d.ts +8 -8
  40. package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
  41. package/dist/_internal/shared/features/products/schema.d.ts +42 -42
  42. package/dist/_internal/shared/features/promotions/schema.d.ts +4 -4
  43. package/dist/_internal/shared/features/reviews/schema.d.ts +1 -1
  44. package/dist/_internal/shared/media/limits.js +4 -3
  45. package/dist/client.d.ts +4 -0
  46. package/dist/client.js +2 -0
  47. package/dist/configs/next.js +4 -0
  48. package/dist/constants/api-endpoints.d.ts +6 -0
  49. package/dist/constants/api-endpoints.js +2 -0
  50. package/dist/constants/field-names.d.ts +1 -0
  51. package/dist/constants/field-names.js +1 -0
  52. package/dist/constants/table-keys.d.ts +6 -0
  53. package/dist/constants/table-keys.js +9 -0
  54. package/dist/core/hooks/useSyncManager.js +9 -8
  55. package/dist/features/about/components/FeesView.js +10 -7
  56. package/dist/features/about/components/HelpPageView.js +10 -1
  57. package/dist/features/about/components/HowAuctionsWorkView.js +10 -1
  58. package/dist/features/about/components/HowCheckoutWorksView.js +10 -1
  59. package/dist/features/about/components/HowOffersWorkView.js +10 -1
  60. package/dist/features/about/components/HowOrdersWorkView.js +10 -1
  61. package/dist/features/about/components/HowPayoutsWorkView.js +10 -1
  62. package/dist/features/about/components/HowPreOrdersWorkView.js +10 -1
  63. package/dist/features/about/components/HowReviewsWorkView.js +10 -1
  64. package/dist/features/about/components/PublicProfileView.js +46 -16
  65. package/dist/features/about/components/SecurityPrivacyView.js +7 -1
  66. package/dist/features/account/components/AddressesIndexListing.js +2 -2
  67. package/dist/features/account/components/NotificationBell.js +27 -16
  68. package/dist/features/account/components/NotificationPreferencesPanel.d.ts +9 -0
  69. package/dist/features/account/components/NotificationPreferencesPanel.js +91 -0
  70. package/dist/features/account/components/UserSidebar.js +4 -4
  71. package/dist/features/account/components/UserSupportView.js +16 -6
  72. package/dist/features/account/components/index.d.ts +2 -0
  73. package/dist/features/account/components/index.js +1 -0
  74. package/dist/features/account/schemas/index.d.ts +4 -4
  75. package/dist/features/account/types/index.d.ts +34 -0
  76. package/dist/features/admin/actions/admin-actions.js +4 -3
  77. package/dist/features/admin/actions/notification-actions.d.ts +24 -22
  78. package/dist/features/admin/actions/notification-actions.js +122 -22
  79. package/dist/features/admin/components/AdminAdEditorView.js +29 -15
  80. package/dist/features/admin/components/AdminAddressEditorView.d.ts +7 -0
  81. package/dist/features/admin/components/AdminAddressEditorView.js +117 -0
  82. package/dist/features/admin/components/AdminAdsView.js +22 -28
  83. package/dist/features/admin/components/AdminAllEventEntriesView.js +6 -1
  84. package/dist/features/admin/components/AdminBidsView.js +10 -3
  85. package/dist/features/admin/components/AdminBlogEditorView.js +2 -2
  86. package/dist/features/admin/components/AdminBlogView.js +8 -3
  87. package/dist/features/admin/components/AdminBrandsView.js +7 -2
  88. package/dist/features/admin/components/AdminBundleEditorView.js +5 -2
  89. package/dist/features/admin/components/AdminCarouselEditorView.js +6 -3
  90. package/dist/features/admin/components/AdminCarouselView.js +13 -7
  91. package/dist/features/admin/components/AdminCategoriesView.js +8 -3
  92. package/dist/features/admin/components/AdminCategoryEditorView.js +12 -9
  93. package/dist/features/admin/components/AdminContactView.js +6 -1
  94. package/dist/features/admin/components/AdminCouponEditorView.js +8 -2
  95. package/dist/features/admin/components/AdminCouponsView.js +6 -1
  96. package/dist/features/admin/components/AdminEmployeeEditorView.js +12 -9
  97. package/dist/features/admin/components/AdminFaqEditorView.js +2 -2
  98. package/dist/features/admin/components/AdminFaqsView.js +7 -2
  99. package/dist/features/admin/components/AdminFeatureFlagsView.js +58 -13
  100. package/dist/features/admin/components/AdminFeaturesView.js +4 -3
  101. package/dist/features/admin/components/AdminMediaView.js +9 -8
  102. package/dist/features/admin/components/AdminNavigationView.js +10 -17
  103. package/dist/features/admin/components/AdminNewsletterView.js +6 -1
  104. package/dist/features/admin/components/AdminNotificationsView.js +11 -3
  105. package/dist/features/admin/components/AdminOrdersView.js +6 -1
  106. package/dist/features/admin/components/AdminPayoutsView.js +10 -3
  107. package/dist/features/admin/components/AdminPrizeDrawsView.js +10 -3
  108. package/dist/features/admin/components/AdminProductEditorView.d.ts +3 -1
  109. package/dist/features/admin/components/AdminProductEditorView.js +12 -9
  110. package/dist/features/admin/components/AdminProductsView.js +18 -12
  111. package/dist/features/admin/components/AdminReturnRequestsView.js +5 -4
  112. package/dist/features/admin/components/AdminReviewsView.js +36 -26
  113. package/dist/features/admin/components/AdminScammerEditorView.js +3 -2
  114. package/dist/features/admin/components/AdminScammersView.js +28 -26
  115. package/dist/features/admin/components/AdminSectionsView.js +112 -99
  116. package/dist/features/admin/components/AdminSessionsView.js +10 -3
  117. package/dist/features/admin/components/AdminSidebar.js +4 -4
  118. package/dist/features/admin/components/AdminSiteSettingsView.js +45 -4
  119. package/dist/features/admin/components/AdminStoresView.js +6 -1
  120. package/dist/features/admin/components/AdminSublistingCategoriesView.js +0 -1
  121. package/dist/features/admin/components/AdminSupportTicketDetailView.js +1 -1
  122. package/dist/features/admin/components/AdminSupportTicketsView.js +32 -34
  123. package/dist/features/admin/components/AdminTeamView.js +6 -1
  124. package/dist/features/admin/components/AdminUserEditorView.js +8 -15
  125. package/dist/features/admin/components/AdminUsersView.js +6 -1
  126. package/dist/features/admin/components/AdminViewCards.js +4 -3
  127. package/dist/features/admin/components/DashboardStats.js +2 -2
  128. package/dist/features/admin/components/DataTable.js +2 -2
  129. package/dist/features/admin/components/index.d.ts +2 -0
  130. package/dist/features/admin/components/index.js +1 -0
  131. package/dist/features/admin/components/sections/adminSectionsTypes.js +4 -3
  132. package/dist/features/admin/repository/chat.repository.js +8 -8
  133. package/dist/features/admin/repository/site-settings.repository.d.ts +1 -0
  134. package/dist/features/admin/repository/site-settings.repository.js +11 -9
  135. package/dist/features/admin/schemas/firestore.d.ts +38 -0
  136. package/dist/features/admin/schemas/firestore.js +15 -0
  137. package/dist/features/auctions/components/AuctionBidsTable.d.ts +13 -0
  138. package/dist/features/auctions/components/AuctionBidsTable.js +62 -0
  139. package/dist/features/auctions/components/AuctionDetailPageView.js +15 -21
  140. package/dist/features/auctions/components/AuctionFilters.d.ts +7 -1
  141. package/dist/features/auctions/components/AuctionFilters.js +3 -2
  142. package/dist/features/auctions/components/MarketplaceAuctionCard.js +18 -9
  143. package/dist/features/auctions/components/MarketplaceAuctionGrid.js +3 -2
  144. package/dist/features/auctions/components/index.d.ts +2 -1
  145. package/dist/features/auctions/components/index.js +1 -1
  146. package/dist/features/auctions/schemas/index.d.ts +14 -14
  147. package/dist/features/auth/actions/realtime-token-actions.js +19 -4
  148. package/dist/features/auth/components/RegisterForm.js +8 -4
  149. package/dist/features/auth/consent-otp.d.ts +2 -0
  150. package/dist/features/auth/consent-otp.js +8 -0
  151. package/dist/features/auth/schemas/firestore.d.ts +2 -0
  152. package/dist/features/auth/schemas/firestore.js +18 -25
  153. package/dist/features/auth/schemas/index.d.ts +2 -2
  154. package/dist/features/before-after/api/[id]/route.js +8 -6
  155. package/dist/features/before-after/schemas/index.d.ts +2 -2
  156. package/dist/features/blog/actions/blog-actions.d.ts +3 -3
  157. package/dist/features/blog/components/BlogIndexListing.js +21 -2
  158. package/dist/features/blog/components/BlogPostForm.js +11 -5
  159. package/dist/features/blog/components/BlogPostView.js +10 -2
  160. package/dist/features/blog/schemas/index.d.ts +18 -18
  161. package/dist/features/cart/components/CartDrawer.js +3 -2
  162. package/dist/features/cart/components/CartView.js +2 -1
  163. package/dist/features/cart/components/CheckoutView.js +2 -1
  164. package/dist/features/cart/repository/cart.repository.js +4 -3
  165. package/dist/features/cart/utils/pending-ops.d.ts +1 -1
  166. package/dist/features/categories/api/[id]/route.js +4 -3
  167. package/dist/features/categories/api/route.js +4 -3
  168. package/dist/features/categories/components/BrandDetailPageView.js +2 -2
  169. package/dist/features/categories/components/BrandDetailTabs.d.ts +5 -1
  170. package/dist/features/categories/components/BrandDetailTabs.js +30 -16
  171. package/dist/features/categories/components/BundleCollage.d.ts +8 -0
  172. package/dist/features/categories/components/BundleCollage.js +50 -0
  173. package/dist/features/categories/components/BundleDetailView.js +2 -10
  174. package/dist/features/categories/components/BundleItemsPicker.js +20 -13
  175. package/dist/features/categories/components/CategoriesIndexListing.js +28 -9
  176. package/dist/features/categories/components/CategoryDetailPageView.js +2 -2
  177. package/dist/features/categories/components/CategoryDetailTabs.d.ts +5 -1
  178. package/dist/features/categories/components/CategoryDetailTabs.js +31 -16
  179. package/dist/features/categories/components/CategoryProductsListing.js +52 -13
  180. package/dist/features/categories/components/index.d.ts +2 -0
  181. package/dist/features/categories/components/index.js +1 -0
  182. package/dist/features/categories/schemas/index.d.ts +6 -6
  183. package/dist/features/checkout/actions/checkout-actions.js +4 -3
  184. package/dist/features/checkout/hooks/usePaymentCheckout.js +31 -22
  185. package/dist/features/classified/components/ClassifiedFilters.d.ts +12 -0
  186. package/dist/features/classified/components/ClassifiedFilters.js +20 -0
  187. package/dist/features/classified/components/ClassifiedIndexListing.d.ts +4 -0
  188. package/dist/features/classified/components/ClassifiedIndexListing.js +110 -0
  189. package/dist/features/classified/components/ClassifiedListView.d.ts +6 -0
  190. package/dist/features/classified/components/ClassifiedListView.js +43 -0
  191. package/dist/features/classified/components/index.d.ts +6 -0
  192. package/dist/features/classified/components/index.js +3 -0
  193. package/dist/features/collections/api/[slug]/route.js +16 -12
  194. package/dist/features/collections/schemas/index.d.ts +5 -5
  195. package/dist/features/consultation/api/[id]/route.js +12 -9
  196. package/dist/features/consultation/components/ConsultationForm.js +3 -2
  197. package/dist/features/consultation/schemas/index.d.ts +6 -6
  198. package/dist/features/contact/email.js +77 -116
  199. package/dist/features/copilot/components/AdminCopilotView.js +12 -2
  200. package/dist/features/corporate/api/[id]/route.js +12 -9
  201. package/dist/features/corporate/components/CorporateInquiryForm.js +2 -1
  202. package/dist/features/digital-codes/components/DigitalCodeFilters.d.ts +12 -0
  203. package/dist/features/digital-codes/components/DigitalCodeFilters.js +17 -0
  204. package/dist/features/digital-codes/components/DigitalCodesIndexListing.d.ts +4 -0
  205. package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +107 -0
  206. package/dist/features/digital-codes/components/DigitalCodesListView.d.ts +6 -0
  207. package/dist/features/digital-codes/components/DigitalCodesListView.js +37 -0
  208. package/dist/features/digital-codes/components/index.d.ts +6 -0
  209. package/dist/features/digital-codes/components/index.js +3 -0
  210. package/dist/features/events/actions/event-actions.js +4 -3
  211. package/dist/features/events/components/AdminEventEditorView.js +3 -2
  212. package/dist/features/events/components/AdminEventsView.js +4 -2
  213. package/dist/features/events/components/EventPollWidget.js +5 -5
  214. package/dist/features/events/components/EventsIndexListing.js +2 -2
  215. package/dist/features/events/repository/event-entry.repository.d.ts +1 -0
  216. package/dist/features/events/repository/event-entry.repository.js +5 -0
  217. package/dist/features/events/schemas/index.d.ts +20 -20
  218. package/dist/features/faq/actions/faq-actions.d.ts +8 -8
  219. package/dist/features/faq/components/ContactCTA.js +3 -1
  220. package/dist/features/faq/components/FAQAccordion.js +1 -1
  221. package/dist/features/faq/schemas/index.d.ts +4 -4
  222. package/dist/features/filters/AsyncFacetSection.d.ts +18 -0
  223. package/dist/features/filters/AsyncFacetSection.js +65 -0
  224. package/dist/features/filters/index.d.ts +2 -0
  225. package/dist/features/filters/index.js +1 -0
  226. package/dist/features/forms/Checkbox.js +2 -2
  227. package/dist/features/forms/Input.js +2 -2
  228. package/dist/features/forms/Radio.js +5 -5
  229. package/dist/features/forms/Select.js +2 -2
  230. package/dist/features/forms/Slider.js +2 -2
  231. package/dist/features/forms/Textarea.js +2 -2
  232. package/dist/features/homepage/api/[id]/route.js +4 -3
  233. package/dist/features/homepage/api/sections/[id]/route.js +12 -9
  234. package/dist/features/homepage/components/AdSlot.js +2 -1
  235. package/dist/features/homepage/components/AdvertisementBanner.js +5 -3
  236. package/dist/features/homepage/components/BrandsSection.js +2 -2
  237. package/dist/features/homepage/components/CTABannerSection.js +2 -2
  238. package/dist/features/homepage/components/CharacterHotspot.d.ts +2 -2
  239. package/dist/features/homepage/components/CharacterHotspot.js +119 -157
  240. package/dist/features/homepage/components/CharacterHotspotForm.js +25 -20
  241. package/dist/features/homepage/components/CustomCardsSection.js +8 -6
  242. package/dist/features/homepage/components/FeaturedProductsSection.js +2 -2
  243. package/dist/features/homepage/components/GoogleReviewsSection.js +3 -3
  244. package/dist/features/homepage/components/HeroBanner.js +5 -4
  245. package/dist/features/homepage/components/HeroCarousel.js +13 -26
  246. package/dist/features/homepage/components/HowItWorksSection.js +4 -2
  247. package/dist/features/homepage/components/SocialFeedSection.js +2 -2
  248. package/dist/features/homepage/components/SocialPostCard.js +3 -2
  249. package/dist/features/homepage/lib/social-feed-fetcher.js +6 -3
  250. package/dist/features/layout/AppLayoutShell.d.ts +8 -2
  251. package/dist/features/layout/AppLayoutShell.js +54 -78
  252. package/dist/features/layout/BottomActions.js +43 -48
  253. package/dist/features/live/components/LiveItemFilters.d.ts +12 -0
  254. package/dist/features/live/components/LiveItemFilters.js +24 -0
  255. package/dist/features/live/components/LiveItemsIndexListing.d.ts +4 -0
  256. package/dist/features/live/components/LiveItemsIndexListing.js +108 -0
  257. package/dist/features/live/components/LiveItemsListView.d.ts +6 -0
  258. package/dist/features/live/components/LiveItemsListView.js +43 -0
  259. package/dist/features/live/components/index.d.ts +6 -0
  260. package/dist/features/live/components/index.js +3 -0
  261. package/dist/features/media/MediaLightbox.js +8 -14
  262. package/dist/features/media/types/index.d.ts +2 -2
  263. package/dist/features/media/upload/CameraCapture.js +2 -2
  264. package/dist/features/media/upload/ImageUpload.js +4 -2
  265. package/dist/features/media/upload/MediaUploadField.js +24 -8
  266. package/dist/features/media/upload/MediaUploadList.js +1 -1
  267. package/dist/features/orders/actions/order-actions.js +4 -3
  268. package/dist/features/orders/components/MarketplaceOrderCard.js +2 -1
  269. package/dist/features/orders/components/OrderFilters.js +12 -9
  270. package/dist/features/orders/schemas/index.d.ts +6 -6
  271. package/dist/features/pre-orders/api/[id]/route.js +12 -9
  272. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +5 -4
  273. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +29 -22
  274. package/dist/features/pre-orders/components/PreOrderFilters.d.ts +7 -1
  275. package/dist/features/pre-orders/components/PreOrderFilters.js +3 -2
  276. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +17 -52
  277. package/dist/features/pre-orders/components/PreorderCard.d.ts +0 -9
  278. package/dist/features/pre-orders/components/PreorderCard.js +2 -13
  279. package/dist/features/pre-orders/components/index.d.ts +1 -1
  280. package/dist/features/pre-orders/components/index.js +1 -1
  281. package/dist/features/pre-orders/schemas/index.d.ts +10 -10
  282. package/dist/features/products/api/[id]/route.js +9 -7
  283. package/dist/features/products/api/route.js +1 -1
  284. package/dist/features/products/columns/productTableColumns.js +3 -3
  285. package/dist/features/products/components/AuctionsIndexListing.js +15 -51
  286. package/dist/features/products/components/BidHistory.js +2 -2
  287. package/dist/features/products/components/CompareOverlay.d.ts +2 -0
  288. package/dist/features/products/components/CompareOverlay.js +3 -2
  289. package/dist/features/products/components/MakeOfferButton.js +20 -14
  290. package/dist/features/products/components/MarketplacePrizeDrawCard.js +2 -1
  291. package/dist/features/products/components/PrizeDrawCollage.d.ts +1 -15
  292. package/dist/features/products/components/PrizeDrawCollage.js +54 -14
  293. package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -1
  294. package/dist/features/products/components/PrizeDrawEntryActions.js +2 -1
  295. package/dist/features/products/components/PrizeDrawItemsEditor.js +9 -7
  296. package/dist/features/products/components/PrizeDrawsIndexListing.js +18 -51
  297. package/dist/features/products/components/PrizeRevealModal.js +24 -14
  298. package/dist/features/products/components/ProductDetailPageView.js +2 -1
  299. package/dist/features/products/components/ProductFilters.d.ts +7 -1
  300. package/dist/features/products/components/ProductFilters.js +11 -8
  301. package/dist/features/products/components/ProductForm.js +18 -16
  302. package/dist/features/products/components/ProductGalleryClient.js +2 -1
  303. package/dist/features/products/components/ProductGrid.js +12 -15
  304. package/dist/features/products/components/ProductsIndexListing.js +16 -52
  305. package/dist/features/products/components/ProductsIndexPageView.js +2 -2
  306. package/dist/features/products/repository/products.repository.d.ts +4 -0
  307. package/dist/features/products/repository/products.repository.js +22 -3
  308. package/dist/features/products/schemas/firestore.d.ts +7 -1
  309. package/dist/features/products/schemas/index.d.ts +56 -56
  310. package/dist/features/products/schemas/product-features.validators.d.ts +14 -14
  311. package/dist/features/products/types/index.d.ts +4 -0
  312. package/dist/features/promotions/components/CouponsIndexListing.js +1 -1
  313. package/dist/features/promotions/schemas/index.d.ts +6 -6
  314. package/dist/features/reviews/actions/review-actions.js +6 -5
  315. package/dist/features/reviews/api/[id]/route.js +4 -3
  316. package/dist/features/reviews/components/ReviewDetailPageView.js +2 -2
  317. package/dist/features/reviews/components/ReviewDetailShell.js +6 -3
  318. package/dist/features/reviews/components/ReviewsIndexListing.js +2 -2
  319. package/dist/features/reviews/schemas/index.d.ts +6 -6
  320. package/dist/features/scams/components/ScamProfileView.js +19 -10
  321. package/dist/features/scams/components/ScamRegistryView.js +2 -1
  322. package/dist/features/search/components/Search.d.ts +1 -1
  323. package/dist/features/search/components/Search.js +56 -49
  324. package/dist/features/search/schemas/index.d.ts +5 -5
  325. package/dist/features/seller/actions/offer-actions.js +11 -9
  326. package/dist/features/seller/components/SellerAddressesView.js +6 -4
  327. package/dist/features/seller/components/SellerBidsView.js +2 -2
  328. package/dist/features/seller/components/SellerCouponsView.js +1 -1
  329. package/dist/features/seller/components/SellerOffersPanel.js +6 -1
  330. package/dist/features/seller/components/SellerOrdersView.js +1 -1
  331. package/dist/features/seller/components/SellerPayoutSettingsView.js +3 -3
  332. package/dist/features/seller/components/SellerPreOrdersView.js +5 -4
  333. package/dist/features/seller/components/SellerPrizeDrawsView.js +5 -4
  334. package/dist/features/seller/components/SellerProductShell.d.ts +19 -1
  335. package/dist/features/seller/components/SellerProductShell.js +75 -9
  336. package/dist/features/seller/components/SellerProductsView.js +10 -11
  337. package/dist/features/seller/components/SellerShippingView.js +3 -3
  338. package/dist/features/seller/components/SellerSidebar.js +10 -7
  339. package/dist/features/seller/components/SellerStorefrontView.js +3 -3
  340. package/dist/features/seller/schemas/index.d.ts +4 -4
  341. package/dist/features/shell/FormShell.js +2 -1
  342. package/dist/features/shell/QuickFormDrawer.js +4 -3
  343. package/dist/features/shell/StepForm.js +4 -3
  344. package/dist/features/stores/actions/store-query-actions.js +4 -3
  345. package/dist/features/stores/components/StoreAboutView.js +2 -1
  346. package/dist/features/stores/components/StoreAuctionsListing.js +43 -64
  347. package/dist/features/stores/components/StoreDetailLayoutView.js +18 -4
  348. package/dist/features/stores/components/StorePreOrdersListing.js +33 -57
  349. package/dist/features/stores/components/StoreProductsListing.js +16 -49
  350. package/dist/features/stores/components/StoresIndexListing.js +2 -2
  351. package/dist/features/stores/schemas/index.d.ts +2 -2
  352. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +8 -7
  353. package/dist/features/wishlist/hooks/useGuestWishlist.d.ts +5 -5
  354. package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +6 -6
  355. package/dist/features/wishlist/utils/guest-wishlist.d.ts +5 -5
  356. package/dist/index.d.ts +27 -3
  357. package/dist/index.js +1743 -1725
  358. package/dist/monitoring/server-logger.js +5 -9
  359. package/dist/next/api/apiHandler.js +56 -37
  360. package/dist/next/components/GlobalError.js +2 -1
  361. package/dist/next/routing/route-map.d.ts +41 -0
  362. package/dist/next/routing/route-map.js +17 -0
  363. package/dist/react/ErrorBoundary.js +2 -1
  364. package/dist/react/contexts/SessionContext.js +38 -28
  365. package/dist/react/hooks/useCamera.d.ts +1 -1
  366. package/dist/react/hooks/useCamera.js +8 -7
  367. package/dist/seed/products-auctions-seed-data.js +40 -40
  368. package/dist/seed/products-preorders-seed-data.js +16 -16
  369. package/dist/seed/products-prize-draws-seed-data.js +4 -4
  370. package/dist/seed/products-standard-seed-data.js +202 -202
  371. package/dist/seed/site-settings-seed-data.js +6 -0
  372. package/dist/server-entry.d.ts +3 -0
  373. package/dist/server-entry.js +3 -0
  374. package/dist/server.d.ts +12 -0
  375. package/dist/server.js +15 -0
  376. package/dist/tailwind-utilities.css +1 -1
  377. package/dist/ui/DataTable.js +28 -7
  378. package/dist/ui/components/Button.d.ts +8 -1
  379. package/dist/ui/components/Button.js +47 -8
  380. package/dist/ui/components/CollageLightbox.d.ts +18 -0
  381. package/dist/ui/components/CollageLightbox.js +41 -0
  382. package/dist/ui/components/Dropdown.js +7 -6
  383. package/dist/ui/components/ImageLightbox.d.ts +7 -1
  384. package/dist/ui/components/ImageLightbox.js +15 -5
  385. package/dist/ui/components/PageLoader.js +4 -3
  386. package/dist/ui/components/PaginatedMultiSelect.d.ts +28 -0
  387. package/dist/ui/components/PaginatedMultiSelect.js +141 -0
  388. package/dist/ui/components/PaginatedMultiSelect.style.css +272 -0
  389. package/dist/ui/components/Semantic.js +1 -1
  390. package/dist/ui/components/SideDrawer.js +17 -15
  391. package/dist/ui/components/index.style.css +1 -0
  392. package/dist/ui/index.d.ts +2 -0
  393. package/dist/ui/index.js +1 -0
  394. package/dist/utils/number.formatter.js +5 -13
  395. package/dist/utils/string.formatter.js +21 -18
  396. package/dist/validation/schemas.d.ts +2 -2
  397. package/package.json +1 -1
@@ -10,6 +10,8 @@
10
10
  */
11
11
  import { NextResponse } from "next/server.js";
12
12
  import { getProviders } from "../../../../contracts";
13
+ const ERR_DB_NOT_CONFIGURED = "DB not configured";
14
+ const ERR_INTERNAL_SERVER_ERROR = "Internal server error";
13
15
  export async function GET(request, { params }) {
14
16
  try {
15
17
  const { id } = await params;
@@ -18,7 +20,7 @@ export async function GET(request, { params }) {
18
20
  }
19
21
  const { db } = getProviders();
20
22
  if (!db)
21
- return NextResponse.json({ success: false, error: "DB not configured" }, { status: 503 });
23
+ return NextResponse.json({ success: false, error: ERR_DB_NOT_CONFIGURED }, { status: 503 });
22
24
  const repo = db.getRepository("before_after");
23
25
  const item = await repo.findById(id);
24
26
  if (!item) {
@@ -32,7 +34,7 @@ export async function GET(request, { params }) {
32
34
  catch (error) {
33
35
  return NextResponse.json({
34
36
  success: false,
35
- error: error instanceof Error ? error.message : "Internal server error",
37
+ error: error instanceof Error ? error.message : ERR_INTERNAL_SERVER_ERROR,
36
38
  }, { status: 500 });
37
39
  }
38
40
  }
@@ -45,7 +47,7 @@ export async function PATCH(request, { params }) {
45
47
  const body = await request.json();
46
48
  const { db } = getProviders();
47
49
  if (!db)
48
- return NextResponse.json({ success: false, error: "DB not configured" }, { status: 503 });
50
+ return NextResponse.json({ success: false, error: ERR_DB_NOT_CONFIGURED }, { status: 503 });
49
51
  const repo = db.getRepository("before_after");
50
52
  const updated = await repo.update(id, body);
51
53
  if (!updated) {
@@ -59,7 +61,7 @@ export async function PATCH(request, { params }) {
59
61
  catch (error) {
60
62
  return NextResponse.json({
61
63
  success: false,
62
- error: error instanceof Error ? error.message : "Internal server error",
64
+ error: error instanceof Error ? error.message : ERR_INTERNAL_SERVER_ERROR,
63
65
  }, { status: 500 });
64
66
  }
65
67
  }
@@ -71,7 +73,7 @@ export async function DELETE(request, { params }) {
71
73
  }
72
74
  const { db } = getProviders();
73
75
  if (!db)
74
- return NextResponse.json({ success: false, error: "DB not configured" }, { status: 503 });
76
+ return NextResponse.json({ success: false, error: ERR_DB_NOT_CONFIGURED }, { status: 503 });
75
77
  const repo = db.getRepository("before_after");
76
78
  await repo.delete(id);
77
79
  return NextResponse.json({
@@ -82,7 +84,7 @@ export async function DELETE(request, { params }) {
82
84
  catch (error) {
83
85
  return NextResponse.json({
84
86
  success: false,
85
- error: error instanceof Error ? error.message : "Internal server error",
87
+ error: error instanceof Error ? error.message : ERR_INTERNAL_SERVER_ERROR,
86
88
  }, { status: 500 });
87
89
  }
88
90
  }
@@ -27,8 +27,8 @@ export declare const beforeAfterItemSchema: z.ZodObject<{
27
27
  title: string;
28
28
  isActive: boolean;
29
29
  createdAt?: string | undefined;
30
- productId?: string | undefined;
31
30
  description?: string | undefined;
31
+ productId?: string | undefined;
32
32
  concern?: string | undefined;
33
33
  beforeImageUrl?: string | undefined;
34
34
  afterImageUrl?: string | undefined;
@@ -38,9 +38,9 @@ export declare const beforeAfterItemSchema: z.ZodObject<{
38
38
  title: string;
39
39
  createdAt?: string | undefined;
40
40
  sortOrder?: number | undefined;
41
+ description?: string | undefined;
41
42
  isActive?: boolean | undefined;
42
43
  productId?: string | undefined;
43
- description?: string | undefined;
44
44
  concern?: string | undefined;
45
45
  beforeImageUrl?: string | undefined;
46
46
  afterImageUrl?: string | undefined;
@@ -73,9 +73,9 @@ export declare const createBlogPostSchema: z.ZodObject<{
73
73
  title: string;
74
74
  content: string;
75
75
  category: "news" | "tips" | "guides" | "updates" | "community";
76
+ slug: string;
76
77
  tags: string[];
77
78
  isFeatured: boolean;
78
- slug: string;
79
79
  excerpt: string;
80
80
  readTimeMinutes: number;
81
81
  contentImages: {
@@ -212,9 +212,9 @@ export declare const updateBlogPostSchema: z.ZodObject<{
212
212
  title?: string | undefined;
213
213
  content?: string | undefined;
214
214
  category?: "news" | "tips" | "guides" | "updates" | "community" | undefined;
215
+ slug?: string | undefined;
215
216
  tags?: string[] | undefined;
216
217
  isFeatured?: boolean | undefined;
217
- slug?: string | undefined;
218
218
  publishedAt?: string | undefined;
219
219
  coverImage?: {
220
220
  type: "video" | "image" | "file";
@@ -249,9 +249,9 @@ export declare const updateBlogPostSchema: z.ZodObject<{
249
249
  title?: string | undefined;
250
250
  content?: string | undefined;
251
251
  category?: "news" | "tips" | "guides" | "updates" | "community" | undefined;
252
+ slug?: string | undefined;
252
253
  tags?: string[] | undefined;
253
254
  isFeatured?: boolean | undefined;
254
- slug?: string | undefined;
255
255
  publishedAt?: string | undefined;
256
256
  coverImage?: string | {
257
257
  type: "video" | "image" | "file";
@@ -4,13 +4,32 @@ import { useState, useCallback, useMemo } from "react";
4
4
  import { X } from "lucide-react";
5
5
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
6
  import { useBlogPosts } from "../hooks/useBlog";
7
- import { Pagination, ListingToolbar } from "../../../ui";
7
+ import { ListingToolbar, Pagination, Text } from "../../../ui";
8
8
  import { ROUTES } from "../../../next";
9
9
  import { BlogCard } from "./BlogListView";
10
10
  import { BlogFilters, BLOG_PUBLIC_SORT_OPTIONS } from "./BlogFilters";
11
11
  import { TABLE_KEYS, VIEW_MODE } from "../../../constants/table-keys";
12
12
  import { sortBy } from "../../../constants/sort";
13
13
  import { BLOG_FIELDS } from "../../../constants/field-names";
14
+ function renderBlogGrid(props) {
15
+ const { isLoading, posts, view } = props;
16
+ if (isLoading) {
17
+ return (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: Array.from({ length: 6 }).map((_, i) => (_jsxs("div", { className: "rounded-xl border border-zinc-100 dark:border-slate-700 overflow-hidden animate-pulse", children: [_jsx("div", { className: "aspect-video bg-zinc-200 dark:bg-slate-700" }), _jsxs("div", { className: "p-5 space-y-2", children: [_jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-1/4" }), _jsx("div", { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-3/4" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-2/3" })] })] }, i))) }));
18
+ }
19
+ if (posts.length === 0) {
20
+ return _jsx(Text, { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: "No posts found." });
21
+ }
22
+ if (view === "list") {
23
+ return (_jsx("div", { className: "flex flex-col divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800", children: posts.map((post) => _jsx(BlogCard, { post: post, href: String(ROUTES.BLOG.ARTICLE(post.slug)) }, post.id)) }));
24
+ }
25
+ return (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: posts.map((post) => _jsx(BlogCard, { post: post, href: String(ROUTES.BLOG.ARTICLE(post.slug)) }, post.id)) }));
26
+ }
27
+ function renderBlogFilterDrawer(props) {
28
+ const { filterOpen, setFilterOpen, activeFilterCount, clearFilters, applyFilters, pendingTable } = props;
29
+ if (!filterOpen)
30
+ return null;
31
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "flex items-center gap-2 text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close filters", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4", children: _jsx(BlogFilters, { table: pendingTable, variant: "public" }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }));
32
+ }
14
33
  const PAGE_SIZE = 24;
15
34
  const DEFAULT_SORT = sortBy(BLOG_FIELDS.PUBLISHED_AT);
16
35
  const FILTER_KEYS = [TABLE_KEYS.CATEGORY, TABLE_KEYS.DATE_FROM, TABLE_KEYS.DATE_TO];
@@ -89,5 +108,5 @@ export function BlogIndexListing({ initialData }) {
89
108
  const commitSearch = useCallback(() => {
90
109
  table.set(TABLE_KEYS.QUERY, searchInput.trim());
91
110
  }, [searchInput, table]);
92
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search posts...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: BLOG_PUBLIC_SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, view: view, onViewChange: handleViewToggle, onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsx("div", { className: "py-6", children: isLoading ? (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: Array.from({ length: 6 }).map((_, i) => (_jsxs("div", { className: "rounded-xl border border-zinc-100 dark:border-slate-700 overflow-hidden animate-pulse", children: [_jsx("div", { className: "aspect-video bg-zinc-200 dark:bg-slate-700" }), _jsxs("div", { className: "p-5 space-y-2", children: [_jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-1/4" }), _jsx("div", { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-3/4" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-2/3" })] })] }, i))) })) : posts.length === 0 ? (_jsx("p", { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: "No posts found." })) : view === "list" ? (_jsx("div", { className: "flex flex-col divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800", children: posts.map((post) => (_jsx(BlogCard, { post: post, href: String(ROUTES.BLOG.ARTICLE(post.slug)) }, post.id))) })) : (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: posts.map((post) => (_jsx(BlogCard, { post: post, href: String(ROUTES.BLOG.ARTICLE(post.slug)) }, post.id))) })) }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "flex items-center gap-2 text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close filters", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4", children: _jsx(BlogFilters, { table: pendingTable, variant: "public" }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }))] }));
111
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search posts...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: BLOG_PUBLIC_SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, view: view, onViewChange: handleViewToggle, onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsx("div", { className: "py-6", children: renderBlogGrid({ isLoading, posts, view }) }), renderBlogFilterDrawer({ filterOpen, setFilterOpen, activeFilterCount, clearFilters, applyFilters, pendingTable })] }));
93
112
  }
@@ -1,11 +1,19 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Div, Input, Label, RichTextEditor, Select, Stack, TagInput, Text, Textarea, } from "../../../ui";
3
3
  import { Checkbox } from "../../forms/index";
4
4
  import { MediaUploadField, MediaUploadList } from "../../media/index";
5
5
  import { coerceMediaFieldArray, getMediaUrl, } from "../../media/types/index";
6
6
  import { normalizeRichTextHtml, slugify } from "../../../utils/string.formatter";
7
+ function renderBlogPostMetaFields(props) {
8
+ const { value, update, isReadonly, categoryOptions, statusOptions, labels } = props;
9
+ return (_jsxs(_Fragment, { children: [_jsxs(Div, { className: "grid gap-4 md:grid-cols-2", children: [_jsx(Select, { label: labels.category, value: value.category, onValueChange: (category) => update({ category }), options: categoryOptions, disabled: isReadonly }), _jsx(Select, { label: labels.status, value: value.status, onValueChange: (status) => update({ status }), options: statusOptions, disabled: isReadonly })] }), _jsxs(Div, { className: "grid gap-4 md:grid-cols-2", children: [_jsx(TagInput, { label: labels.tags, value: value.tags ?? [], onChange: (tags) => update({ tags }), disabled: isReadonly }), _jsxs(Stack, { gap: "xs", children: [_jsx(Label, { htmlFor: "blog-post-read-time", children: labels.readTime }), _jsx(Input, { id: "blog-post-read-time", type: "number", value: String(value.readTimeMinutes ?? 5), onChange: (event) => update({ readTimeMinutes: parseInt(event.target.value, 10) || 5 }), disabled: isReadonly })] })] }), _jsx(Checkbox, { label: labels.featured, checked: value.isFeatured || false, onChange: (event) => update({ isFeatured: event.target.checked }), disabled: isReadonly })] }));
10
+ }
11
+ function renderBlogPostMediaFields(props) {
12
+ const { value, update, isReadonly, labels, onUploadCover, onUploadContentImage, onUploadAdditionalImage, onAbort, coverImageUrl, contentImages, additionalImages } = props;
13
+ return (_jsxs(_Fragment, { children: [_jsx(MediaUploadField, { label: labels.coverImage, value: coverImageUrl || "", onChange: (url) => update({ coverImage: url ? { url, type: "image" } : null }), onChangeField: (media) => update({ coverImage: media }), onUpload: onUploadCover, onAbort: onAbort, accept: "image/*", maxSizeMB: 10, disabled: isReadonly, helperText: labels.coverImageHelper }), _jsx(MediaUploadList, { label: labels.contentImages, value: contentImages, onChange: (media) => update({ contentImages: media }), onUpload: onUploadContentImage, onAbort: onAbort, accept: "image/*", maxItems: 10, maxSizeMB: 10, disabled: isReadonly, helperText: labels.contentImagesHelper }), _jsx(MediaUploadList, { label: labels.additionalImages, value: additionalImages, onChange: (media) => update({ additionalImages: media }), onUpload: onUploadAdditionalImage, onAbort: onAbort, accept: "image/*", maxItems: 5, maxSizeMB: 10, disabled: isReadonly, helperText: labels.additionalImagesHelper }), isReadonly && coverImageUrl && _jsx(Text, { size: "xs", variant: "secondary", children: coverImageUrl })] }));
14
+ }
7
15
  export function BlogPostForm({ value, onChange, categoryOptions, statusOptions, labels, onUploadCover, onUploadContentImage, onUploadAdditionalImage, onAbort, isReadonly = false, renderContentField, renderContentReadonly, }) {
8
- const coverImageUrl = getMediaUrl(value.coverImage);
16
+ const coverImageUrl = getMediaUrl(value.coverImage) ?? null;
9
17
  const contentImages = coerceMediaFieldArray(value.contentImages);
10
18
  const additionalImages = coerceMediaFieldArray(value.additionalImages);
11
19
  const update = (partial) => {
@@ -22,7 +30,5 @@ export function BlogPostForm({ value, onChange, categoryOptions, statusOptions,
22
30
  value: value.content || "",
23
31
  onChange: (content) => update({ content }),
24
32
  isReadonly,
25
- })) : isReadonly && renderContentReadonly ? (renderContentReadonly(value.content || "")) : (_jsxs(Stack, { gap: "xs", children: [_jsx(RichTextEditor, { value: normalizeRichTextHtml(value.content || ""), onChange: (content) => update({ content }), disabled: isReadonly, minHeightClassName: "min-h-[240px]", placeholder: "Write blog content" }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Rich text is supported for blog content." })] }))] }), _jsx(MediaUploadField, { label: labels.coverImage, value: coverImageUrl || "", onChange: (url) => update({ coverImage: url ? { url, type: "image" } : null }), onChangeField: (media) => update({ coverImage: media }), onUpload: onUploadCover, onAbort: onAbort, accept: "image/*", maxSizeMB: 10, disabled: isReadonly, helperText: labels.coverImageHelper }), _jsx(MediaUploadList, { label: labels.contentImages, value: contentImages, onChange: (media) => update({ contentImages: media }), onUpload: onUploadContentImage, onAbort: onAbort, accept: "image/*", maxItems: 10, maxSizeMB: 10, disabled: isReadonly, helperText: labels.contentImagesHelper }), _jsx(MediaUploadList, { label: labels.additionalImages, value: additionalImages, onChange: (media) => update({ additionalImages: media }), onUpload: onUploadAdditionalImage, onAbort: onAbort, accept: "image/*", maxItems: 5, maxSizeMB: 10, disabled: isReadonly, helperText: labels.additionalImagesHelper }), _jsxs(Div, { className: "grid gap-4 md:grid-cols-2", children: [_jsx(Select, { label: labels.category, value: value.category, onValueChange: (category) => update({ category }), options: categoryOptions, disabled: isReadonly }), _jsx(Select, { label: labels.status, value: value.status, onValueChange: (status) => update({ status }), options: statusOptions, disabled: isReadonly })] }), _jsxs(Div, { className: "grid gap-4 md:grid-cols-2", children: [_jsx(TagInput, { label: labels.tags, value: value.tags ?? [], onChange: (tags) => update({ tags }), disabled: isReadonly }), _jsxs(Stack, { gap: "xs", children: [_jsx(Label, { htmlFor: "blog-post-read-time", children: labels.readTime }), _jsx(Input, { id: "blog-post-read-time", type: "number", value: String(value.readTimeMinutes ?? 5), onChange: (event) => update({
26
- readTimeMinutes: parseInt(event.target.value, 10) || 5,
27
- }), disabled: isReadonly })] })] }), _jsx(Checkbox, { label: labels.featured, checked: value.isFeatured || false, onChange: (event) => update({ isFeatured: event.target.checked }), disabled: isReadonly }), isReadonly && coverImageUrl && (_jsx(Text, { size: "xs", variant: "secondary", children: coverImageUrl }))] }));
33
+ })) : isReadonly && renderContentReadonly ? (renderContentReadonly(value.content || "")) : (_jsxs(Stack, { gap: "xs", children: [_jsx(RichTextEditor, { value: normalizeRichTextHtml(value.content || ""), onChange: (content) => update({ content }), disabled: isReadonly, minHeightClassName: "min-h-[240px]", placeholder: "Write blog content" }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Rich text is supported for blog content." })] }))] }), renderBlogPostMediaFields({ value, update, isReadonly, labels, onUploadCover, onUploadContentImage, onUploadAdditionalImage, onAbort, coverImageUrl, contentImages, additionalImages }), renderBlogPostMetaFields({ value, update, isReadonly, categoryOptions, statusOptions, labels })] }));
28
34
  }
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import React from "react";
4
4
  import { Div, Heading, RichText, Row, Span, Text } from "../../../ui";
5
5
  import { useBlogPost } from "../hooks/useBlog";
@@ -15,6 +15,14 @@ const CATEGORY_BADGE = {
15
15
  updates: "bg-purple-100 text-purple-800",
16
16
  community: "bg-orange-100 text-orange-800",
17
17
  };
18
+ function renderBlogPostHeader(post, date, labels) {
19
+ return (_jsxs(Div, { className: "mb-8", children: [_jsxs(Row, { className: "gap-2 mb-4", children: [_jsx(Span, { className: `inline-block px-2 py-0.5 rounded-full text-xs font-medium capitalize ${CATEGORY_BADGE[post.category] ?? ""}`, children: post.category }), post.isFeatured && _jsx(Span, { className: "bg-yellow-100 text-yellow-800 px-2 py-0.5 rounded-full text-xs font-medium", children: labels?.featured ?? "Featured" })] }), _jsx(Heading, { level: 1, className: "text-3xl font-bold mb-4", children: post.title }), post.excerpt && _jsx(Text, { className: "text-lg text-neutral-500 mb-6", children: post.excerpt }), _jsxs(Row, { wrap: true, gap: "md", className: "text-sm text-neutral-400", children: [post.authorName && _jsxs(Span, { children: [labels?.author ?? "By", " ", _jsx(Span, { className: "font-medium text-neutral-700", children: post.authorName })] }), post.readTimeMinutes != null && _jsxs(Span, { children: [post.readTimeMinutes, " ", labels?.readTime ?? "min read"] }), date && _jsxs(Span, { children: [labels?.publishedOn ?? "Published", " ", date] }), post.views != null && _jsxs(Span, { children: [post.views, " ", labels?.viewsLabel ?? "views"] })] })] }));
20
+ }
21
+ function renderBlogPostRelated(related, labels, renderRelatedCard) {
22
+ if (related.length === 0)
23
+ return null;
24
+ return (_jsxs(Div, { children: [_jsx(Heading, { level: 2, className: "text-xl font-semibold mb-6", children: labels?.relatedTitle ?? "Related Posts" }), _jsx(Div, { className: "grid sm:grid-cols-3 gap-6", children: related.map((rel, i) => renderRelatedCard ? (_jsx(React.Fragment, { children: renderRelatedCard(rel, i) }, rel.id)) : (_jsx(BlogCard, { post: rel, href: String(ROUTES.BLOG.ARTICLE(rel.slug)) }, rel.id))) })] }));
25
+ }
18
26
  export function BlogPostView({ slug, initialData, labels = {}, renderImage, renderContent, renderBackButton, renderLoading, renderError, renderRelatedCard, renderAuthorBio, className = "", }) {
19
27
  const { post, related, isLoading, error } = useBlogPost(slug, {
20
28
  initialData,
@@ -37,5 +45,5 @@ export function BlogPostView({ slug, initialData, labels = {}, renderImage, rend
37
45
  })
38
46
  : "";
39
47
  const coverImageUrl = getMediaUrl(post.coverImage);
40
- return (_jsxs(Div, { className: `min-h-screen ${className}`, children: [coverImageUrl && (_jsxs(Div, { className: "relative h-72 md:h-96 overflow-hidden", children: [renderImage ? (renderImage(post)) : (_jsx(Div, { role: "img", "aria-label": post.title, className: "h-full w-full bg-cover bg-center", style: { backgroundImage: `url(${coverImageUrl})` } })), _jsx(Div, { className: "absolute inset-0 bg-gradient-to-t from-black/50 to-transparent" })] })), _jsxs(Div, { className: "max-w-3xl mx-auto px-4 py-12", children: [_jsxs(Div, { className: "mb-8", children: [_jsxs(Row, { className: "gap-2 mb-4", children: [_jsx(Span, { className: `inline-block px-2 py-0.5 rounded-full text-xs font-medium capitalize ${CATEGORY_BADGE[post.category] ?? ""}`, children: post.category }), post.isFeatured && (_jsx(Span, { className: "bg-yellow-100 text-yellow-800 px-2 py-0.5 rounded-full text-xs font-medium", children: labels.featured ?? "Featured" }))] }), _jsx(Heading, { level: 1, className: "text-3xl font-bold mb-4", children: post.title }), post.excerpt && (_jsx(Text, { className: "text-lg text-neutral-500 mb-6", children: post.excerpt })), _jsxs(Row, { wrap: true, gap: "md", className: "text-sm text-neutral-400", children: [post.authorName && (_jsxs(Span, { children: [labels.author ?? "By", " ", _jsx(Span, { className: "font-medium text-neutral-700", children: post.authorName })] })), post.readTimeMinutes != null && (_jsxs(Span, { children: [post.readTimeMinutes, " ", labels.readTime ?? "min read"] })), date && (_jsxs(Span, { children: [labels.publishedOn ?? "Published", " ", date] })), post.views != null && (_jsxs(Span, { children: [post.views, " ", labels.viewsLabel ?? "views"] }))] })] }), post.tags && post.tags.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", className: "mb-8", children: post.tags.map((tag) => (_jsxs(Span, { className: "inline-block px-3 py-1 rounded-full bg-neutral-100 text-neutral-600 text-xs font-medium", children: ["#", tag] }, tag))) })), renderAuthorBio && (_jsx(Div, { className: "mb-6", children: renderAuthorBio(post) })), _jsx(Div, { className: "bg-white dark:bg-slate-900 rounded-xl border border-neutral-200 dark:border-slate-700 p-8 mb-12", children: renderContent ? (renderContent(post)) : (_jsx(RichText, { html: normalizeRichTextHtml(post.content ?? ""), proseClass: "prose max-w-none dark:prose-invert", className: "text-neutral-800 dark:text-neutral-100" })) }), related.length > 0 && (_jsxs(Div, { children: [_jsx(Heading, { level: 2, className: "text-xl font-semibold mb-6", children: labels.relatedTitle ?? "Related Posts" }), _jsx(Div, { className: "grid sm:grid-cols-3 gap-6", children: related.map((rel, i) => renderRelatedCard ? (_jsx(React.Fragment, { children: renderRelatedCard(rel, i) }, rel.id)) : (_jsx(BlogCard, { post: rel, href: String(ROUTES.BLOG.ARTICLE(rel.slug)) }, rel.id))) })] })), renderBackButton && (_jsx(Div, { className: "mt-10 pt-8 border-t border-neutral-200", children: renderBackButton() }))] })] }));
48
+ return (_jsxs(Div, { className: `min-h-screen ${className}`, children: [coverImageUrl && (_jsxs(Div, { className: "relative h-72 md:h-96 overflow-hidden", children: [renderImage ? (renderImage(post)) : (_jsx(Div, { role: "img", "aria-label": post.title, className: "h-full w-full bg-cover bg-center", style: { backgroundImage: `url(${coverImageUrl})` } })), _jsx(Div, { className: "absolute inset-0 bg-gradient-to-t from-black/50 to-transparent" })] })), _jsxs(Div, { className: "max-w-3xl mx-auto px-4 py-12", children: [renderBlogPostHeader(post, date, labels), post.tags && post.tags.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", className: "mb-8", children: post.tags.map((tag) => (_jsxs(Span, { className: "inline-block px-3 py-1 rounded-full bg-neutral-100 text-neutral-600 text-xs font-medium", children: ["#", tag] }, tag))) })), renderAuthorBio && _jsx(Div, { className: "mb-6", children: renderAuthorBio(post) }), _jsx(Div, { className: "bg-white dark:bg-slate-900 rounded-xl border border-neutral-200 dark:border-slate-700 p-8 mb-12", children: renderContent ? renderContent(post) : (_jsx(RichText, { html: normalizeRichTextHtml(post.content ?? ""), proseClass: "prose max-w-none dark:prose-invert", className: "text-neutral-800 dark:text-neutral-100" })) }), renderBlogPostRelated(related, labels, renderRelatedCard), renderBackButton && _jsx(Div, { className: "mt-10 pt-8 border-t border-neutral-200", children: renderBackButton() })] })] }));
41
49
  }
@@ -31,14 +31,14 @@ export declare const blogPostSchema: z.ZodObject<{
31
31
  }, "strip", z.ZodTypeAny, {
32
32
  type: "video" | "image" | "file";
33
33
  url: string;
34
- source?: "external" | "upload" | "youtube" | undefined;
34
+ source?: "upload" | "youtube" | "external" | undefined;
35
35
  alt?: string | undefined;
36
36
  thumbnailUrl?: string | undefined;
37
37
  youtubeId?: string | undefined;
38
38
  }, {
39
39
  type: "video" | "image" | "file";
40
40
  url: string;
41
- source?: "external" | "upload" | "youtube" | undefined;
41
+ source?: "upload" | "youtube" | "external" | undefined;
42
42
  alt?: string | undefined;
43
43
  thumbnailUrl?: string | undefined;
44
44
  youtubeId?: string | undefined;
@@ -48,7 +48,7 @@ export declare const blogPostSchema: z.ZodObject<{
48
48
  }, string>]>>>, {
49
49
  type: "video" | "image" | "file";
50
50
  url: string;
51
- source?: "external" | "upload" | "youtube" | undefined;
51
+ source?: "upload" | "youtube" | "external" | undefined;
52
52
  alt?: string | undefined;
53
53
  thumbnailUrl?: string | undefined;
54
54
  youtubeId?: string | undefined;
@@ -58,7 +58,7 @@ export declare const blogPostSchema: z.ZodObject<{
58
58
  } | null, string | {
59
59
  type: "video" | "image" | "file";
60
60
  url: string;
61
- source?: "external" | "upload" | "youtube" | undefined;
61
+ source?: "upload" | "youtube" | "external" | undefined;
62
62
  alt?: string | undefined;
63
63
  thumbnailUrl?: string | undefined;
64
64
  youtubeId?: string | undefined;
@@ -73,14 +73,14 @@ export declare const blogPostSchema: z.ZodObject<{
73
73
  }, "strip", z.ZodTypeAny, {
74
74
  type: "video" | "image" | "file";
75
75
  url: string;
76
- source?: "external" | "upload" | "youtube" | undefined;
76
+ source?: "upload" | "youtube" | "external" | undefined;
77
77
  alt?: string | undefined;
78
78
  thumbnailUrl?: string | undefined;
79
79
  youtubeId?: string | undefined;
80
80
  }, {
81
81
  type: "video" | "image" | "file";
82
82
  url: string;
83
- source?: "external" | "upload" | "youtube" | undefined;
83
+ source?: "upload" | "youtube" | "external" | undefined;
84
84
  alt?: string | undefined;
85
85
  thumbnailUrl?: string | undefined;
86
86
  youtubeId?: string | undefined;
@@ -95,14 +95,14 @@ export declare const blogPostSchema: z.ZodObject<{
95
95
  }, "strip", z.ZodTypeAny, {
96
96
  type: "video" | "image" | "file";
97
97
  url: string;
98
- source?: "external" | "upload" | "youtube" | undefined;
98
+ source?: "upload" | "youtube" | "external" | undefined;
99
99
  alt?: string | undefined;
100
100
  thumbnailUrl?: string | undefined;
101
101
  youtubeId?: string | undefined;
102
102
  }, {
103
103
  type: "video" | "image" | "file";
104
104
  url: string;
105
- source?: "external" | "upload" | "youtube" | undefined;
105
+ source?: "upload" | "youtube" | "external" | undefined;
106
106
  alt?: string | undefined;
107
107
  thumbnailUrl?: string | undefined;
108
108
  youtubeId?: string | undefined;
@@ -130,7 +130,7 @@ export declare const blogPostSchema: z.ZodObject<{
130
130
  coverImage: {
131
131
  type: "video" | "image" | "file";
132
132
  url: string;
133
- source?: "external" | "upload" | "youtube" | undefined;
133
+ source?: "upload" | "youtube" | "external" | undefined;
134
134
  alt?: string | undefined;
135
135
  thumbnailUrl?: string | undefined;
136
136
  youtubeId?: string | undefined;
@@ -141,7 +141,7 @@ export declare const blogPostSchema: z.ZodObject<{
141
141
  contentImages: {
142
142
  type: "video" | "image" | "file";
143
143
  url: string;
144
- source?: "external" | "upload" | "youtube" | undefined;
144
+ source?: "upload" | "youtube" | "external" | undefined;
145
145
  alt?: string | undefined;
146
146
  thumbnailUrl?: string | undefined;
147
147
  youtubeId?: string | undefined;
@@ -149,7 +149,7 @@ export declare const blogPostSchema: z.ZodObject<{
149
149
  additionalImages: {
150
150
  type: "video" | "image" | "file";
151
151
  url: string;
152
- source?: "external" | "upload" | "youtube" | undefined;
152
+ source?: "upload" | "youtube" | "external" | undefined;
153
153
  alt?: string | undefined;
154
154
  thumbnailUrl?: string | undefined;
155
155
  youtubeId?: string | undefined;
@@ -183,7 +183,7 @@ export declare const blogPostSchema: z.ZodObject<{
183
183
  coverImage?: string | {
184
184
  type: "video" | "image" | "file";
185
185
  url: string;
186
- source?: "external" | "upload" | "youtube" | undefined;
186
+ source?: "upload" | "youtube" | "external" | undefined;
187
187
  alt?: string | undefined;
188
188
  thumbnailUrl?: string | undefined;
189
189
  youtubeId?: string | undefined;
@@ -196,7 +196,7 @@ export declare const blogPostSchema: z.ZodObject<{
196
196
  contentImages?: {
197
197
  type: "video" | "image" | "file";
198
198
  url: string;
199
- source?: "external" | "upload" | "youtube" | undefined;
199
+ source?: "upload" | "youtube" | "external" | undefined;
200
200
  alt?: string | undefined;
201
201
  thumbnailUrl?: string | undefined;
202
202
  youtubeId?: string | undefined;
@@ -204,7 +204,7 @@ export declare const blogPostSchema: z.ZodObject<{
204
204
  additionalImages?: {
205
205
  type: "video" | "image" | "file";
206
206
  url: string;
207
- source?: "external" | "upload" | "youtube" | undefined;
207
+ source?: "upload" | "youtube" | "external" | undefined;
208
208
  alt?: string | undefined;
209
209
  thumbnailUrl?: string | undefined;
210
210
  youtubeId?: string | undefined;
@@ -226,16 +226,16 @@ export declare const blogListParamsSchema: z.ZodObject<{
226
226
  sort?: string | undefined;
227
227
  perPage?: number | undefined;
228
228
  q?: string | undefined;
229
- page?: number | undefined;
230
229
  category?: "news" | "tips" | "guides" | "updates" | "community" | undefined;
231
- tags?: string | undefined;
232
230
  featured?: boolean | undefined;
231
+ tags?: string | undefined;
232
+ page?: number | undefined;
233
233
  }, {
234
234
  sort?: string | undefined;
235
235
  perPage?: number | undefined;
236
236
  q?: string | undefined;
237
- page?: number | undefined;
238
237
  category?: "news" | "tips" | "guides" | "updates" | "community" | undefined;
239
- tags?: string | undefined;
240
238
  featured?: boolean | undefined;
239
+ tags?: string | undefined;
240
+ page?: number | undefined;
241
241
  }>;
@@ -2,14 +2,15 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { Aside, Button, Div, Heading, Row, Span, Text } from "../../../ui";
3
3
  import { formatCurrency } from "../../../utils/number.formatter";
4
4
  import { THEME_CONSTANTS } from "../../../tokens";
5
+ import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
5
6
  export function CartItemRow({ item, onQtyChange, onRemove, href, isOutOfStock = false }) {
6
7
  return (_jsxs(Div, { className: `flex gap-4 rounded-xl border bg-white dark:bg-slate-900 p-4 transition-opacity ${isOutOfStock ? "border-neutral-200 dark:border-slate-700 opacity-60" : "border-neutral-200 dark:border-slate-700"}`, children: [_jsx(Div, { className: "h-20 w-20 flex-shrink-0 overflow-hidden rounded-lg bg-neutral-100 dark:bg-slate-800", children: item.meta.image && (_jsx(Div, { role: "img", "aria-label": item.meta.title, className: "h-full w-full bg-center bg-cover", style: { backgroundImage: `url(${item.meta.image})` } })) }), _jsxs(Div, { className: "flex flex-1 flex-col justify-between", children: [_jsxs(Div, { className: "flex items-start gap-1.5", children: [href ? (_jsx("a", { href: href, target: "_blank", rel: "noopener noreferrer", className: `font-medium text-neutral-900 dark:text-zinc-100 hover:underline underline-offset-2 ${THEME_CONSTANTS.utilities.textClamp2}`, children: item.meta.title })) : (_jsx(Text, { className: `font-medium text-neutral-900 dark:text-zinc-100 ${THEME_CONSTANTS.utilities.textClamp2}`, children: item.meta.title })), isOutOfStock && (_jsx(Span, { className: "flex-shrink-0 rounded bg-red-100 dark:bg-red-900/30 px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-[var(--appkit-color-error)]", children: "Out of Stock" }))] }), item.meta.attributes &&
7
8
  Object.keys(item.meta.attributes).length > 0 && (_jsx(Text, { className: "text-xs text-neutral-500 dark:text-zinc-400", children: Object.entries(item.meta.attributes)
8
9
  .map(([k, v]) => `${k}: ${v}`)
9
- .join(", ") })), _jsxs(Row, { justify: "between", children: [_jsx(Text, { className: "font-semibold text-neutral-900 dark:text-zinc-100", children: formatCurrency(item.meta.price * item.quantity, item.meta.currency) }), onQtyChange && !isOutOfStock && (_jsxs(Row, { className: "gap-2", children: [_jsx(Button, { onClick: () => onQtyChange(item.id, item.quantity - 1), disabled: item.quantity <= 1, variant: "outline", size: "sm", className: "flex h-7 w-7 items-center justify-center rounded-full border border-neutral-200 dark:border-slate-600 text-sm disabled:opacity-40", children: "\u2212" }), _jsx(Span, { className: "min-w-[1.5rem] text-center text-sm", children: item.quantity }), _jsx(Button, { onClick: () => onQtyChange(item.id, item.quantity + 1), variant: "outline", size: "sm", className: "flex h-7 w-7 items-center justify-center rounded-full border border-neutral-200 dark:border-slate-600 text-sm", children: "+" })] })), isOutOfStock && (_jsxs(Span, { className: "text-xs text-neutral-400 dark:text-zinc-500", children: ["Qty: ", item.quantity] }))] })] }), onRemove && (_jsx(Button, { onClick: () => onRemove(item.id), variant: "ghost", size: "sm", "aria-label": "Remove from cart", className: "self-start text-neutral-400 dark:text-zinc-500 transition hover:text-red-500", children: "\u2715" }))] }));
10
+ .join(", ") })), _jsxs(Row, { justify: "between", children: [_jsx(Text, { className: "font-semibold text-neutral-900 dark:text-zinc-100", children: formatCurrency(item.meta.price * item.quantity, item.meta.currency) }), onQtyChange && !isOutOfStock && (_jsxs(Row, { className: "gap-2", children: [_jsx(Button, { onClick: () => onQtyChange(item.id, item.quantity - 1), disabled: item.quantity <= 1, variant: "outline", size: "sm", className: "flex h-7 w-7 items-center justify-center rounded-full border border-neutral-200 dark:border-slate-600 text-sm disabled:opacity-40", children: "\u2212" }), _jsx(Span, { className: "min-w-[1.5rem] text-center text-sm", children: item.quantity }), _jsx(Button, { onClick: () => onQtyChange(item.id, item.quantity + 1), variant: "outline", size: "sm", className: "flex h-7 w-7 items-center justify-center rounded-full border border-neutral-200 dark:border-slate-600 text-sm", children: "+" })] })), isOutOfStock && (_jsxs(Span, { className: "text-xs text-neutral-400 dark:text-zinc-500", children: ["Qty: ", item.quantity] }))] })] }), onRemove && (_jsx(Button, { onClick: () => onRemove(item.id), variant: "ghost", size: "sm", "aria-label": ACTIONS.CART["remove-item"].ariaLabel, className: "self-start text-neutral-400 dark:text-zinc-500 transition hover:text-red-500", children: "\u2715" }))] }));
10
11
  }
11
12
  export function CartDrawer({ isOpen, onClose, items, subtotal = 0, currency, isLoading, onQtyChange, onRemove, onCheckout, labels = {}, }) {
12
13
  if (!isOpen)
13
14
  return null;
14
- return (_jsxs(_Fragment, { children: [_jsx(Div, { role: "presentation", className: "fixed inset-0 z-40 bg-black/40", onClick: onClose }), _jsxs(Aside, { className: "fixed inset-y-0 right-0 z-50 flex w-full max-w-sm flex-col bg-white dark:bg-slate-900 shadow-xl", children: [_jsxs(Row, { justify: "between", className: "border-b border-neutral-200 dark:border-slate-700 p-4", children: [_jsx(Heading, { level: 2, className: "text-lg font-semibold", children: labels.title ?? "Cart" }), _jsx(Button, { onClick: onClose, variant: "ghost", size: "sm", "aria-label": "Close cart", className: "text-neutral-500 dark:text-zinc-400 hover:text-neutral-900 dark:hover:text-zinc-100", children: "\u2715" })] }), _jsx(Div, { className: "flex-1 overflow-y-auto p-4 space-y-3", children: isLoading ? (_jsx(Div, { className: "flex justify-center py-12", children: _jsx(Div, { className: "h-8 w-8 animate-spin rounded-full border-2 border-neutral-300 dark:border-slate-600 border-t-neutral-800 dark:border-t-zinc-200" }) })) : items.length === 0 ? (_jsx(Text, { className: "py-12 text-center text-sm text-neutral-500 dark:text-zinc-400", children: labels.empty ?? "Your cart is empty" })) : (items.map((item) => (_jsx(CartItemRow, { item: item, onQtyChange: onQtyChange, onRemove: onRemove }, item.id)))) }), items.length > 0 && (_jsxs(Div, { className: "border-t border-neutral-200 dark:border-slate-700 p-4 space-y-4", children: [_jsxs(Row, { justify: "between", className: "text-sm", children: [_jsx(Span, { className: "text-neutral-600 dark:text-zinc-300", children: labels.subtotal ?? "Subtotal" }), _jsx(Span, { className: "font-semibold", children: formatCurrency(subtotal, currency) })] }), onCheckout && (_jsx(Button, { onClick: onCheckout, variant: "primary", className: "w-full rounded-xl bg-neutral-900 py-3 text-sm font-semibold text-white transition hover:bg-neutral-800", children: labels.checkout ?? "Proceed to Checkout" }))] }))] })] }));
15
+ return (_jsxs(_Fragment, { children: [_jsx(Div, { role: "presentation", className: "fixed inset-0 z-40 bg-black/40", onClick: onClose }), _jsxs(Aside, { className: "fixed inset-y-0 right-0 z-50 flex w-full max-w-sm flex-col bg-white dark:bg-slate-900 shadow-xl", children: [_jsxs(Row, { justify: "between", className: "border-b border-neutral-200 dark:border-slate-700 p-4", children: [_jsx(Heading, { level: 2, className: "text-lg font-semibold", children: labels.title ?? "Cart" }), _jsx(Button, { onClick: onClose, variant: "ghost", size: "sm", "aria-label": "Close cart", className: "text-neutral-500 dark:text-zinc-400 hover:text-neutral-900 dark:hover:text-zinc-100", children: "\u2715" })] }), _jsx(Div, { className: "flex-1 overflow-y-auto p-4 space-y-3", children: isLoading ? (_jsx(Div, { className: "flex justify-center py-12", children: _jsx(Div, { className: "h-8 w-8 animate-spin rounded-full border-2 border-neutral-300 dark:border-slate-600 border-t-neutral-800 dark:border-t-zinc-200" }) })) : items.length === 0 ? (_jsx(Text, { className: "py-12 text-center text-sm text-neutral-500 dark:text-zinc-400", children: labels.empty ?? "Your cart is empty" })) : (items.map((item) => (_jsx(CartItemRow, { item: item, onQtyChange: onQtyChange, onRemove: onRemove }, item.id)))) }), items.length > 0 && (_jsxs(Div, { className: "border-t border-neutral-200 dark:border-slate-700 p-4 space-y-4", children: [_jsxs(Row, { justify: "between", className: "text-sm", children: [_jsx(Span, { className: "text-neutral-600 dark:text-zinc-300", children: labels.subtotal ?? "Subtotal" }), _jsx(Span, { className: "font-semibold", children: formatCurrency(subtotal, currency) })] }), onCheckout && (_jsx(Button, { onClick: onCheckout, variant: "primary", className: "w-full rounded-xl bg-neutral-900 py-3 text-sm font-semibold text-white transition hover:bg-neutral-800", children: labels.checkout ?? ACTIONS.CART["checkout"].label }))] }))] })] }));
15
16
  }
@@ -1,7 +1,8 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Div, Heading } from "../../../ui";
3
+ import { AdSlot } from "../../homepage/components/AdSlot";
3
4
  export function CartView({ labels = {}, renderItems, renderGroups, groups = [], renderSummary, renderPromoCode, renderCheckoutButton, renderEmpty, isEmpty = false, isLoading = false, className = "", }) {
4
5
  if (isEmpty && renderEmpty)
5
6
  return _jsx(_Fragment, { children: renderEmpty() });
6
- return (_jsxs(Div, { className: className, children: [labels.title && (_jsx(Heading, { level: 1, className: "text-2xl font-bold mb-6", children: labels.title })), _jsxs(Div, { className: "flex flex-col gap-6 lg:flex-row lg:gap-8", children: [_jsxs(Div, { className: "flex-1", children: [renderGroups ? renderGroups(groups, isLoading) : renderItems(isLoading), !renderGroups && renderPromoCode?.(), renderGroups && renderPromoCode?.()] }), _jsxs(Div, { className: "w-full lg:w-80", children: [renderSummary?.(), renderCheckoutButton?.(() => { }, isLoading)] })] })] }));
7
+ return (_jsxs(Div, { className: className, children: [labels.title && (_jsx(Heading, { level: 1, className: "text-2xl font-bold mb-6", children: labels.title })), _jsxs(Div, { className: "flex flex-col gap-6 lg:flex-row lg:gap-8", children: [_jsxs(Div, { className: "flex-1", children: [renderGroups ? renderGroups(groups, isLoading) : renderItems(isLoading), !renderGroups && renderPromoCode?.(), renderGroups && renderPromoCode?.(), _jsx(AdSlot, { id: "cart-upsell", className: "mt-6" })] }), _jsxs(Div, { className: "w-full lg:w-80", children: [renderSummary?.(), renderCheckoutButton?.(() => { }, isLoading)] })] })] }));
7
8
  }
@@ -2,6 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import React from "react";
4
4
  import { Div, Heading } from "../../../ui";
5
+ import { AdSlot } from "../../homepage/components/AdSlot";
5
6
  export function CheckoutView({ labels = {}, renderStep, renderStepIndicator, renderOrderSummary, totalSteps = 3, initialStep = 0, activeStep, onStepChange, className = "", }) {
6
7
  const [internalStep, setInternalStep] = React.useState(initialStep);
7
8
  const step = activeStep ?? internalStep;
@@ -14,5 +15,5 @@ export function CheckoutView({ labels = {}, renderStep, renderStepIndicator, ren
14
15
  }
15
16
  onStepChange?.(nextStep);
16
17
  }, [activeStep, onStepChange, step]);
17
- return (_jsxs(Div, { className: className, children: [labels.title && (_jsx(Heading, { level: 1, className: "text-2xl font-bold mb-6", children: labels.title })), renderStepIndicator?.(step, totalSteps, setStep), _jsxs(Div, { className: "flex flex-col gap-6 lg:flex-row lg:gap-8", children: [_jsx(Div, { className: "flex-1", children: renderStep(step, setStep) }), renderOrderSummary && (_jsx(Div, { className: "w-full lg:w-80", children: renderOrderSummary() }))] })] }));
18
+ return (_jsxs(Div, { className: className, children: [labels.title && (_jsx(Heading, { level: 1, className: "text-2xl font-bold mb-6", children: labels.title })), renderStepIndicator?.(step, totalSteps, setStep), _jsxs(Div, { className: "flex flex-col gap-6 lg:flex-row lg:gap-8", children: [_jsxs(Div, { className: "flex-1", children: [renderStep(step, setStep), _jsx(AdSlot, { id: "checkout-upsell", className: "mt-6" })] }), renderOrderSummary && (_jsx(Div, { className: "w-full lg:w-80", children: renderOrderSummary() }))] })] }));
18
19
  }
@@ -1,5 +1,6 @@
1
1
  import { randomUUID } from "crypto";
2
2
  import { DatabaseError, NotFoundError } from "../../../errors";
3
+ const ERR_CART_ITEM_NOT_FOUND = "Cart item not found";
3
4
  import { BaseRepository, prepareForFirestore, } from "../../../providers/db-firebase";
4
5
  import { decryptPii } from "../../../security";
5
6
  import { CART_COLLECTION, } from "../schemas";
@@ -120,7 +121,7 @@ export class CartRepository extends BaseRepository {
120
121
  throw new NotFoundError("Cart not found");
121
122
  const itemIndex = cart.items.findIndex((item) => item.itemId === itemId);
122
123
  if (itemIndex < 0)
123
- throw new NotFoundError("Cart item not found");
124
+ throw new NotFoundError(ERR_CART_ITEM_NOT_FOUND);
124
125
  const items = [...cart.items];
125
126
  items[itemIndex] = {
126
127
  ...items[itemIndex],
@@ -152,7 +153,7 @@ export class CartRepository extends BaseRepository {
152
153
  throw new NotFoundError("Cart not found");
153
154
  const itemExists = cart.items.some((item) => item.itemId === itemId);
154
155
  if (!itemExists)
155
- throw new NotFoundError("Cart item not found");
156
+ throw new NotFoundError(ERR_CART_ITEM_NOT_FOUND);
156
157
  const items = cart.items.filter((item) => item.itemId !== itemId);
157
158
  const updatedCart = {
158
159
  ...cart,
@@ -223,7 +224,7 @@ export class CartRepository extends BaseRepository {
223
224
  throw new NotFoundError("Cart not found");
224
225
  const itemIndex = cart.items.findIndex((item) => item.itemId === itemId);
225
226
  if (itemIndex < 0)
226
- throw new NotFoundError("Cart item not found");
227
+ throw new NotFoundError(ERR_CART_ITEM_NOT_FOUND);
227
228
  const items = [...cart.items];
228
229
  items[itemIndex] = {
229
230
  ...items[itemIndex],
@@ -20,7 +20,7 @@ export interface CartOp {
20
20
  export interface WishlistOp {
21
21
  op: WishlistOpKind;
22
22
  itemId: string;
23
- type: "product" | "auction" | "preorder" | "category" | "store";
23
+ type: "product" | "auction" | "preorder" | "category" | "store" | "classified" | "digital-code" | "live";
24
24
  title?: string;
25
25
  image?: string;
26
26
  ts: number;
@@ -12,6 +12,7 @@ import { NextResponse } from "next/server.js";
12
12
  import { z } from "zod";
13
13
  import { getProviders } from "../../../../contracts";
14
14
  import { createRouteHandler } from "../../../../next";
15
+ const ERR_CATEGORY_NOT_FOUND = "Category not found";
15
16
  // ---- GET /api/categories/[id] ------------------------------------------------
16
17
  export async function GET(_request, context) {
17
18
  try {
@@ -23,7 +24,7 @@ export async function GET(_request, context) {
23
24
  const repo = db.getRepository("categories");
24
25
  const category = await repo.findById(id);
25
26
  if (!category) {
26
- return NextResponse.json({ success: false, error: "Category not found" }, { status: 404 });
27
+ return NextResponse.json({ success: false, error: ERR_CATEGORY_NOT_FOUND }, { status: 404 });
27
28
  }
28
29
  return NextResponse.json({ success: true, data: category });
29
30
  }
@@ -65,7 +66,7 @@ export const categoryItemPATCH = createRouteHandler({
65
66
  const repo = db.getRepository("categories");
66
67
  const category = await repo.findById(id);
67
68
  if (!category)
68
- return NextResponse.json({ success: false, error: "Category not found" }, { status: 404 });
69
+ return NextResponse.json({ success: false, error: ERR_CATEGORY_NOT_FOUND }, { status: 404 });
69
70
  const updated = await repo.update(id, {
70
71
  ...body,
71
72
  updatedAt: new Date().toISOString(),
@@ -87,7 +88,7 @@ export const categoryItemDELETE = createRouteHandler({
87
88
  const repo = db.getRepository("categories");
88
89
  const category = await repo.findById(id);
89
90
  if (!category)
90
- return NextResponse.json({ success: false, error: "Category not found" }, { status: 404 });
91
+ return NextResponse.json({ success: false, error: ERR_CATEGORY_NOT_FOUND }, { status: 404 });
91
92
  // Guard: refuse to delete if it has children
92
93
  if (category.childrenIds?.length) {
93
94
  return NextResponse.json({ success: false, error: "Cannot delete a category that has children" }, { status: 409 });
@@ -16,6 +16,7 @@ import { NextResponse } from "next/server.js";
16
16
  import { z } from "zod";
17
17
  import { getProviders } from "../../../contracts";
18
18
  import { createRouteHandler } from "../../../next";
19
+ const CACHE_CONTROL_PUBLIC = "public, max-age=3600, s-maxage=3600, stale-while-revalidate=86400";
19
20
  function buildTreeFromFlat(items, rootId) {
20
21
  const byId = new Map(items.map((i) => [i.id, i]));
21
22
  // Roots: tier === 0 or no parentIds
@@ -130,7 +131,7 @@ export async function GET(request) {
130
131
  });
131
132
  const items = result.data.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
132
133
  const res = NextResponse.json({ success: true, data: items });
133
- res.headers.set("Cache-Control", "public, max-age=300, s-maxage=600, stale-while-revalidate=120");
134
+ res.headers.set("Cache-Control", CACHE_CONTROL_PUBLIC);
134
135
  return res;
135
136
  }
136
137
  // -- Tree mode (default or explicit ?tree=true) ----------------------------
@@ -143,7 +144,7 @@ export async function GET(request) {
143
144
  if (tree === "true" || !flat) {
144
145
  const treeNodes = buildTreeFromFlat(allResult.data, rootId);
145
146
  const res = NextResponse.json({ success: true, data: treeNodes });
146
- res.headers.set("Cache-Control", "public, max-age=300, s-maxage=600, stale-while-revalidate=120");
147
+ res.headers.set("Cache-Control", CACHE_CONTROL_PUBLIC);
147
148
  return res;
148
149
  }
149
150
  // Explicit ?flat=true on full set (non-filtered path, shouldn't reach here
@@ -152,7 +153,7 @@ export async function GET(request) {
152
153
  success: true,
153
154
  data: allResult.data.sort((a, b) => (a.order ?? 0) - (b.order ?? 0)),
154
155
  });
155
- res.headers.set("Cache-Control", "public, max-age=300, s-maxage=600, stale-while-revalidate=120");
156
+ res.headers.set("Cache-Control", CACHE_CONTROL_PUBLIC);
156
157
  return res;
157
158
  }
158
159
  catch (error) {
@@ -2,7 +2,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
2
2
  import Link from "next/link";
3
3
  import { categoriesRepository, productRepository, } from "../../../repositories";
4
4
  import { ROUTES } from "../../../next";
5
- import { Container, Main, Section } from "../../../ui";
5
+ import { Container, Heading, Main, Section, Text } from "../../../ui";
6
6
  import { BrandDetailTabs } from "./BrandDetailTabs";
7
7
  export async function BrandDetailPageView({ slug, initialBrand }) {
8
8
  const brand = (initialBrand ?? (await categoriesRepository
@@ -81,5 +81,5 @@ export async function BrandDetailPageView({ slug, initialBrand }) {
81
81
  counts.preOrders +
82
82
  counts.prizeDraws +
83
83
  counts.bundles;
84
- return (_jsxs(Main, { children: [_jsxs("section", { className: `relative overflow-hidden ${hasCover ? "min-h-[220px] md:min-h-[280px]" : "bg-zinc-50 dark:bg-zinc-900"}`, children: [hasCover && (_jsxs(_Fragment, { children: [_jsx("div", { className: "absolute inset-0 bg-center bg-cover", style: { backgroundImage: `url(${coverImage})` } }), _jsx("div", { className: "absolute inset-0 bg-black/55" })] })), !hasCover && (_jsx("div", { className: "absolute inset-0 opacity-10", style: { backgroundColor: brandColor } })), _jsxs("div", { className: `relative z-10 max-w-7xl mx-auto px-4 ${hasCover ? "py-12" : "py-8"}`, children: [_jsxs("nav", { className: "flex items-center gap-1.5 text-sm mb-4", "aria-label": "Breadcrumb", children: [_jsx(Link, { href: String(ROUTES.HOME), className: hasCover ? "text-white/70 hover:text-white transition-colors" : "text-zinc-500 hover:text-primary-600 transition-colors", children: "Home" }), _jsx("span", { className: hasCover ? "text-white/40" : "text-zinc-400", children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.BRANDS ?? "/brands"), className: hasCover ? "text-white/70 hover:text-white transition-colors" : "text-zinc-500 hover:text-primary-600 transition-colors", children: "Brands" }), _jsx("span", { className: hasCover ? "text-white/40" : "text-zinc-400", children: "/" }), _jsx("span", { className: hasCover ? "text-white font-medium" : "text-zinc-900 dark:text-zinc-100 font-medium", children: brand?.name ?? slug })] }), _jsxs("div", { className: "flex items-center gap-4 mb-3", children: [brand?.display?.icon && (_jsx("span", { className: `text-5xl leading-none ${!hasCover ? "" : ""}`, children: brand.display.icon })), _jsxs("div", { children: [_jsx("h1", { className: `text-3xl md:text-4xl font-bold ${hasCover ? "text-white" : "text-zinc-900 dark:text-zinc-50"}`, children: brand?.name ?? slug }), brand?.description && typeof brand.description === "string" && !brand.description.startsWith("{") && (_jsx("p", { className: `text-base max-w-2xl mt-1 ${hasCover ? "text-white/80" : "text-zinc-600 dark:text-zinc-400"}`, children: brand.description }))] })] }), _jsxs("div", { className: "flex flex-wrap gap-2 mt-3", children: [counts.products > 0 && (_jsxs("span", { className: `inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full ${hasCover ? "bg-white/20 text-white backdrop-blur-sm" : "bg-primary/10 text-primary-700 dark:text-primary-400"}`, children: [counts.products.toLocaleString(), " ", counts.products === 1 ? "product" : "products"] })), counts.auctions > 0 && (_jsxs("span", { className: `inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full ${hasCover ? "bg-white/20 text-white backdrop-blur-sm" : "bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400"}`, children: [counts.auctions.toLocaleString(), " ", counts.auctions === 1 ? "auction" : "auctions"] })), counts.preOrders > 0 && (_jsxs("span", { className: `inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full ${hasCover ? "bg-white/20 text-white backdrop-blur-sm" : "bg-violet-100 text-violet-700 dark:bg-violet-900/30 dark:text-violet-400"}`, children: [counts.preOrders.toLocaleString(), " ", counts.preOrders === 1 ? "pre-order" : "pre-orders"] })), totalItems === 0 && (_jsx("span", { className: `text-sm ${hasCover ? "text-white/60" : "text-zinc-400"}`, children: "No items listed yet" }))] })] })] }), _jsx(Section, { className: "py-6", children: _jsx(Container, { size: "xl", children: brandName ? (_jsx(BrandDetailTabs, { brandName: brandName, initialProductsData: productsResult ?? undefined, initialBundles: brandBundles, counts: counts })) : (_jsx("p", { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: "Brand not found." })) }) })] }));
84
+ return (_jsxs(Main, { children: [_jsxs(Section, { className: `relative overflow-hidden ${hasCover ? "min-h-[220px] md:min-h-[280px]" : "bg-zinc-50 dark:bg-zinc-900"}`, children: [hasCover && (_jsxs(_Fragment, { children: [_jsx("div", { className: "absolute inset-0 bg-center bg-cover", style: { backgroundImage: `url(${coverImage})` } }), _jsx("div", { className: "absolute inset-0 bg-black/55" })] })), !hasCover && (_jsx("div", { className: "absolute inset-0 opacity-10", style: { backgroundColor: brandColor } })), _jsxs("div", { className: `relative z-10 max-w-7xl mx-auto px-4 ${hasCover ? "py-12" : "py-8"}`, children: [_jsxs("nav", { className: "flex items-center gap-1.5 text-sm mb-4", "aria-label": "Breadcrumb", children: [_jsx(Link, { href: String(ROUTES.HOME), className: hasCover ? "text-white/70 hover:text-white transition-colors" : "text-zinc-500 hover:text-primary-600 transition-colors", children: "Home" }), _jsx("span", { className: hasCover ? "text-white/40" : "text-zinc-400", children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.BRANDS ?? "/brands"), className: hasCover ? "text-white/70 hover:text-white transition-colors" : "text-zinc-500 hover:text-primary-600 transition-colors", children: "Brands" }), _jsx("span", { className: hasCover ? "text-white/40" : "text-zinc-400", children: "/" }), _jsx("span", { className: hasCover ? "text-white font-medium" : "text-zinc-900 dark:text-zinc-100 font-medium", children: brand?.name ?? slug })] }), _jsxs("div", { className: "flex items-center gap-4 mb-3", children: [brand?.display?.icon && (_jsx("span", { className: `text-5xl leading-none ${!hasCover ? "" : ""}`, children: brand.display.icon })), _jsxs(_Fragment, { children: [_jsx(Heading, { level: 1, className: `text-3xl md:text-4xl font-bold ${hasCover ? "text-white" : "text-zinc-900 dark:text-zinc-50"}`, children: brand?.name ?? slug }), brand?.description && typeof brand.description === "string" && !brand.description.startsWith("{") && (_jsx(Text, { className: `text-base max-w-2xl mt-1 ${hasCover ? "text-white/80" : "text-zinc-600 dark:text-zinc-400"}`, children: brand.description }))] })] }), _jsxs("div", { className: "flex flex-wrap gap-2 mt-3", children: [counts.products > 0 && (_jsxs("span", { className: `inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full ${hasCover ? "bg-white/20 text-white backdrop-blur-sm" : "bg-primary/10 text-primary-700 dark:text-primary-400"}`, children: [counts.products.toLocaleString(), " ", counts.products === 1 ? "product" : "products"] })), counts.auctions > 0 && (_jsxs("span", { className: `inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full ${hasCover ? "bg-white/20 text-white backdrop-blur-sm" : "bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400"}`, children: [counts.auctions.toLocaleString(), " ", counts.auctions === 1 ? "auction" : "auctions"] })), counts.preOrders > 0 && (_jsxs("span", { className: `inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full ${hasCover ? "bg-white/20 text-white backdrop-blur-sm" : "bg-violet-100 text-violet-700 dark:bg-violet-900/30 dark:text-violet-400"}`, children: [counts.preOrders.toLocaleString(), " ", counts.preOrders === 1 ? "pre-order" : "pre-orders"] })), totalItems === 0 && (_jsx("span", { className: `text-sm ${hasCover ? "text-white/60" : "text-zinc-400"}`, children: "No items listed yet" }))] })] })] }), _jsx(Section, { className: "py-6", children: _jsx(Container, { size: "xl", children: brandName ? (_jsx(BrandDetailTabs, { brandName: brandName, initialProductsData: productsResult ?? undefined, initialBundles: brandBundles, counts: counts })) : (_jsx(Text, { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: "Brand not found." })) }) })] }));
85
85
  }