@mohasinac/appkit 4.59.0 → 4.60.0

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 (531) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +62 -5
  3. package/dist/_internal/client/features/maintenance/views/MaintenanceDashboardView.js +2 -2
  4. package/dist/_internal/server/features/brands/actions.js +78 -4
  5. package/dist/_internal/server/features/checkout/actions.d.ts +36 -13
  6. package/dist/_internal/server/features/checkout/actions.js +668 -183
  7. package/dist/_internal/server/features/checkout/supplier-identity.js +18 -1
  8. package/dist/_internal/server/features/gateway-events/index.d.ts +10 -0
  9. package/dist/_internal/server/features/gateway-events/index.js +10 -0
  10. package/dist/_internal/server/features/gateway-events/ingest.d.ts +127 -0
  11. package/dist/_internal/server/features/gateway-events/ingest.js +188 -0
  12. package/dist/_internal/server/features/gateway-events/redact.d.ts +66 -0
  13. package/dist/_internal/server/features/gateway-events/redact.js +151 -0
  14. package/dist/_internal/server/features/grievance/actions.d.ts +63 -0
  15. package/dist/_internal/server/features/grievance/actions.js +173 -0
  16. package/dist/_internal/server/features/grievance/index.d.ts +8 -0
  17. package/dist/_internal/server/features/grievance/index.js +8 -0
  18. package/dist/_internal/server/features/grouped/data.js +28 -3
  19. package/dist/_internal/server/features/lottery/actions.js +99 -4
  20. package/dist/_internal/server/features/order-completion/actions.d.ts +92 -0
  21. package/dist/_internal/server/features/order-completion/actions.js +336 -0
  22. package/dist/_internal/server/features/order-completion/index.d.ts +7 -0
  23. package/dist/_internal/server/features/order-completion/index.js +7 -0
  24. package/dist/_internal/server/features/orders/actions.d.ts +13 -0
  25. package/dist/_internal/server/features/orders/actions.js +56 -2
  26. package/dist/_internal/server/features/orders/adapters.js +26 -0
  27. package/dist/_internal/server/features/orders/cancellation-refund.d.ts +116 -0
  28. package/dist/_internal/server/features/orders/cancellation-refund.js +466 -0
  29. package/dist/_internal/server/features/orders/index.d.ts +2 -1
  30. package/dist/_internal/server/features/orders/index.js +1 -1
  31. package/dist/_internal/server/features/orders/service.d.ts +60 -0
  32. package/dist/_internal/server/features/orders/service.js +74 -0
  33. package/dist/_internal/server/features/payment-cases/disputes.d.ts +76 -0
  34. package/dist/_internal/server/features/payment-cases/disputes.js +241 -0
  35. package/dist/_internal/server/features/payment-cases/index.d.ts +9 -0
  36. package/dist/_internal/server/features/payment-cases/index.js +9 -0
  37. package/dist/_internal/server/features/payouts/actions.d.ts +28 -3
  38. package/dist/_internal/server/features/payouts/actions.js +84 -10
  39. package/dist/_internal/server/features/points/adjust.d.ts +61 -0
  40. package/dist/_internal/server/features/points/adjust.js +121 -0
  41. package/dist/_internal/server/features/points/award.d.ts +65 -0
  42. package/dist/_internal/server/features/points/award.js +145 -0
  43. package/dist/_internal/server/features/price-index/market.d.ts +33 -0
  44. package/dist/_internal/server/features/price-index/market.js +54 -1
  45. package/dist/_internal/server/features/products/data.js +40 -22
  46. package/dist/_internal/server/features/protection-claims/actions.d.ts +72 -0
  47. package/dist/_internal/server/features/protection-claims/actions.js +228 -0
  48. package/dist/_internal/server/features/protection-claims/index.d.ts +8 -0
  49. package/dist/_internal/server/features/protection-claims/index.js +8 -0
  50. package/dist/_internal/server/features/refunds/actions.d.ts +20 -0
  51. package/dist/_internal/server/features/refunds/actions.js +259 -17
  52. package/dist/_internal/server/features/refunds/capacity.d.ts +29 -0
  53. package/dist/_internal/server/features/refunds/capacity.js +37 -0
  54. package/dist/_internal/server/features/reviews/actions.js +3 -2
  55. package/dist/_internal/server/features/search/index-build/sources.js +20 -1
  56. package/dist/_internal/server/features/shipping/reconcile.d.ts +10 -1
  57. package/dist/_internal/server/features/shipping/reconcile.js +34 -3
  58. package/dist/_internal/server/features/shipping/reimbursement.d.ts +117 -0
  59. package/dist/_internal/server/features/shipping/reimbursement.js +223 -0
  60. package/dist/_internal/server/features/stores/tabs.d.ts +19 -4
  61. package/dist/_internal/server/features/stores/tabs.js +24 -4
  62. package/dist/_internal/server/functions/https.d.ts +31 -1
  63. package/dist/_internal/server/functions/https.js +52 -1
  64. package/dist/_internal/server/functions/scheduled.d.ts +72 -1
  65. package/dist/_internal/server/functions/scheduled.js +124 -1
  66. package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +62 -16
  67. package/dist/_internal/server/jobs/core/boxRollupReconcile.d.ts +46 -0
  68. package/dist/_internal/server/jobs/core/boxRollupReconcile.js +142 -0
  69. package/dist/_internal/server/jobs/core/dailyDataCleanup.js +149 -1
  70. package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +14 -0
  71. package/dist/_internal/server/jobs/core/dailyStatusDigest.js +79 -1
  72. package/dist/_internal/server/jobs/core/index.d.ts +2 -0
  73. package/dist/_internal/server/jobs/core/index.js +2 -0
  74. package/dist/_internal/server/jobs/core/marketPriceRollup.d.ts +64 -0
  75. package/dist/_internal/server/jobs/core/marketPriceRollup.js +153 -0
  76. package/dist/_internal/server/jobs/core/obligationSweep.d.ts +36 -0
  77. package/dist/_internal/server/jobs/core/obligationSweep.js +503 -0
  78. package/dist/_internal/server/jobs/core/paymentReconcile.d.ts +79 -0
  79. package/dist/_internal/server/jobs/core/paymentReconcile.js +614 -0
  80. package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +34 -0
  81. package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +35 -4
  82. package/dist/_internal/server/jobs/handlers/boxRollupReconcile.d.ts +2 -0
  83. package/dist/_internal/server/jobs/handlers/boxRollupReconcile.js +15 -0
  84. package/dist/_internal/server/jobs/handlers/countersReconcileNow.d.ts +65 -0
  85. package/dist/_internal/server/jobs/handlers/countersReconcileNow.js +89 -0
  86. package/dist/_internal/server/jobs/handlers/index.d.ts +5 -0
  87. package/dist/_internal/server/jobs/handlers/index.js +5 -0
  88. package/dist/_internal/server/jobs/handlers/marketPriceRollup.d.ts +2 -0
  89. package/dist/_internal/server/jobs/handlers/marketPriceRollup.js +2 -0
  90. package/dist/_internal/server/jobs/handlers/obligationSweep.d.ts +2 -0
  91. package/dist/_internal/server/jobs/handlers/obligationSweep.js +15 -0
  92. package/dist/_internal/server/jobs/handlers/onShipmentAllocationSync.js +30 -1
  93. package/dist/_internal/server/jobs/handlers/paymentReconcile.d.ts +2 -0
  94. package/dist/_internal/server/jobs/handlers/paymentReconcile.js +6 -0
  95. package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
  96. package/dist/_internal/shared/actions/action-registry.js +71 -0
  97. package/dist/_internal/shared/checkout/coupon-discount.d.ts +73 -0
  98. package/dist/_internal/shared/checkout/coupon-discount.js +103 -0
  99. package/dist/_internal/shared/checkout/lanes.d.ts +42 -0
  100. package/dist/_internal/shared/checkout/lanes.js +46 -0
  101. package/dist/_internal/shared/checkout/order-math.d.ts +149 -1
  102. package/dist/_internal/shared/checkout/order-math.js +251 -3
  103. package/dist/_internal/shared/checkout/refundable-base.d.ts +116 -0
  104. package/dist/_internal/shared/checkout/refundable-base.js +122 -0
  105. package/dist/_internal/shared/features/auctions/config.d.ts +14 -1
  106. package/dist/_internal/shared/features/auctions/config.js +30 -1
  107. package/dist/_internal/shared/features/brands/schema.d.ts +42 -0
  108. package/dist/_internal/shared/features/brands/schema.js +18 -0
  109. package/dist/_internal/shared/features/orders/refund-copy.d.ts +22 -0
  110. package/dist/_internal/shared/features/orders/refund-copy.js +34 -0
  111. package/dist/_internal/shared/features/print/label-profiles.d.ts +198 -0
  112. package/dist/_internal/shared/features/print/label-profiles.js +350 -0
  113. package/dist/_internal/shared/features/products/to-product-item.js +33 -5
  114. package/dist/_internal/shared/fees/calculator.d.ts +31 -2
  115. package/dist/_internal/shared/fees/calculator.js +103 -5
  116. package/dist/_internal/shared/fees/india-states.d.ts +195 -0
  117. package/dist/_internal/shared/fees/india-states.js +190 -0
  118. package/dist/_internal/shared/fees/payout-hold.d.ts +80 -0
  119. package/dist/_internal/shared/fees/payout-hold.js +74 -0
  120. package/dist/_internal/shared/obligations/deadlines.d.ts +94 -0
  121. package/dist/_internal/shared/obligations/deadlines.js +155 -0
  122. package/dist/_internal/shared/shipping/quote.d.ts +96 -0
  123. package/dist/_internal/shared/shipping/quote.js +67 -0
  124. package/dist/_internal/shared/time/business-days.d.ts +91 -0
  125. package/dist/_internal/shared/time/business-days.js +185 -0
  126. package/dist/cli/index.js +0 -2
  127. package/dist/client.d.ts +9 -4
  128. package/dist/client.js +26 -3
  129. package/dist/configs/tailwind.d.ts +0 -12
  130. package/dist/configs/tailwind.js +28 -15
  131. package/dist/constants/api-endpoints.d.ts +51 -9
  132. package/dist/constants/api-endpoints.js +23 -7
  133. package/dist/constants/index.d.ts +1 -1
  134. package/dist/constants/index.js +1 -1
  135. package/dist/contracts/index.d.ts +1 -1
  136. package/dist/contracts/payment.d.ts +131 -0
  137. package/dist/features/about/components/AboutView.js +1 -1
  138. package/dist/features/about/components/DeveloperView.js +5 -2
  139. package/dist/features/about/components/FAQPageView.js +2 -1
  140. package/dist/features/about/components/FeesView.js +2 -1
  141. package/dist/features/about/components/HelpPageView.js +2 -1
  142. package/dist/features/about/components/HowAuctionsWorkView.js +2 -1
  143. package/dist/features/about/components/HowCheckoutWorksView.js +2 -1
  144. package/dist/features/about/components/HowEmiWorksView.js +2 -1
  145. package/dist/features/about/components/HowOffersWorkView.js +2 -1
  146. package/dist/features/about/components/HowOrdersWorkView.js +2 -1
  147. package/dist/features/about/components/HowPayoutsWorkView.js +2 -1
  148. package/dist/features/about/components/HowPreOrdersWorkView.js +2 -1
  149. package/dist/features/about/components/HowReviewsWorkView.js +2 -1
  150. package/dist/features/about/components/PolicyPageView.js +2 -1
  151. package/dist/features/about/components/ProseHero.d.ts +73 -0
  152. package/dist/features/about/components/ProseHero.js +18 -0
  153. package/dist/features/about/components/SecurityPrivacyView.js +2 -1
  154. package/dist/features/about/components/ShippingPolicyView.js +2 -1
  155. package/dist/features/about/components/TrackOrderView.js +2 -1
  156. package/dist/features/about/components/UnauthorizedView.js +1 -1
  157. package/dist/features/about/index.d.ts +2 -0
  158. package/dist/features/about/index.js +5 -0
  159. package/dist/features/account/actions/address-actions.d.ts +26 -2
  160. package/dist/features/account/actions/address-actions.js +25 -1
  161. package/dist/features/account/components/BuyerShoppingGuideView.js +1 -1
  162. package/dist/features/account/components/NotificationPreferencesPanel.js +1 -1
  163. package/dist/features/account/components/UserOrdersView.js +17 -0
  164. package/dist/features/account/components/UserSidebar.js +1 -1
  165. package/dist/features/account/hooks/useNotifications.js +29 -0
  166. package/dist/features/admin/actions/admin-coupon-actions.js +36 -0
  167. package/dist/features/admin/components/AdminBeysView.js +2 -2
  168. package/dist/features/admin/components/AdminBlogEditorView.js +2 -2
  169. package/dist/features/admin/components/AdminBrandEditorView.js +32 -2
  170. package/dist/features/admin/components/AdminBundleEditorView.js +1 -1
  171. package/dist/features/admin/components/AdminCarouselEditorView.js +1 -1
  172. package/dist/features/admin/components/AdminCategoriesView.js +1 -1
  173. package/dist/features/admin/components/AdminCategoryEditorView.js +73 -17
  174. package/dist/features/admin/components/AdminContactEditorView.js +1 -1
  175. package/dist/features/admin/components/AdminCouponEditorView.js +26 -1
  176. package/dist/features/admin/components/AdminFaqEditorView.js +1 -1
  177. package/dist/features/admin/components/AdminFaqsView.js +2 -2
  178. package/dist/features/admin/components/AdminGatewayEventsView.d.ts +54 -0
  179. package/dist/features/admin/components/AdminGatewayEventsView.js +209 -0
  180. package/dist/features/admin/components/AdminGuideHubView.js +1 -1
  181. package/dist/features/admin/components/AdminMoneyCasesView.d.ts +60 -0
  182. package/dist/features/admin/components/AdminMoneyCasesView.js +287 -0
  183. package/dist/features/admin/components/AdminPartsView.js +2 -2
  184. package/dist/features/admin/components/AdminProductsView.js +75 -4
  185. package/dist/features/admin/components/AdminSidebar.js +2 -2
  186. package/dist/features/admin/components/AdminSiteSettingsView.js +65 -7
  187. package/dist/features/admin/components/AdminSublistingCategoriesView.js +2 -0
  188. package/dist/features/admin/components/AdminSupportTicketDetailView.js +1 -1
  189. package/dist/features/admin/components/AdminSupportTicketsView.js +2 -2
  190. package/dist/features/admin/components/AdminTesterChecklistView.js +2 -2
  191. package/dist/features/admin/components/AdminUsersView.js +72 -1
  192. package/dist/features/admin/components/AdminViewCards.d.ts +3 -1
  193. package/dist/features/admin/components/AdminViewCards.js +4 -4
  194. package/dist/features/admin/components/DataListingView.d.ts +28 -0
  195. package/dist/features/admin/components/DataListingView.js +175 -14
  196. package/dist/features/admin/components/DataTable.d.ts +12 -1
  197. package/dist/features/admin/components/DataTable.js +3 -3
  198. package/dist/features/admin/components/OwnerQuickActions.d.ts +1 -1
  199. package/dist/features/admin/components/OwnerQuickActions.js +60 -2
  200. package/dist/features/admin/components/RecordOwnerQuickActions.d.ts +1 -1
  201. package/dist/features/admin/components/RecordOwnerQuickActions.js +61 -14
  202. package/dist/features/admin/components/analytics/AdminStatCard.d.ts +35 -1
  203. package/dist/features/admin/components/analytics/AdminStatCard.js +77 -2
  204. package/dist/features/admin/components/index.d.ts +4 -0
  205. package/dist/features/admin/components/index.js +6 -0
  206. package/dist/features/admin/constants/filter-tabs.d.ts +156 -0
  207. package/dist/features/admin/constants/filter-tabs.js +106 -0
  208. package/dist/features/admin/repository/site-settings.repository.d.ts +22 -0
  209. package/dist/features/admin/repository/site-settings.repository.js +82 -1
  210. package/dist/features/admin/schemas/admin-editor-forms.d.ts +21 -0
  211. package/dist/features/admin/schemas/admin-editor-forms.js +44 -0
  212. package/dist/features/admin/schemas/firestore.js +5 -1
  213. package/dist/features/admin/schemas/site-settings-form.js +30 -1
  214. package/dist/features/auctions/actions/bid-actions.js +13 -1
  215. package/dist/features/auctions/components/AuctionBottomActions.js +2 -2
  216. package/dist/features/auctions/components/AuctionDetailPageView.js +3 -1
  217. package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +11 -0
  218. package/dist/features/auctions/components/MarketplaceAuctionCard.js +5 -3
  219. package/dist/features/auctions/components/PlaceBidFormClient.d.ts +8 -1
  220. package/dist/features/auctions/components/PlaceBidFormClient.js +2 -2
  221. package/dist/features/audit-log/schemas/firestore.d.ts +28 -0
  222. package/dist/features/audit-log/schemas/firestore.js +14 -0
  223. package/dist/features/auth/permissions/constants.d.ts +17 -1
  224. package/dist/features/auth/permissions/constants.js +18 -0
  225. package/dist/features/blog/components/BlogPostView.js +1 -1
  226. package/dist/features/catalogue/components/AdminCatalogueApprovalsView.js +1 -1
  227. package/dist/features/categories/api/[id]/description-template/route.js +107 -1
  228. package/dist/features/categories/components/BrandDetailPageView.js +2 -2
  229. package/dist/features/categories/components/BreadcrumbTrail.js +7 -1
  230. package/dist/features/categories/components/BundleDetailView.js +1 -1
  231. package/dist/features/categories/components/CategoryDetailPageView.js +2 -2
  232. package/dist/features/categories/components/CategoryForm.js +12 -1
  233. package/dist/features/categories/components/CategoryTemplatePicker.js +38 -5
  234. package/dist/features/categories/repository/market-price-index.repository.d.ts +123 -0
  235. package/dist/features/categories/repository/market-price-index.repository.js +105 -0
  236. package/dist/features/categories/repository/price-observation.repository.d.ts +166 -0
  237. package/dist/features/categories/repository/price-observation.repository.js +132 -0
  238. package/dist/features/events/components/EventSaleBanner.js +1 -1
  239. package/dist/features/events/components/EventStatusBadge.js +1 -1
  240. package/dist/features/faq/components/FAQAccordion.js +2 -1
  241. package/dist/features/faq/components/FAQCategorySidebar.js +2 -2
  242. package/dist/features/faq/components/FAQHelpfulButtons.js +4 -4
  243. package/dist/features/faq/components/RelatedFAQs.js +1 -1
  244. package/dist/features/filters/FilterFacetSection.js +1 -1
  245. package/dist/features/filters/SwitchFilter.js +1 -1
  246. package/dist/features/gateway-events/repository/gateway-events.repository.d.ts +117 -0
  247. package/dist/features/gateway-events/repository/gateway-events.repository.js +274 -0
  248. package/dist/features/gateway-events/schemas/firestore.d.ts +217 -0
  249. package/dist/features/gateway-events/schemas/firestore.js +125 -0
  250. package/dist/features/gateway-events/schemas/index.d.ts +81 -0
  251. package/dist/features/gateway-events/schemas/index.js +79 -0
  252. package/dist/features/grouped/components/GroupedListingDetailView.js +1 -1
  253. package/dist/features/homepage/components/AnnouncementBar.js +37 -1
  254. package/dist/features/homepage/components/AnnouncementBar.style.css +30 -0
  255. package/dist/features/homepage/components/BrandsSection.js +1 -1
  256. package/dist/features/homepage/components/CTABannerSection.js +1 -1
  257. package/dist/features/homepage/components/FeaturedBundlesSection.js +14 -24
  258. package/dist/features/homepage/components/HeroCarousel.js +2 -2
  259. package/dist/features/homepage/components/SocialPostCard.js +1 -1
  260. package/dist/features/inventory/components/AdminMoveLedgerView.d.ts +7 -0
  261. package/dist/features/inventory/components/AdminMoveLedgerView.js +157 -0
  262. package/dist/features/inventory/components/AdminStorageBoxesView.d.ts +11 -0
  263. package/dist/features/inventory/components/AdminStorageBoxesView.js +168 -0
  264. package/dist/features/inventory/components/ReceiveStationView.d.ts +39 -0
  265. package/dist/features/inventory/components/ReceiveStationView.js +413 -0
  266. package/dist/features/inventory/components/operator-message.d.ts +29 -0
  267. package/dist/features/inventory/components/operator-message.js +41 -0
  268. package/dist/features/inventory/index.d.ts +13 -0
  269. package/dist/features/inventory/index.js +28 -0
  270. package/dist/features/inventory/repository/inventory-movements.repository.d.ts +97 -0
  271. package/dist/features/inventory/repository/inventory-movements.repository.js +186 -0
  272. package/dist/features/inventory/repository/inventory-placements.repository.d.ts +179 -0
  273. package/dist/features/inventory/repository/inventory-placements.repository.js +345 -0
  274. package/dist/features/inventory/repository/storage-boxes.repository.d.ts +83 -0
  275. package/dist/features/inventory/repository/storage-boxes.repository.js +127 -0
  276. package/dist/features/inventory/schemas/firestore.d.ts +197 -0
  277. package/dist/features/inventory/schemas/firestore.js +159 -0
  278. package/dist/features/layout/AppLayoutShell.d.ts +12 -1
  279. package/dist/features/layout/AppLayoutShell.js +25 -12
  280. package/dist/features/layout/AutoBreadcrumbs.js +162 -3
  281. package/dist/features/layout/AutoBreadcrumbs.style.css +45 -0
  282. package/dist/features/layout/BottomNavbar.d.ts +1 -1
  283. package/dist/features/layout/BottomNavbar.js +2 -2
  284. package/dist/features/media/MediaAvatar.js +1 -1
  285. package/dist/features/media/MediaImage.d.ts +24 -4
  286. package/dist/features/media/MediaImage.js +44 -4
  287. package/dist/features/media/MediaLightbox.js +1 -1
  288. package/dist/features/media/modals/ImageCropModal.js +1 -1
  289. package/dist/features/media/modals/ImageEditor.js +1 -1
  290. package/dist/features/media/upload/MediaUploadField.js +91 -3
  291. package/dist/features/obligations/constants/policies.d.ts +92 -0
  292. package/dist/features/obligations/constants/policies.js +378 -0
  293. package/dist/features/obligations/repository/obligations.repository.d.ts +68 -0
  294. package/dist/features/obligations/repository/obligations.repository.js +158 -0
  295. package/dist/features/obligations/schemas/firestore.d.ts +160 -0
  296. package/dist/features/obligations/schemas/firestore.js +87 -0
  297. package/dist/features/orders/actions/order-actions.d.ts +43 -4
  298. package/dist/features/orders/actions/order-actions.js +60 -3
  299. package/dist/features/orders/actions/refund-actions.js +70 -10
  300. package/dist/features/orders/components/OrderCompletionPanel.d.ts +27 -0
  301. package/dist/features/orders/components/OrderCompletionPanel.js +192 -0
  302. package/dist/features/orders/components/OrdersList.js +2 -2
  303. package/dist/features/orders/components/RefundHistoryTable.js +3 -1
  304. package/dist/features/orders/components/index.d.ts +2 -0
  305. package/dist/features/orders/components/index.js +6 -0
  306. package/dist/features/orders/constants/transitions.d.ts +59 -0
  307. package/dist/features/orders/constants/transitions.js +104 -0
  308. package/dist/features/orders/repository/orders.repository.d.ts +109 -6
  309. package/dist/features/orders/repository/orders.repository.js +464 -21
  310. package/dist/features/orders/schemas/firestore.d.ts +270 -0
  311. package/dist/features/orders/schemas/firestore.js +24 -0
  312. package/dist/features/orders/schemas/index.d.ts +61 -0
  313. package/dist/features/orders/schemas/index.js +22 -0
  314. package/dist/features/orders/types/index.d.ts +79 -0
  315. package/dist/features/parts/components/PartsIndexPageView.js +8 -1
  316. package/dist/features/payment-cases/repository/payment-cases.repository.d.ts +170 -0
  317. package/dist/features/payment-cases/repository/payment-cases.repository.js +342 -0
  318. package/dist/features/payment-cases/schemas/firestore.d.ts +229 -0
  319. package/dist/features/payment-cases/schemas/firestore.js +105 -0
  320. package/dist/features/payment-cases/schemas/resolve-form.d.ts +97 -0
  321. package/dist/features/payment-cases/schemas/resolve-form.js +114 -0
  322. package/dist/features/payments/repository/payout.repository.d.ts +0 -1
  323. package/dist/features/payments/repository/payout.repository.js +0 -1
  324. package/dist/features/points/repository/points.repository.d.ts +122 -0
  325. package/dist/features/points/repository/points.repository.js +304 -1
  326. package/dist/features/points/schemas/adjust-form.d.ts +58 -0
  327. package/dist/features/points/schemas/adjust-form.js +63 -0
  328. package/dist/features/points/schemas/firestore.d.ts +108 -1
  329. package/dist/features/points/schemas/firestore.js +84 -0
  330. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +3 -3
  331. package/dist/features/pre-orders/components/PreOrderBadge.js +1 -1
  332. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +1 -1
  333. package/dist/features/price-index/components/PriceIndexToolView.d.ts +23 -4
  334. package/dist/features/price-index/components/PriceIndexToolView.js +71 -6
  335. package/dist/features/price-index/market-stats.d.ts +82 -0
  336. package/dist/features/price-index/market-stats.js +230 -0
  337. package/dist/features/print/components/BoxLabelPrintView.d.ts +25 -0
  338. package/dist/features/print/components/BoxLabelPrintView.js +66 -0
  339. package/dist/features/print/components/LabelProfilePicker.d.ts +13 -0
  340. package/dist/features/print/components/LabelProfilePicker.js +38 -0
  341. package/dist/features/print/components/labels.d.ts +117 -0
  342. package/dist/features/print/components/labels.js +258 -0
  343. package/dist/features/print/components/labels.style.css +46 -0
  344. package/dist/features/print/index.d.ts +6 -0
  345. package/dist/features/print/index.js +16 -0
  346. package/dist/features/products/columns/productTableColumns.js +5 -4
  347. package/dist/features/products/components/MarketplaceBundleCard.js +2 -2
  348. package/dist/features/products/components/MarketplacePrizeDrawCard.js +6 -6
  349. package/dist/features/products/components/PrizeDrawCollage.js +1 -1
  350. package/dist/features/products/components/PrizeDrawItemsEditor.js +1 -1
  351. package/dist/features/products/components/PrizeRevealModal.js +2 -2
  352. package/dist/features/products/components/ProductDetailPageView.js +18 -4
  353. package/dist/features/products/components/ProductForm.js +34 -23
  354. package/dist/features/products/components/ProductGrid.js +86 -62
  355. package/dist/features/products/constants/card-badges.d.ts +97 -0
  356. package/dist/features/products/constants/card-badges.js +100 -0
  357. package/dist/features/products/repository/products.repository.js +34 -1
  358. package/dist/features/products/schemas/firestore.d.ts +46 -3
  359. package/dist/features/products/schemas/firestore.js +21 -0
  360. package/dist/features/promotions/components/PromotionsView.js +1 -1
  361. package/dist/features/promotions/repository/claimed-coupons.repository.d.ts +32 -0
  362. package/dist/features/promotions/repository/claimed-coupons.repository.js +58 -0
  363. package/dist/features/promotions/schemas/firestore.js +30 -3
  364. package/dist/features/promotions/schemas/index.d.ts +6 -6
  365. package/dist/features/protection-claims/repository/protection-claims.repository.d.ts +54 -0
  366. package/dist/features/protection-claims/repository/protection-claims.repository.js +174 -0
  367. package/dist/features/protection-claims/schemas/firestore.d.ts +168 -0
  368. package/dist/features/protection-claims/schemas/firestore.js +130 -0
  369. package/dist/features/reviews/actions/review-actions.js +3 -2
  370. package/dist/features/reviews/components/ReviewModal.js +1 -1
  371. package/dist/features/reviews/components/ReviewsList.js +1 -1
  372. package/dist/features/reviews/schemas/firestore.d.ts +20 -1
  373. package/dist/features/scams/constants/scam-types.d.ts +2 -0
  374. package/dist/features/scams/constants/scam-types.js +18 -0
  375. package/dist/features/scams/schemas/report-form.d.ts +3 -3
  376. package/dist/features/scams/schemas/report-form.js +26 -1
  377. package/dist/features/search/components/Search.js +9 -9
  378. package/dist/features/search/components/SearchResultsClient.js +18 -3
  379. package/dist/features/search/components/SearchResultsPageView.d.ts +1 -6
  380. package/dist/features/search/components/SearchResultsPageView.js +2 -2
  381. package/dist/features/seller/actions/offer-actions.js +16 -1
  382. package/dist/features/seller/actions/seller-actions.js +14 -3
  383. package/dist/features/seller/components/CategoryInlineSelect.js +75 -11
  384. package/dist/features/seller/components/PrintCenterView.d.ts +5 -0
  385. package/dist/features/seller/components/PrintCenterView.js +41 -30
  386. package/dist/features/seller/components/SellerOrdersView.js +1 -1
  387. package/dist/features/seller/components/SellerPayoutRequestView.js +16 -5
  388. package/dist/features/seller/components/SellerPayoutSettingsView.js +1 -1
  389. package/dist/features/seller/components/SellerProductShell.d.ts +16 -0
  390. package/dist/features/seller/components/SellerProductShell.js +123 -13
  391. package/dist/features/seller/components/SellerReviewsView.js +4 -2
  392. package/dist/features/seller/components/SellerSidebar.js +1 -1
  393. package/dist/features/seller/schemas/coupon-form.d.ts +26 -0
  394. package/dist/features/seller/schemas/coupon-form.js +27 -0
  395. package/dist/features/seller/schemas/product-form.d.ts +3 -0
  396. package/dist/features/seller/schemas/product-form.js +5 -0
  397. package/dist/features/shell/FormShell.js +2 -2
  398. package/dist/features/shell/QuickFormDrawer.js +14 -0
  399. package/dist/features/shell/SectionForm.d.ts +19 -0
  400. package/dist/features/shell/SectionForm.js +133 -9
  401. package/dist/features/shell/SectionForm.style.css +54 -0
  402. package/dist/features/shipments/components/AdminShipmentsView.js +16 -1
  403. package/dist/features/shipments/repository/shipment-items.repository.d.ts +9 -0
  404. package/dist/features/shipments/repository/shipment-items.repository.js +14 -0
  405. package/dist/features/site-settings/components/ActionPermissionsManager.js +1 -1
  406. package/dist/features/sticker-trace/components/StickerCommitPanel.js +1 -1
  407. package/dist/features/store-extensions/schemas/report-review-form.d.ts +8 -8
  408. package/dist/features/stores/components/StoreGuideHubView.js +1 -1
  409. package/dist/features/stores/components/StoreHeader.js +1 -1
  410. package/dist/features/support/schemas/firestore.d.ts +73 -2
  411. package/dist/features/support/schemas/firestore.js +59 -0
  412. package/dist/index.d.ts +16 -24
  413. package/dist/index.js +38 -47
  414. package/dist/next/ErrorBoundary.js +1 -1
  415. package/dist/next/routing/route-map.d.ts +24 -0
  416. package/dist/next/routing/route-map.js +40 -0
  417. package/dist/providers/payment-manual/index.d.ts +15 -1
  418. package/dist/providers/payment-manual/index.js +37 -0
  419. package/dist/providers/payment-phonepe/index.d.ts +14 -1
  420. package/dist/providers/payment-phonepe/index.js +36 -0
  421. package/dist/providers/payment-razorpay/index.d.ts +44 -1
  422. package/dist/providers/payment-razorpay/index.js +99 -0
  423. package/dist/providers/shipping-shiprocket/index.d.ts +18 -0
  424. package/dist/providers/shipping-shiprocket/index.js +18 -0
  425. package/dist/schemas/registry.d.ts +44 -11
  426. package/dist/server-entry.d.ts +2 -0
  427. package/dist/server-entry.js +27 -0
  428. package/dist/server.d.ts +42 -0
  429. package/dist/server.js +93 -0
  430. package/dist/styles.css +418 -149
  431. package/dist/tailwind-utilities.css +1 -1
  432. package/dist/tokens/themes/default-dark.js +15 -12
  433. package/dist/tokens/themes/default-light.js +14 -11
  434. package/dist/tokens/tokens.css +106 -23
  435. package/dist/ui/DataTable.style.css +4 -4
  436. package/dist/ui/columns/cell-renderers.d.ts +20 -0
  437. package/dist/ui/columns/cell-renderers.js +26 -1
  438. package/dist/ui/columns/index.d.ts +1 -1
  439. package/dist/ui/columns/index.js +4 -1
  440. package/dist/ui/components/Badge.style.css +1 -1
  441. package/dist/ui/components/Breadcrumb.js +19 -1
  442. package/dist/ui/components/BulkActionBar.style.css +4 -4
  443. package/dist/ui/components/Button.style.css +1 -1
  444. package/dist/ui/components/Checkbox.style.css +1 -1
  445. package/dist/ui/components/FallbackShell.js +1 -1
  446. package/dist/ui/components/Form.d.ts +14 -1
  447. package/dist/ui/components/Form.js +2 -2
  448. package/dist/ui/components/FormField.js +18 -4
  449. package/dist/ui/components/FormField.style.css +43 -3
  450. package/dist/ui/components/GatedPrice.style.css +1 -1
  451. package/dist/ui/components/IconButton.style.css +1 -1
  452. package/dist/ui/components/Input.js +22 -1
  453. package/dist/ui/components/Input.style.css +38 -22
  454. package/dist/ui/components/ListingFilterDrawer.js +1 -1
  455. package/dist/ui/components/ListingToolbar.js +1 -1
  456. package/dist/ui/components/PaginatedSelect.js +0 -0
  457. package/dist/ui/components/Radio.style.css +1 -1
  458. package/dist/ui/components/Repeater.d.ts +53 -0
  459. package/dist/ui/components/Repeater.js +7 -0
  460. package/dist/ui/components/RichTextEditor.d.ts +20 -1
  461. package/dist/ui/components/RichTextEditor.js +23 -2
  462. package/dist/ui/components/Select.style.css +7 -21
  463. package/dist/ui/components/Semantic.js +27 -3
  464. package/dist/ui/components/TagInput.style.css +4 -9
  465. package/dist/ui/components/Textarea.style.css +4 -18
  466. package/dist/ui/components/Toggle.style.css +1 -1
  467. package/dist/ui/components/Typography.d.ts +3 -3
  468. package/dist/ui/components/Typography.js +15 -15
  469. package/dist/ui/components/ViewToggle.style.css +4 -4
  470. package/dist/ui/forms/AddAnotherToggle.d.ts +16 -0
  471. package/dist/ui/forms/AddAnotherToggle.js +56 -0
  472. package/dist/ui/forms/ColorPickerField.js +15 -2
  473. package/dist/ui/forms/FieldCheckbox.js +15 -2
  474. package/dist/ui/forms/FieldInput.d.ts +22 -1
  475. package/dist/ui/forms/FieldInput.js +19 -5
  476. package/dist/ui/forms/FieldLabel.d.ts +35 -0
  477. package/dist/ui/forms/FieldLabel.js +70 -0
  478. package/dist/ui/forms/FieldSelect.d.ts +4 -1
  479. package/dist/ui/forms/FieldSelect.js +27 -5
  480. package/dist/ui/forms/FieldTextarea.d.ts +4 -1
  481. package/dist/ui/forms/FieldTextarea.js +22 -5
  482. package/dist/ui/forms/FormShell.d.ts +17 -1
  483. package/dist/ui/forms/FormShell.js +36 -2
  484. package/dist/ui/forms/FormShell.style.css +41 -33
  485. package/dist/ui/forms/index.d.ts +5 -1
  486. package/dist/ui/forms/index.js +2 -0
  487. package/dist/ui/icons/icon-registry.d.ts +1 -0
  488. package/dist/ui/icons/icon-registry.js +17 -1
  489. package/dist/utils/id-generators.d.ts +80 -0
  490. package/dist/utils/id-generators.js +93 -0
  491. package/dist/utils/search-txt-builders.d.ts +12 -0
  492. package/dist/utils/search-txt-builders.js +17 -0
  493. package/package.json +1 -1
  494. package/scripts/seed-cli.mjs +106 -5
  495. package/dist/features/loyalty/api/admin/loyalty/grant/route.d.ts +0 -12
  496. package/dist/features/loyalty/api/admin/loyalty/grant/route.js +0 -38
  497. package/dist/features/loyalty/api/balance/route.d.ts +0 -12
  498. package/dist/features/loyalty/api/balance/route.js +0 -41
  499. package/dist/features/loyalty/api/earn/route.d.ts +0 -12
  500. package/dist/features/loyalty/api/earn/route.js +0 -38
  501. package/dist/features/loyalty/api/history/route.d.ts +0 -12
  502. package/dist/features/loyalty/api/history/route.js +0 -58
  503. package/dist/features/loyalty/api/redeem/route.d.ts +0 -12
  504. package/dist/features/loyalty/api/redeem/route.js +0 -38
  505. package/dist/features/loyalty/columns/index.d.ts +0 -17
  506. package/dist/features/loyalty/columns/index.js +0 -40
  507. package/dist/features/loyalty/components/CoinsDisplay.d.ts +0 -12
  508. package/dist/features/loyalty/components/CoinsDisplay.js +0 -10
  509. package/dist/features/loyalty/components/index.d.ts +0 -1
  510. package/dist/features/loyalty/components/index.js +0 -1
  511. package/dist/features/loyalty/hooks/useLoyaltyBalance.d.ts +0 -4
  512. package/dist/features/loyalty/hooks/useLoyaltyBalance.js +0 -25
  513. package/dist/features/loyalty/index.d.ts +0 -6
  514. package/dist/features/loyalty/index.js +0 -6
  515. package/dist/features/loyalty/manifest.d.ts +0 -2
  516. package/dist/features/loyalty/manifest.js +0 -16
  517. package/dist/features/loyalty/messages/en.json +0 -19
  518. package/dist/features/loyalty/repository/loyalty.repository.d.ts +0 -8
  519. package/dist/features/loyalty/repository/loyalty.repository.js +0 -22
  520. package/dist/features/loyalty/schemas/index.d.ts +0 -85
  521. package/dist/features/loyalty/schemas/index.js +0 -40
  522. package/dist/features/loyalty/server.d.ts +0 -6
  523. package/dist/features/loyalty/server.js +0 -6
  524. package/dist/features/loyalty/types/index.d.ts +0 -31
  525. package/dist/features/loyalty/types/index.js +0 -1
  526. package/dist/features/loyalty/types/loyalty-config.d.ts +0 -7
  527. package/dist/features/loyalty/types/loyalty-config.js +0 -1
  528. package/dist/features/loyalty/types/loyalty-math.d.ts +0 -9
  529. package/dist/features/loyalty/types/loyalty-math.js +0 -27
  530. package/dist/features/products/components/ProductOwnerQuickActions.d.ts +0 -11
  531. package/dist/features/products/components/ProductOwnerQuickActions.js +0 -120
@@ -0,0 +1,258 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ /**
4
+ * Physical labels — the ones that get stuck to things.
5
+ *
6
+ * 🛑 EVERYTHING HERE IS SIZED IN MILLIMETRES, because the output is a physical
7
+ * object. `PrintCenterView` sized its labels `w-[200px]` and emitted no `@page`
8
+ * rule at all, so a thermal printer received the browser's default A4 with a
9
+ * 200-pixel card in the corner of it. Nothing errored; the operator found out
10
+ * by holding a mostly-blank 50 x 25 mm label.
11
+ *
12
+ * ── THE TWO UNIT CONVERSIONS THAT MATTER ────────────────────────────────────
13
+ *
14
+ * 1. CSS defines 96 px per inch, EXACTLY, regardless of screen DPI. At print
15
+ * time the browser maps that to physical length, so a CSS px is 25.4/96 =
16
+ * 0.2646 mm of paper. That is the only bridge between a layout and a ruler.
17
+ *
18
+ * 2. `JsBarcode`'s `width` option is PIXELS PER MODULE, not millimetres. The
19
+ * previous code passed `width: 2`, i.e. a 0.53 mm module — twice the density
20
+ * needed, which is why those barcodes were enormous. `moduleWidthPx()`
21
+ * converts a target mm module into that option so the intent is stated once.
22
+ *
23
+ * 🛑 AND THE WHOLE CHAIN IS DEFEATED BY THE PRINT DIALOG. "Fit to page" or any
24
+ * scale other than 100% rescales the symbol, taking the module width with it —
25
+ * silently, and the label still looks correct. Every printable view here says
26
+ * so on screen, because it is the one failure no code can prevent.
27
+ *
28
+ * ── WHY THIS FILE USES `style={{}}` FOR DIMENSIONS ──────────────────────────
29
+ *
30
+ * Normally a variant or a token; here the numbers come from the PROFILE at
31
+ * runtime, so `w-[${profile.widthMm}mm]` is a class Tailwind's build-time
32
+ * scanner never sees and therefore never generates — it would silently emit
33
+ * nothing and every label would collapse to its content size. These are the
34
+ * "dynamic values impossible with classes" case the inline-style rule exists
35
+ * to permit, and none of them is a COLOUR: every `style` here is a length or a
36
+ * position. Colour, surface and type still go through the primitives.
37
+ */
38
+ import { useEffect, useMemo, useRef } from "react";
39
+ import JsBarcode from "jsbarcode";
40
+ import { Div, Row, Stack, Text } from "../../../ui/index.js";
41
+ import { normalizeError } from "../../../errors/normalize.js";
42
+ import { MM_PER_INCH, SAFE_MODULE_MM, labelFitsProfile, sheetPositionMm, } from "../../../_internal/shared/features/print/label-profiles.js";
43
+ /** CSS px per inch is 96 by definition — not a screen measurement. */
44
+ const CSS_PX_PER_INCH = 96;
45
+ /** Millimetres of paper to CSS pixels. The only unit bridge in this file. */
46
+ export function mmToCssPx(mm) {
47
+ return (mm / MM_PER_INCH) * CSS_PX_PER_INCH;
48
+ }
49
+ /**
50
+ * A target module width in mm, as JsBarcode's `width` option.
51
+ *
52
+ * Not rounded to an integer: JsBarcode accepts a fractional module width and
53
+ * rounding to 1 px would quantise every density to 0.265 mm steps — which on a
54
+ * 50 x 25 mm label is the difference between fitting and not.
55
+ */
56
+ export function moduleWidthPx(moduleMm = SAFE_MODULE_MM) {
57
+ return mmToCssPx(moduleMm);
58
+ }
59
+ /**
60
+ * Renders a CODE128 symbol at a known physical density.
61
+ *
62
+ * 🛑 THE QUIET ZONE IS COMPUTED, NOT GUESSED. CODE128 requires 10 modules of
63
+ * clear space each side, and JsBarcode's `margin` is in pixels — so it must
64
+ * scale with the module. The previous code passed a FIXED `margin: 8` beside
65
+ * `width: 2`, which is 4 modules: under half the spec minimum. A short quiet
66
+ * zone does not look wrong and does not fail to render; it just makes some
67
+ * scanners refuse some reads, which is indistinguishable from a worn label.
68
+ */
69
+ function Barcode({ value, moduleMm = SAFE_MODULE_MM, heightMm, showValue = true, }) {
70
+ const ref = useRef(null);
71
+ useEffect(() => {
72
+ if (!ref.current || !value)
73
+ return;
74
+ const px = moduleWidthPx(moduleMm);
75
+ try {
76
+ JsBarcode(ref.current, value, {
77
+ format: "CODE128",
78
+ width: px,
79
+ height: mmToCssPx(heightMm),
80
+ displayValue: showValue,
81
+ // ~2 mm of type: readable by a human squinting, and small enough that
82
+ // it does not steal height from the bars on a 25 mm label.
83
+ fontSize: mmToCssPx(2),
84
+ textMargin: mmToCssPx(0.4),
85
+ margin: 10 * px,
86
+ });
87
+ }
88
+ catch (_err) {
89
+ /*
90
+ * JsBarcode throws on a value CODE128 cannot encode. The `<svg>` is left
91
+ * empty and the label still prints its text, which is the right
92
+ * degradation: a label with a title and no barcode is filable by hand,
93
+ * and the only real fix is correcting the code on the record.
94
+ */
95
+ void normalizeError(_err);
96
+ }
97
+ }, [value, moduleMm, heightMm, showValue]);
98
+ return _jsx("svg", { ref: ref, "aria-label": `Barcode ${value}` });
99
+ }
100
+ /**
101
+ * The single `@page` owner for a printable view.
102
+ *
103
+ * 🛑 EXACTLY ONE OF THESE PER VIEW. `@page` is document-global and cannot be
104
+ * scoped — two of them does not give two geometries, the later one in document
105
+ * order silently wins and the label prints at the wrong size with nothing in
106
+ * the markup looking wrong. `audit-label-profiles` R3 enforces that only
107
+ * `label-profiles.ts` may author the rule at all.
108
+ */
109
+ export function LabelPageStyle({ css }) {
110
+ return _jsx("style", { children: css });
111
+ }
112
+ /** One label's box, in mm, with the profile's padding inside it. */
113
+ function LabelBox({ profile, children, }) {
114
+ return (_jsx(Div, { className: "appkit-label", style: {
115
+ width: `${profile.widthMm}mm`,
116
+ height: `${profile.heightMm}mm`,
117
+ padding: `${profile.paddingMm}mm`,
118
+ boxSizing: "border-box",
119
+ overflow: "hidden",
120
+ display: "flex",
121
+ flexDirection: "column",
122
+ alignItems: "center",
123
+ justifyContent: "center",
124
+ textAlign: "center",
125
+ }, children: children }));
126
+ }
127
+ /**
128
+ * A product label: symbol, name, price, and WHERE IT LIVES.
129
+ *
130
+ * 🛑 THE BOX CODE IS THE ADDITION THAT MAKES THE LABEL USEFUL FOR PUTTING
131
+ * THINGS AWAY. Without it a picker holding the item has to scan it and look at
132
+ * a screen to learn which shelf it came off; with it the label answers the
133
+ * question the person holding it is actually asking. It replaces the free-text
134
+ * `physicalLocation` that used to print here — that field was three
135
+ * inconsistent inputs with no registry behind it, so two people wrote "shelf
136
+ * 3", "Shelf-3" and "AC60 3" for one place and no list could group them.
137
+ */
138
+ export function ProductLabel({ profile, product, }) {
139
+ const code = product.barcodeId ?? product.sku ?? null;
140
+ /*
141
+ * The fit is checked PER LABEL, against the code this label actually
142
+ * carries — not once for the profile. Codes vary in length (a seller-authored
143
+ * SKU is variable width by design), so one product can fit stock that the
144
+ * next cannot.
145
+ */
146
+ const fit = useMemo(() => (code ? labelFitsProfile(profile, code.length) : null), [profile, code]);
147
+ /*
148
+ * 🛑 REFUSES, NEVER SCALES. A symbol squeezed to fit looks perfect and does
149
+ * not scan — the proportions stay right while the module width drops below
150
+ * what a scanner resolves, so the failure surfaces weeks later as "the
151
+ * scanner is broken" with every label already stuck to something. A visible
152
+ * refusal is read in the second it happens, by the person who can still pick
153
+ * different stock.
154
+ */
155
+ const refuse = fit !== null && !fit.fits;
156
+ return (_jsxs(LabelBox, { profile: profile, children: [code && !refuse ? (_jsx(Barcode, { value: code,
157
+ // A third of the label's height, which leaves room for the name and
158
+ // price without the bars becoming too short to scan at an angle.
159
+ heightMm: Math.max(6, profile.heightMm * 0.42) })) : code ? (_jsxs(Text, { size: "xs", color: "error", children: ["Code too long for ", profile.widthMm, "\u00D7", profile.heightMm, " mm"] })) : (_jsx(Text, { size: "xs", color: "muted", children: "No barcode" })), _jsx(Text, { size: "xs", weight: "medium", truncate: 1, children: product.name }), _jsxs(Row, { gap: "xs", justify: "center", wrap: true, children: [product.price != null && (_jsxs(Text, { size: "xs", color: "muted", children: ["\u20B9", product.price.toLocaleString("en-IN")] })), product.boxCode && (_jsx(Text, { size: "xs", weight: "semibold", children: product.boxCode }))] })] }));
160
+ }
161
+ /**
162
+ * A box label: the code, large, plus what it held WHEN PRINTED.
163
+ *
164
+ * 🛑 THE PRINT DATE IS NOT DECORATION — it is what makes the counts honest. A
165
+ * label is a frozen snapshot stuck to a moving object: the moment something is
166
+ * picked, the printed count is wrong. Printing "8 items" with no date invites
167
+ * the operator to trust it; printing "8 items as of 21 Oct" says plainly that
168
+ * it is a note from the past and the screen is authoritative.
169
+ *
170
+ * 🛑 The barcode encodes `BOX-{code}`, with the prefix, because the receive
171
+ * station discriminates on it: a `BOX-` scan arms a box and a `LIR-` scan adds
172
+ * an item, and that decision has to be makeable without a lookup. The stored
173
+ * `code` is the bare `AC60-03`.
174
+ */
175
+ export function BoxLabel({ profile, box, }) {
176
+ const value = `BOX-${box.code.toUpperCase()}`;
177
+ const fit = labelFitsProfile(profile, value.length);
178
+ return (_jsxs(LabelBox, { profile: profile, children: [fit.fits ? (_jsx(Barcode, { value: value, heightMm: Math.max(8, profile.heightMm * 0.4) })) : (_jsxs(Text, { size: "xs", color: "error", children: [value, " too long for this stock"] })), _jsx(Text, { size: "lg", weight: "bold", numeric: true, children: box.code }), _jsx(Text, { size: "xs", color: "muted", children: [box.boxType, box.location].filter(Boolean).join(" · ") }), box.totalUnits != null ? (_jsxs(Text, { size: "xs", color: "muted", children: [box.distinctProducts ?? 0, " product", box.distinctProducts === 1 ? "" : "s", " \u00B7 ", box.totalUnits, " unit", box.totalUnits === 1 ? "" : "s", box.countedAt
179
+ ? ` as of ${new Date(box.countedAt).toLocaleDateString("en-IN", {
180
+ day: "numeric",
181
+ month: "short",
182
+ })}`
183
+ : ""] })) : (
184
+ /*
185
+ * "Not yet counted" rather than "0 products". The rollup is written by
186
+ * a scheduled job, so a box registered this morning has no counts —
187
+ * and a printed `0` about a full box is worse than no number at all.
188
+ */
189
+ _jsx(Text, { size: "xs", color: "muted", children: "Not yet counted" }))] }));
190
+ }
191
+ /**
192
+ * Lays labels out on an A4 die-cut sheet, at the stock's real pitch.
193
+ *
194
+ * 🛑 ABSOLUTE POSITIONING FROM THE PITCH, not a flex grid. A grid distributes
195
+ * whatever space it is given; a die-cut sheet has fixed holes, and the only
196
+ * thing that lands ink inside them is placing each label at
197
+ * `margin + n x pitch`. One millimetre of accumulated flex rounding is
198
+ * invisible on label one and off the die-cut by label thirteen.
199
+ */
200
+ export function LabelSheet({ profile, children, }) {
201
+ const sheet = profile.sheet;
202
+ if (!sheet) {
203
+ // Thermal: the page IS the label, so each child is its own page and the
204
+ // `@page` rule plus `break-after` handles it. No positioning to do.
205
+ return _jsx(_Fragment, { children: children });
206
+ }
207
+ const perPage = sheet.columns * sheet.rows;
208
+ const pages = [];
209
+ for (let i = 0; i < children.length; i += perPage) {
210
+ pages.push(children.slice(i, i + perPage));
211
+ }
212
+ return (_jsx(_Fragment, { children: pages.map((page, pageIndex) => (_jsx(Div, { className: "appkit-label-sheet", style: {
213
+ position: "relative",
214
+ width: `${profile.page.widthMm}mm`,
215
+ height: `${profile.page.heightMm}mm`,
216
+ // A sheet past the first must start on a new page; the first must
217
+ // NOT, or every print begins with a blank sheet.
218
+ breakBefore: pageIndex === 0 ? "auto" : "page",
219
+ }, children: page.map((child, i) => {
220
+ const pos = sheetPositionMm(sheet, i);
221
+ if (!pos)
222
+ return null;
223
+ return (_jsx(Div, { style: {
224
+ position: "absolute",
225
+ left: `${pos.leftMm}mm`,
226
+ top: `${pos.topMm}mm`,
227
+ }, children: child }, i));
228
+ }) }, pageIndex))) }));
229
+ }
230
+ /**
231
+ * An A4 sheet listing what is in a box — the thing that goes INSIDE it, or on
232
+ * the shelf beside it.
233
+ *
234
+ * 🛑 A4, not a label, and that is the point of having it at all. A 50 x 25 mm
235
+ * label cannot list eight products, so the box label carries only a total; the
236
+ * contents have to live somewhere a person can read them without a screen, and
237
+ * that is a sheet of paper. It is explicitly a snapshot, dated in the header
238
+ * for the same reason the box label's counts are.
239
+ */
240
+ export function BoxContentsSheet({ boxCode, boxType, location, rows, printedAt, }) {
241
+ const totalUnits = rows.reduce((n, r) => n + r.quantity, 0);
242
+ return (_jsx(Div, { className: "appkit-label-sheet", style: {
243
+ width: "210mm",
244
+ minHeight: "297mm",
245
+ padding: "12mm",
246
+ boxSizing: "border-box",
247
+ }, children: _jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { size: "2xl", weight: "bold", numeric: true, children: boxCode }), _jsx(Text, { size: "sm", color: "muted", children: [boxType, location].filter(Boolean).join(" · ") })] }), _jsxs(Text, { size: "sm", color: "muted", children: [rows.length, " product", rows.length === 1 ? "" : "s", " \u00B7 ", totalUnits, " ", "unit", totalUnits === 1 ? "" : "s", " \u00B7 printed", " ", new Date(printedAt).toLocaleString("en-IN")] }), _jsx(Text, { size: "xs", color: "muted", children: "A snapshot. The dashboard is authoritative \u2014 anything picked since this was printed is still listed here." }), _jsx(Div, { style: { marginTop: "6mm" }, children: rows.length === 0 ? (_jsx(Text, { color: "muted", children: "This box is empty." })) : (_jsx(Stack, { gap: "none", children: rows.map((r, i) => (_jsxs(Row, { justify: "between", align: "center", padding: "y-2xs", border: "bottom", children: [_jsxs(Stack, { gap: "none", children: [_jsx(Text, { size: "sm", children: r.productTitle }), (r.productSku || r.slot) && (_jsx(Text, { size: "xs", color: "muted", numeric: true, children: [r.productSku, r.slot].filter(Boolean).join(" · ") }))] }), _jsxs(Text, { size: "sm", weight: "semibold", numeric: true, children: ["\u00D7", r.quantity] })] }, `${r.productTitle}-${i}`))) })) })] }) }));
248
+ }
249
+ /**
250
+ * The on-screen warning that no code can replace.
251
+ *
252
+ * Every density calculation in this file assumes the browser prints at 100%.
253
+ * "Fit to page" rescales the symbol and takes the module width with it, and
254
+ * the result still looks like a correct label.
255
+ */
256
+ export function PrintScaleWarning() {
257
+ return (_jsx(Text, { size: "sm", color: "warning", className: "no-print", children: "Print at 100% / \u201CActual size\u201D. Any scaling \u2014 including \u201CFit to page\u201D \u2014 narrows the barcode below what scanners read, and the label will still look correct." }));
258
+ }
@@ -0,0 +1,46 @@
1
+ /*
2
+ * Print-layout classes for physical labels and printable documents.
3
+ *
4
+ * 🛑 THESE LIVE IN A STATIC STYLESHEET, NOT ONLY IN `labelPageCss`'s STRING.
5
+ *
6
+ * `labelPageCss()` and `documentPageCss()` emit an `@page` rule plus these
7
+ * same `break-*` declarations into a runtime `<style>`. That is necessary for
8
+ * `@page` — its `size` is computed from the chosen profile, so it cannot be
9
+ * static — but it meant `.appkit-label` and `.appkit-label-sheet` existed
10
+ * ONLY inside a template literal.
11
+ *
12
+ * Consequence: `audit-dead-css-classes` reported them as classes generating no
13
+ * CSS rule, correctly, because nothing it can read defines them. A class whose
14
+ * only definition is a string concatenation is invisible to every tool — the
15
+ * audit, an editor's go-to-definition, and anyone grepping the stylesheets.
16
+ * Declaring them here makes them real; the runtime string still carries its
17
+ * own copy because a print view may be opened in a context where the bundled
18
+ * stylesheet has not loaded, and a duplicated `break-inside: avoid` is
19
+ * harmless where a missing one splits a label across two pages.
20
+ *
21
+ * @tag domain:print
22
+ * @tag layer:feature
23
+ */
24
+
25
+ @media print {
26
+ /*
27
+ * A label must never be split across a page boundary. On thermal stock a
28
+ * page IS a label, so a split would print the top half on one label and the
29
+ * bottom half on the next — and the operator discovers it after both have
30
+ * been peeled and stuck to something.
31
+ */
32
+ .appkit-label {
33
+ break-inside: avoid;
34
+ page-break-inside: avoid;
35
+ }
36
+
37
+ /*
38
+ * A sheet is one A4 page of die-cut labels, or one contents sheet. Same
39
+ * rule, different unit — splitting it would offset every label after the
40
+ * break from its die-cut hole.
41
+ */
42
+ .appkit-label-sheet {
43
+ break-inside: avoid;
44
+ page-break-inside: avoid;
45
+ }
46
+ }
@@ -0,0 +1,6 @@
1
+ export { LabelPageStyle, LabelSheet, ProductLabel, BoxLabel, BoxContentsSheet, PrintScaleWarning, mmToCssPx, moduleWidthPx, } from "./components/labels";
2
+ export type { ProductLabelData, BoxLabelData, BoxContentsRow, } from "./components/labels";
3
+ export { LabelProfilePicker } from "./components/LabelProfilePicker";
4
+ export type { LabelProfilePickerProps } from "./components/LabelProfilePicker";
5
+ export { BoxLabelPrintView } from "./components/BoxLabelPrintView";
6
+ export type { BoxLabelPrintViewProps, PrintableBox, } from "./components/BoxLabelPrintView";
@@ -0,0 +1,16 @@
1
+ /*
2
+ * The print feature's surface — physical labels and printable documents.
3
+ *
4
+ * Everything here is a Client Component or a pure isomorphic helper, so unlike
5
+ * `features/inventory` there is no `firebase-admin` reachability hazard. It is
6
+ * still not re-exported from `appkit/src/index.ts`: nothing in the consumer
7
+ * imports it through a barrel, and adding a re-export for convenience is what
8
+ * Root Cause #18 is about.
9
+ *
10
+ * @tag domain:print
11
+ * @tag layer:feature
12
+ * @tag access:client
13
+ */
14
+ export { LabelPageStyle, LabelSheet, ProductLabel, BoxLabel, BoxContentsSheet, PrintScaleWarning, mmToCssPx, moduleWidthPx, } from "./components/labels.js";
15
+ export { LabelProfilePicker } from "./components/LabelProfilePicker.js";
16
+ export { BoxLabelPrintView } from "./components/BoxLabelPrintView.js";
@@ -1,13 +1,14 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Button, Div, GatedPrice, Row, Span } from "../../../ui/index.js";
3
3
  import { MediaImage } from "../../media/MediaImage.js";
4
+ import { statusLabel } from "../../../ui/columns/cell-renderers.js";
4
5
  import { formatCurrency as defaultFormatCurrency } from "../../../utils/number.formatter.js";
5
6
  const __O = {
6
7
  hidden: "overflow-hidden",
7
8
  };
8
9
  const STATUS_STYLES = {
9
10
  published: "bg-success-surface text-success dark:bg-success-surface dark:text-success",
10
- draft: "bg-[var(--appkit-color-surface)] bg-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)]",
11
+ draft: "bg-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)]",
11
12
  out_of_stock: "bg-warning-surface text-warning dark:bg-warning-surface dark:text-warning",
12
13
  discontinued: "bg-error-surface text-error dark:bg-error-surface dark:text-error",
13
14
  sold: "bg-primary/10 dark:bg-primary/20 text-primary",
@@ -54,8 +55,8 @@ export function getProductTableColumns({ labels, onEdit, onDelete, currencyCode,
54
55
  return (_jsx(Span, { className: [
55
56
  "rounded px-[var(--appkit-space-2)] py-[var(--appkit-space-1)] text-[length:var(--appkit-text-xs)] font-medium",
56
57
  STATUS_STYLES[status] ??
57
- "bg-[var(--appkit-color-surface)] bg-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)]",
58
- ].join(" "), children: status.replace("_", " ") }));
58
+ "bg-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)]",
59
+ ].join(" "), children: statusLabel(status) }));
59
60
  },
60
61
  },
61
62
  {
@@ -76,7 +77,7 @@ export function getProductTableColumns({ labels, onEdit, onDelete, currencyCode,
76
77
  "rounded px-[var(--appkit-space-2)] py-[var(--appkit-space-1)] text-[length:var(--appkit-text-xs)] font-medium",
77
78
  featured
78
79
  ? CLS_LOW_STOCK
79
- : "bg-[var(--appkit-color-surface)] bg-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)]",
80
+ : "bg-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)]",
80
81
  ].join(" "), children: featured ? labels.yes : labels.no }));
81
82
  },
82
83
  },
@@ -50,7 +50,7 @@ export function MarketplaceBundleCard({ bundle, className = "", variant = "grid"
50
50
  }
51
51
  router.push(String(detailHref));
52
52
  }, [detailHref, onNavigate, router]);
53
- const card = (_jsxs(BaseListingCard, { isSelected: isSelected, variant: variant, className: className, onMouseDown: !isSelected ? longPress.onMouseDown : undefined, onMouseUp: !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: !isSelected ? longPress.onTouchEnd : undefined, onTouchCancel: !isSelected ? longPress.onTouchCancel : undefined, children: [_jsxs(BaseListingCard.Hero, { aspect: "square", variant: variant, children: [_jsx(TextLink, { href: String(detailHref), className: "absolute inset-0 block", children: showCollage ? (_jsx(Div, { layout: "grid", className: `h-full w-full gap-[0.125rem] bg-[var(--appkit-color-surface-muted)] ${collageTiles.length === 2 ? "grid-cols-2 grid-rows-1" : "grid-cols-2 grid-rows-2"}`, children: collageTiles.map((tile, i) => (_jsxs(Div, { className: "relative overflow-hidden bg-[var(--appkit-color-surface-muted)]", children: [_jsx(MediaImage, { src: tile.imageURL, alt: tile.title ?? `${bundle.name} item ${i + 1}`, size: "card" }), i === collageTiles.length - 1 && overflow > 0 && (_jsxs(Row, { textWeight: "semibold", textSize: "sm", surface: "overlay-md", className: "absolute inset-0 text-white", align: "center", justify: "center", children: ["+", overflow] }))] }, `${tile.productId}-${i}`))) })) : cover ? (_jsx(Div, { className: "absolute inset-0 bg-[var(--appkit-color-surface-muted)]", children: _jsx(MediaImage, { src: cover, alt: bundle.name, size: "card" }) })) : (_jsx(Row, { className: "absolute inset-0 bg-[var(--appkit-color-surface-muted)]", align: "center", justify: "center", children: _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "xs", children: "No image" }) })) }), discount && (_jsx(PricesOnly, { children: _jsx(Span, { size: "xs", weight: "bold", className: "absolute left-2 top-2 bg-success-solid text-success-on-solid", rounded: "full", padding: "pill-xs", children: BUNDLE_COPY.detail.discountBadge(discount.percent) }) })), _jsxs(Stack, { className: "absolute right-2 top-2", align: "end", gap: "xs", children: [_jsx(Span, { size: "xs", weight: "medium", className: CLS_BUNDLE_PILL, children: mergedLabels.bundleBadge }), _jsx(Span, { layout: "inline-flex", color: "inverse", className: `${stock === "out_of_stock" ? "bg-neutral-500 " : CLS_STOCK_OK}`, rounded: "full", padding: "pill-xs", size: "xs", weight: "medium", children: stock === "out_of_stock" ? mergedLabels.outOfStockBadge : mergedLabels.inStockBadge })] }), stock === "out_of_stock" && (_jsx(Row, { surface: "overlay-xs", className: "absolute inset-0", align: "center", justify: "center", children: _jsx(Span, { color: "inverse", size: "xs", weight: "bold", className: "bg-neutral-900/80 tracking-wider", rounded: "default", padding: "pill-md", transform: "uppercase", children: mergedLabels.outOfStockBadge }) })), onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (event) => {
53
+ const card = (_jsxs(BaseListingCard, { isSelected: isSelected, variant: variant, className: className, onMouseDown: !isSelected ? longPress.onMouseDown : undefined, onMouseUp: !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: !isSelected ? longPress.onTouchEnd : undefined, onTouchCancel: !isSelected ? longPress.onTouchCancel : undefined, children: [_jsxs(BaseListingCard.Hero, { aspect: "square", variant: variant, children: [_jsx(TextLink, { href: String(detailHref), className: "absolute inset-0 block", children: showCollage ? (_jsx(Div, { layout: "grid", className: `h-full w-full gap-[0.125rem] bg-[var(--appkit-color-bg)] ${collageTiles.length === 2 ? "grid-cols-2 grid-rows-1" : "grid-cols-2 grid-rows-2"}`, children: collageTiles.map((tile, i) => (_jsxs(Div, { className: "relative overflow-hidden bg-[var(--appkit-color-bg)]", children: [_jsx(MediaImage, { src: tile.imageURL, alt: tile.title ?? `${bundle.name} item ${i + 1}`, size: "card" }), i === collageTiles.length - 1 && overflow > 0 && (_jsxs(Row, { textWeight: "semibold", textSize: "sm", surface: "overlay-md", className: "absolute inset-0 text-white", align: "center", justify: "center", children: ["+", overflow] }))] }, `${tile.productId}-${i}`))) })) : cover ? (_jsx(Div, { className: "absolute inset-0 bg-[var(--appkit-color-bg)]", children: _jsx(MediaImage, { src: cover, alt: bundle.name, size: "card" }) })) : (_jsx(Row, { className: "absolute inset-0 bg-[var(--appkit-color-bg)]", align: "center", justify: "center", children: _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "xs", children: "No image" }) })) }), discount && (_jsx(PricesOnly, { children: _jsx(Span, { size: "xs", weight: "bold", className: "absolute left-2 top-2 bg-success-solid text-success-on-solid", rounded: "full", padding: "pill-xs", children: BUNDLE_COPY.detail.discountBadge(discount.percent) }) })), _jsxs(Stack, { className: "absolute right-2 top-2", align: "end", gap: "xs", children: [_jsx(Span, { size: "xs", weight: "medium", className: CLS_BUNDLE_PILL, children: mergedLabels.bundleBadge }), _jsx(Span, { layout: "inline-flex", color: "inverse", className: `${stock === "out_of_stock" ? "bg-neutral-500 " : CLS_STOCK_OK}`, rounded: "full", padding: "pill-xs", size: "xs", weight: "medium", children: stock === "out_of_stock" ? mergedLabels.outOfStockBadge : mergedLabels.inStockBadge })] }), stock === "out_of_stock" && (_jsx(Row, { surface: "overlay-xs", className: "absolute inset-0", align: "center", justify: "center", children: _jsx(Span, { color: "inverse", size: "xs", weight: "bold", className: "bg-neutral-900/80 tracking-wider", rounded: "default", padding: "pill-md", transform: "uppercase", children: mergedLabels.outOfStockBadge }) })), onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (event) => {
54
54
  event.stopPropagation();
55
55
  onSelect(bundle.id, !isSelected);
56
56
  }, className: selectable || isSelected
@@ -77,5 +77,5 @@ export function MarketplaceBundleCard({ bundle, className = "", variant = "grid"
77
77
  * Sibling of the card, never a child — see the prop's docstring. `z-20`
78
78
  * clears this card's own overlays, which all sit at `z-10`.
79
79
  */
80
- return (_jsxs(Div, { className: "relative h-full", children: [card, _jsx(Div, { className: "absolute right-2 top-2 z-20", children: ownerActions })] }));
80
+ return (_jsxs(Div, { className: "flex h-full flex-col", children: [card, _jsx(Div, { className: "flex justify-end px-[var(--appkit-space-3)] pb-[var(--appkit-space-3)]", children: ownerActions })] }));
81
81
  }
@@ -11,7 +11,7 @@ const CLS_PRIZE_PILL = "inline-flex items-center rounded-full bg-fuchsia-600 px-
11
11
  import { BaseListingCard, Button, Div, GatedPrice, Row, Span, Stack, Text, TextLink } from "../../../ui/index.js";
12
12
  import { MediaImage } from "../../media/MediaImage.js";
13
13
  import { CardStoreLine } from "./CardStoreLine.js";
14
- import { ProductOwnerQuickActions } from "./ProductOwnerQuickActions.js";
14
+ import { RecordOwnerQuickActions } from "../../admin/components/RecordOwnerQuickActions.js";
15
15
  const DEFAULT_LABELS = {
16
16
  prizeDrawBadge: "Prize draw",
17
17
  pendingBadge: "Reveal pending",
@@ -91,11 +91,11 @@ export function MarketplacePrizeDrawCard({ product, className = "", variant = "g
91
91
  }
92
92
  router.push(String(detailHref));
93
93
  }, [detailHref, onNavigate, router]);
94
- const card = (_jsxs(BaseListingCard, { isSelected: isSelected, variant: variant, className: className, onMouseDown: !isSelected ? longPress.onMouseDown : undefined, onMouseUp: !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: !isSelected ? longPress.onTouchEnd : undefined, onTouchCancel: !isSelected ? longPress.onTouchCancel : undefined, children: [_jsxs(BaseListingCard.Hero, { aspect: "square", variant: variant, children: [_jsx(TextLink, { href: String(detailHref), className: "absolute inset-0 block", children: thumbItems.length > 0 ? (_jsx(Div, { layout: "grid", className: "grid-cols-2 grid-rows-2 gap-[0.125rem] h-full w-full bg-[var(--appkit-color-surface-muted)]", children: Array.from({ length: 4 }).map((_, i) => {
94
+ const card = (_jsxs(BaseListingCard, { isSelected: isSelected, variant: variant, className: className, onMouseDown: !isSelected ? longPress.onMouseDown : undefined, onMouseUp: !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: !isSelected ? longPress.onTouchEnd : undefined, onTouchCancel: !isSelected ? longPress.onTouchCancel : undefined, children: [_jsxs(BaseListingCard.Hero, { aspect: "square", variant: variant, children: [_jsx(TextLink, { href: String(detailHref), className: "absolute inset-0 block", children: thumbItems.length > 0 ? (_jsx(Div, { layout: "grid", className: "grid-cols-2 grid-rows-2 gap-[0.125rem] h-full w-full bg-[var(--appkit-color-bg)]", children: Array.from({ length: 4 }).map((_, i) => {
95
95
  const it = thumbItems[i];
96
96
  const img = it?.images?.[0];
97
- return (_jsx(Div, { className: "relative overflow-hidden bg-[var(--appkit-color-surface-muted)]", children: img ? (_jsx(MediaImage, { src: img, alt: it?.title ?? `Prize ${i + 1}`, size: "card" })) : null }, `thumb-${i}`));
98
- }) })) : (_jsx(Row, { className: "absolute inset-0 bg-[var(--appkit-color-surface-muted)]", align: "center", justify: "center", children: _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "xs", children: "No prizes" }) })) }), _jsxs(Stack, { className: "absolute right-2 top-2", align: "end", gap: "xs", children: [_jsx(Span, { size: "xs", weight: "medium", className: CLS_PRIZE_PILL, children: mergedLabels.prizeDrawBadge }), _jsx(Span, { layout: "inline-flex", size: "xs", weight: "medium", className: `${statusVariant(status)}`, rounded: "full", padding: "pill-xs", children: statusLabel(status, mergedLabels) })] }), status === "closed" ? (_jsx(Row, { surface: "overlay-xs", className: "absolute inset-0", align: "center", justify: "center", children: _jsx(Span, { color: "inverse", size: "xs", weight: "bold", className: "bg-neutral-900/80 tracking-wider", rounded: "default", padding: "pill-md", transform: "uppercase", children: mergedLabels.closedBadge }) })) : null, onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (event) => {
97
+ return (_jsx(Div, { className: "relative overflow-hidden bg-[var(--appkit-color-bg)]", children: img ? (_jsx(MediaImage, { src: img, alt: it?.title ?? `Prize ${i + 1}`, size: "card" })) : null }, `thumb-${i}`));
98
+ }) })) : (_jsx(Row, { className: "absolute inset-0 bg-[var(--appkit-color-bg)]", align: "center", justify: "center", children: _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "xs", children: "No prizes" }) })) }), _jsxs(Stack, { className: "absolute right-2 top-2", align: "end", gap: "xs", children: [_jsx(Span, { size: "xs", weight: "medium", className: CLS_PRIZE_PILL, children: mergedLabels.prizeDrawBadge }), _jsx(Span, { layout: "inline-flex", size: "xs", weight: "medium", className: `${statusVariant(status)}`, rounded: "full", padding: "pill-xs", children: statusLabel(status, mergedLabels) })] }), status === "closed" ? (_jsx(Row, { surface: "overlay-xs", className: "absolute inset-0", align: "center", justify: "center", children: _jsx(Span, { color: "inverse", size: "xs", weight: "bold", className: "bg-neutral-900/80 tracking-wider", rounded: "default", padding: "pill-md", transform: "uppercase", children: mergedLabels.closedBadge }) })) : null, onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (event) => {
99
99
  event.stopPropagation();
100
100
  onSelect(product.id, !isSelected);
101
101
  }, className: selectable || isSelected
@@ -111,7 +111,7 @@ export function MarketplacePrizeDrawCard({ product, className = "", variant = "g
111
111
  const ownerActions = renderOwnerActions
112
112
  ? renderOwnerActions()
113
113
  : product.id
114
- ? (_jsx(ProductOwnerQuickActions, { productId: String(product.id), storeId: product.storeId ? String(product.storeId) : undefined, recordLabel: product.title, placement: "card" }))
114
+ ? (_jsx(RecordOwnerQuickActions, { resource: "PRODUCT", recordId: String(product.id), storeId: product.storeId ? String(product.storeId) : undefined, recordLabel: product.title, placement: "card" }))
115
115
  : null;
116
116
  if (!ownerActions)
117
117
  return card;
@@ -119,5 +119,5 @@ export function MarketplacePrizeDrawCard({ product, className = "", variant = "g
119
119
  * Sibling of the card, never a child — see the prop's docstring. `z-20`
120
120
  * clears this card's own overlays, which all sit at `z-10`.
121
121
  */
122
- return (_jsxs(Div, { className: "relative h-full", children: [card, _jsx(Div, { className: "absolute right-2 top-2 z-20", children: ownerActions })] }));
122
+ return (_jsxs(Div, { className: "flex h-full flex-col", children: [card, _jsx(Div, { className: "flex justify-end px-[var(--appkit-space-3)] pb-[var(--appkit-space-3)]", children: ownerActions })] }));
123
123
  }
@@ -75,7 +75,7 @@ export function PrizeDrawCollage({ items, highlightItemNumber, onItemClick, wonL
75
75
  isHighlight
76
76
  ? "ring-2 ring-offset-2 ring-[var(--appkit-color-primary)] scale-[1.02]"
77
77
  : "hover:scale-[1.01]",
78
- ].join(" "), "aria-label": `View ${it.title || `prize #${it.itemNumber}`} in lightbox`, children: [_jsxs(Div, { className: "relative aspect-square w-full", children: [cover ? (_jsx(MediaImage, { src: cover, alt: it.title || `Prize #${it.itemNumber}`, size: "thumbnail" })) : (_jsx(Row, { className: "absolute inset-0 bg-[var(--appkit-color-surface-muted)]", align: "center", justify: "center", children: _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "xs", children: "No image" }) })), _jsxs(Div, { textWeight: "semibold", textSize: "xs", surface: "overlay-xl", padding: "chip-2xs", className: "absolute left-2 top-2 text-white", rounded: "default", children: ["#", it.itemNumber] }), it.isWon && !hideWonState ? (_jsxs(_Fragment, { children: [_jsx(Scrim, { direction: "diagonal", intensity: "medium", multiply: true, className: "absolute inset-0" }), _jsx(Row, { className: "absolute inset-0", align: "center", justify: "center", children: _jsx(Text, { className: CLS_WON_STAMP, children: wonLabel }) })] })) : null] }), _jsxs(Div, { padding: "xs", children: [_jsx(Text, { className: "line-clamp-2", size: "sm", weight: "medium", children: it.title || `Prize #${it.itemNumber}` }), it.estimatedValue != null ? (
78
+ ].join(" "), "aria-label": `View ${it.title || `prize #${it.itemNumber}`} in lightbox`, children: [_jsxs(Div, { className: "relative aspect-square w-full", children: [cover ? (_jsx(MediaImage, { src: cover, alt: it.title || `Prize #${it.itemNumber}`, size: "thumbnail" })) : (_jsx(Row, { className: "absolute inset-0 bg-[var(--appkit-color-bg)]", align: "center", justify: "center", children: _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "xs", children: "No image" }) })), _jsxs(Div, { textWeight: "semibold", textSize: "xs", surface: "overlay-xl", padding: "chip-2xs", className: "absolute left-2 top-2 text-white", rounded: "default", children: ["#", it.itemNumber] }), it.isWon && !hideWonState ? (_jsxs(_Fragment, { children: [_jsx(Scrim, { direction: "diagonal", intensity: "medium", multiply: true, className: "absolute inset-0" }), _jsx(Row, { className: "absolute inset-0", align: "center", justify: "center", children: _jsx(Text, { className: CLS_WON_STAMP, children: wonLabel }) })] })) : null] }), _jsxs(Div, { padding: "xs", children: [_jsx(Text, { className: "line-clamp-2", size: "sm", weight: "medium", children: it.title || `Prize #${it.itemNumber}` }), it.estimatedValue != null ? (
79
79
  // The prize's estimated value is a money amount like any
80
80
  // other — hidden rather than prompted, because the entry
81
81
  // price beside it already carries the sign-in gate.
@@ -95,7 +95,7 @@ export function PrizeDrawItemsEditor({ items, onChange, onUploadImage, onUploadV
95
95
  }), disabled: locked, placeholder: "2999" }) })] }), _jsxs(Stack, { gap: "xs", children: [_jsxs(Text, { size: "sm", weight: "medium", children: ["Images (", (it.images ?? []).length, "/", MAX_IMAGES_PER_ITEM, ")"] }), _jsx(Row, { gap: "sm", wrap: true, children: Array.from({ length: MAX_IMAGES_PER_ITEM }).map((_, slot) => {
96
96
  const existing = (it.images ?? [])[slot];
97
97
  return (_jsxs(Div, { className: "w-40", children: [_jsx(ImageUpload, { currentImage: existing, label: existing ? "Replace" : `Image ${slot + 1}`, onUpload: (file) => onUploadImage(file, it.itemNumber), onChange: (url) => setImage(index, slot, url) }), existing && !locked ? (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => removeImage(index, slot), children: "Remove" })) : null] }, slot));
98
- }) })] }), onUploadVideo ? (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "medium", children: "Video (optional)" }), _jsx(Input, { bare: true, type: "file", accept: "video/*", disabled: locked, onChange: (e) => handleVideoFileChange(e, index, it.itemNumber) }), it.video?.url ? (_jsxs(Text, { className: "text-[var(--appkit-color-text-muted)] truncate", size: "xs", children: ["Current: ", it.video.url] })) : null] })) : null] })] }, `prize-item-${it.itemNumber}-${index}`));
98
+ }) })] }), onUploadVideo ? (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "medium", children: "Video (optional)" }), _jsx(Input, { bare: true, "aria-label": `Video for item ${it.itemNumber} (optional)`, type: "file", accept: "video/*", disabled: locked, onChange: (e) => handleVideoFileChange(e, index, it.itemNumber) }), it.video?.url ? (_jsxs(Text, { className: "text-[var(--appkit-color-text-muted)] truncate", size: "xs", children: ["Current: ", it.video.url] })) : null] })) : null] })] }, `prize-item-${it.itemNumber}-${index}`));
99
99
  }) }), items.length < MIN_ITEMS ? (_jsxs(Div, { textSize: "sm", className: "border border-error/40", color: "error", surface: "danger-surface", padding: "inlineSm", rounded: "default", children: ["At least ", MIN_ITEMS, " prizes are required."] })) : null] }));
100
100
  }
101
101
  export default PrizeDrawItemsEditor;
@@ -24,8 +24,8 @@ export function PrizeRevealModal({ open, onClose, items, initialPrizeWon, reveal
24
24
  const winnerImg = winner?.images?.[0];
25
25
  return (_jsx(Modal, { isOpen: open, onClose: onClose, title: "Prize Reveal", size: "lg", children: _jsxs(Stack, { gap: "md", children: [_jsx(PrizeDrawCollage, { items: items, hideWonState: true }), !winner ? (
26
26
  // audit-content-alignment-ok: informational reveal-status panel, not marketing content
27
- _jsxs(Div, { className: `bg-[var(--appkit-color-surface-muted)] ${__P.p4} text-center`, rounded: "default", children: [_jsx(Text, { size: "lg", weight: "semibold", children: "Reveal pending" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: PENDING_COPY[revealMode] })] })) : (
27
+ _jsxs(Div, { className: `bg-[var(--appkit-color-bg)] ${__P.p4} text-center`, rounded: "default", children: [_jsx(Text, { size: "lg", weight: "semibold", children: "Reveal pending" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: PENDING_COPY[revealMode] })] })) : (
28
28
  // audit-content-alignment-ok: theatrical reveal-modal centerpiece, not marketing content
29
- _jsxs(Div, { className: `border-2 border-[var(--appkit-color-primary)] bg-[var(--appkit-color-surface)] ${__P.p4} text-center`, rounded: "lg", children: [_jsx(Text, { className: "tracking-wider text-[var(--appkit-color-text-muted)]", size: "xs", transform: "uppercase", children: "You won" }), _jsxs(Heading, { level: 2, className: "my-2", children: ["#", winner.itemNumber, " \u2014 ", winner.title] }), winnerImg ? (_jsx(Div, { className: "relative mx-auto h-64 w-64 max-w-full", rounded: "md", overflow: "hidden", children: _jsx(MediaImage, { src: winnerImg, alt: winner.title, size: "hero", objectFit: "contain" }) })) : null, winner.estimatedValue != null ? (_jsx(PricesOnly, { children: _jsxs(Text, { className: "mt-2 text-[var(--appkit-color-text-muted)]", size: "sm", children: ["Estimated value: \u20B9", winner.estimatedValue.toLocaleString("en-IN")] }) })) : null] })), _jsxs(Div, { textSize: "xs", className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-muted)] text-[var(--appkit-color-text-muted)]", padding: "inlineSm", rounded: "default", children: [_jsx(Span, { weight: "bold", children: "Fairness guarantee:" }), " ", "Winners are picked by ", _jsx("code", { children: "crypto.randomInt" }), " running on LetItRip's server the moment your prize is assigned. Neither the store nor LetItRip staff can influence the outcome.", " ", rngSourceUrl ? (_jsx(Anchor, { href: rngSourceUrl, tone: "none", underline: "always", children: "View RNG source code \u2192" })) : null] })] }) }));
29
+ _jsxs(Div, { className: `border-2 border-[var(--appkit-color-primary)] bg-[var(--appkit-color-surface)] ${__P.p4} text-center`, rounded: "lg", children: [_jsx(Text, { className: "tracking-wider text-[var(--appkit-color-text-muted)]", size: "xs", transform: "uppercase", children: "You won" }), _jsxs(Heading, { level: 2, className: "my-2", children: ["#", winner.itemNumber, " \u2014 ", winner.title] }), winnerImg ? (_jsx(Div, { className: "relative mx-auto h-64 w-64 max-w-full", rounded: "md", overflow: "hidden", children: _jsx(MediaImage, { src: winnerImg, alt: winner.title, size: "hero", objectFit: "contain" }) })) : null, winner.estimatedValue != null ? (_jsx(PricesOnly, { children: _jsxs(Text, { className: "mt-2 text-[var(--appkit-color-text-muted)]", size: "sm", children: ["Estimated value: \u20B9", winner.estimatedValue.toLocaleString("en-IN")] }) })) : null] })), _jsxs(Div, { textSize: "xs", className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-bg)] text-[var(--appkit-color-text-muted)]", padding: "inlineSm", rounded: "default", children: [_jsx(Span, { weight: "bold", children: "Fairness guarantee:" }), " ", "Winners are picked by ", _jsx("code", { children: "crypto.randomInt" }), " running on LetItRip's server the moment your prize is assigned. Neither the store nor LetItRip staff can influence the outcome.", " ", rngSourceUrl ? (_jsx(Anchor, { href: rngSourceUrl, tone: "none", underline: "always", children: "View RNG source code \u2192" })) : null] })] }) }));
30
30
  }
31
31
  export default PrizeRevealModal;
@@ -31,7 +31,7 @@ import { ctaAnchorProps } from "../../layout/cta-anchor.js";
31
31
  import { ContextualTrail } from "../../categories/components/ContextualTrail.js";
32
32
  import { productCrumbs, withTrailHead } from "../../categories/utils/breadcrumb-chain.js";
33
33
  import { getDefaultCurrency } from "../../../core/baseline-resolver.js";
34
- import { ProductOwnerQuickActions } from "./ProductOwnerQuickActions.js";
34
+ import { RecordOwnerQuickActions } from "../../admin/components/RecordOwnerQuickActions.js";
35
35
  import { PurchaseReviewAffordance } from "../../reviews/components/PurchaseReviewAffordance.js";
36
36
  import { Button, Container, Div, Heading, Main, PriceDisplay, RichText, Row, Section, Span, Stack, Text, Ul, Ol, Li, SpecTable, Icon, } from "../../../ui/index.js";
37
37
  import { normalizeRichTextHtml } from "../../../utils/string.formatter.js";
@@ -348,11 +348,25 @@ export async function ProductDetailPageView({ slug, initialProduct, renderOfferA
348
348
  const { relatedItems, relatedByBrand, relatedByTags, relatedByStore } = related;
349
349
  return (_jsxs(Main, { children: [_jsx(HistoryTracker, { productId: product.id, productType: "product", snapshot: {
350
350
  title: product.title,
351
- thumb: product.mainImage ?? product.images?.[0],
351
+ /*
352
+ * 🛑 `images` is `ProductImage[]`, not `string[]` — reading
353
+ * `product.images?.[0]` here wrote an OBJECT into the history
354
+ * snapshot, which `resolveMediaUrl` then refuses on every later
355
+ * render of `/user/history` ("expected a string, received
356
+ * [object Object]") and shows a placeholder for. The three sibling
357
+ * detail views (classified, digital-code, live) already use the
358
+ * derived `images` array for exactly this reason; this one was
359
+ * missed by the `string[]` -> `ProductImage[]` migration.
360
+ *
361
+ * `mainImage` stays first because it is the authored cover and is
362
+ * not part of the gallery array, so `images[0]` is a different
363
+ * picture whenever both exist.
364
+ */
365
+ thumb: typeof product.mainImage === "string" ? product.mainImage : images[0],
352
366
  price: product.price,
353
367
  storeId: product.storeId,
354
368
  storeName: product.storeName,
355
- } }), _jsxs(Container, { size: "xl", padding: "y-lg", children: [_jsx(ProductDetailView, { renderBreadcrumb: () => (_jsxs(Row, { className: "mb-4", align: "center", justify: "between", gap: "sm", wrap: true, children: [_jsx(ContextualTrail, { trails: trails, alternates: { ids: categoryIds, names: categoryIdNames } }), _jsx(ShareButton, { title: title || undefined })] })), renderGallery: () => (_jsx(ProductGalleryClient, { images: images, video: productVideo, productName: title || undefined })), renderInfo: () => (_jsxs(Stack, { gap: "md", children: [_jsx(ProductOwnerQuickActions, { productId: String(product.id), recordLabel: title || String(product.slug ?? product.id), storeId: product.storeId ? String(product.storeId) : undefined }), _jsxs(Div, { children: [condition && (_jsx(Span, { size: "xs", weight: "medium", className: "mb-2 inline-block", padding: "pill-sm", rounded: "full", surface: "subtle", color: "muted", transform: "capitalize", children: condition === "new"
369
+ } }), _jsxs(Container, { size: "xl", padding: "y-lg", children: [_jsx(ProductDetailView, { renderBreadcrumb: () => (_jsxs(Row, { className: "mb-4", align: "center", justify: "between", gap: "sm", wrap: true, children: [_jsx(ContextualTrail, { trails: trails, alternates: { ids: categoryIds, names: categoryIdNames } }), _jsx(ShareButton, { title: title || undefined })] })), renderGallery: () => (_jsx(ProductGalleryClient, { images: images, video: productVideo, productName: title || undefined })), renderInfo: () => (_jsxs(Stack, { gap: "md", children: [_jsx(RecordOwnerQuickActions, { resource: "PRODUCT", recordId: String(product.id), recordLabel: title || String(product.slug ?? product.id), storeId: product.storeId ? String(product.storeId) : undefined }), _jsxs(Div, { children: [condition && (_jsx(Span, { size: "xs", weight: "medium", className: "mb-2 inline-block", padding: "pill-sm", rounded: "full", surface: "subtle", color: "muted", transform: "capitalize", children: condition === "new"
356
370
  ? "Brand New"
357
371
  : condition === "like_new"
358
372
  ? "Like New"
@@ -360,7 +374,7 @@ export async function ProductDetailPageView({ slug, initialProduct, renderOfferA
360
374
  ? "Refurbished"
361
375
  : condition === "used"
362
376
  ? "Used"
363
- : condition })), _jsx(Heading, { level: 1, className: "leading-snug", smSize: "2xl", color: "primary", size: "xl", weight: "bold", children: title || "Untitled Product" })] }), avgRating !== null ? (_jsxs(Row, { align: "center", gap: "sm", children: [_jsx(StarRating, { value: avgRating }), _jsxs(Span, { size: "sm", color: "muted", children: [avgRating.toFixed(1), reviewCount ? ` (${reviewCount} reviews)` : ""] }), showViews && (_jsxs(Span, { size: "sm", color: "muted", children: ["\u00B7 ", views7d.toLocaleString(), " viewed this week"] })), _jsxs(Span, { size: "xs", weight: "medium", surface: inStock ? "success-surface" : "danger-surface", className: `ml-auto ${inStock ? "text-success" : "text-error"}`, padding: "pill-sm", rounded: "full", children: [madeToOrder
377
+ : condition })), _jsx(Heading, { level: 1, className: "leading-snug", smSize: "2xl", color: "primary", size: "xl", weight: "bold", children: title || "Untitled Product" })] }), avgRating !== null && (reviewCount ?? 0) > 0 ? (_jsxs(Row, { align: "center", gap: "sm", children: [_jsx(StarRating, { value: avgRating }), _jsxs(Span, { size: "sm", color: "muted", children: [avgRating.toFixed(1), reviewCount ? ` (${reviewCount} reviews)` : ""] }), showViews && (_jsxs(Span, { size: "sm", color: "muted", children: ["\u00B7 ", views7d.toLocaleString(), " viewed this week"] })), _jsxs(Span, { size: "xs", weight: "medium", surface: inStock ? "success-surface" : "danger-surface", className: `ml-auto ${inStock ? "text-success" : "text-error"}`, padding: "pill-sm", rounded: "full", children: [madeToOrder
364
378
  ? "✓ Made to order"
365
379
  : inStock
366
380
  ? "✓ In Stock"