@mohasinac/appkit 4.10.0 → 4.11.1

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 (324) hide show
  1. package/dist/_internal/client/features/layout/DashboardLayoutClient.d.ts +6 -1
  2. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +4 -1
  3. package/dist/_internal/client/features/lottery/LotteryPullForm.d.ts +1 -1
  4. package/dist/_internal/client/features/lottery/LotteryPullForm.js +2 -2
  5. package/dist/_internal/server/features/admin/daily-digest-actions.d.ts +18 -0
  6. package/dist/_internal/server/features/admin/daily-digest-actions.js +37 -0
  7. package/dist/_internal/server/features/audit-log/actions.d.ts +25 -0
  8. package/dist/_internal/server/features/audit-log/actions.js +38 -0
  9. package/dist/_internal/server/features/brands/actions.js +0 -2
  10. package/dist/_internal/server/features/brands/og.d.ts +4 -1
  11. package/dist/_internal/server/features/brands/og.js +1 -1
  12. package/dist/_internal/server/features/grouped/data.d.ts +4 -0
  13. package/dist/_internal/server/features/grouped/data.js +24 -0
  14. package/dist/_internal/server/features/grouped/index.d.ts +1 -1
  15. package/dist/_internal/server/features/grouped/index.js +1 -1
  16. package/dist/_internal/server/features/orders/actions.js +9 -0
  17. package/dist/_internal/server/features/orders/adapters.js +25 -0
  18. package/dist/_internal/server/features/products/data.d.ts +2 -2
  19. package/dist/_internal/server/features/products/data.js +5 -23
  20. package/dist/_internal/server/functions/scheduled.d.ts +3 -1
  21. package/dist/_internal/server/functions/scheduled.js +17 -1
  22. package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +40 -0
  23. package/dist/_internal/server/jobs/core/dailyStatusDigest.js +164 -0
  24. package/dist/_internal/server/jobs/core/hardBanCascade.js +11 -0
  25. package/dist/_internal/server/jobs/core/testerSandboxCleanup.d.ts +1 -0
  26. package/dist/_internal/server/jobs/core/testerSandboxCleanup.js +4 -1
  27. package/dist/_internal/server/jobs/core/testerSandboxRefresh.d.ts +12 -0
  28. package/dist/_internal/server/jobs/core/testerSandboxRefresh.js +85 -0
  29. package/dist/_internal/server/jobs/core/whatsappNotify.js +16 -0
  30. package/dist/_internal/server/jobs/handlers/dailyStatusDigest.d.ts +2 -0
  31. package/dist/_internal/server/jobs/handlers/dailyStatusDigest.js +4 -0
  32. package/dist/_internal/server/jobs/handlers/index.d.ts +2 -0
  33. package/dist/_internal/server/jobs/handlers/index.js +3 -0
  34. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.d.ts +2 -0
  35. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.js +2 -0
  36. package/dist/_internal/server/notifications/channel-health.d.ts +27 -0
  37. package/dist/_internal/server/notifications/channel-health.js +101 -0
  38. package/dist/_internal/shared/features/brands/schema.d.ts +0 -6
  39. package/dist/_internal/shared/features/brands/schema.js +0 -1
  40. package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +7 -0
  41. package/dist/_internal/shared/features/categories/bundle-schemas.js +3 -0
  42. package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
  43. package/dist/_internal/shared/features/products/to-product-item.d.ts +25 -0
  44. package/dist/_internal/shared/features/products/to-product-item.js +45 -0
  45. package/dist/client.d.ts +21 -6
  46. package/dist/client.js +13 -3
  47. package/dist/constants/api-endpoints.d.ts +6 -9
  48. package/dist/constants/api-endpoints.js +2 -3
  49. package/dist/contracts/client-auth.d.ts +3 -7
  50. package/dist/contracts/email.d.ts +1 -0
  51. package/dist/features/account/components/AddressForm.js +24 -2
  52. package/dist/features/account/components/BecomeSellerView.d.ts +1 -2
  53. package/dist/features/account/components/BecomeSellerView.js +1 -1
  54. package/dist/features/account/components/NotificationBell.js +1 -1
  55. package/dist/features/account/components/UserBidsView.d.ts +1 -0
  56. package/dist/features/account/components/UserBidsView.js +47 -0
  57. package/dist/features/account/components/UserOrdersView.d.ts +4 -11
  58. package/dist/features/account/components/UserOrdersView.js +54 -4
  59. package/dist/features/account/components/UserReturnsView.d.ts +4 -9
  60. package/dist/features/account/components/UserReturnsView.js +37 -3
  61. package/dist/features/account/components/index.d.ts +3 -2
  62. package/dist/features/account/components/index.js +1 -0
  63. package/dist/features/admin/actions/admin-actions.js +22 -0
  64. package/dist/features/admin/actions/admin-coupon-actions.js +10 -0
  65. package/dist/features/admin/actions/notification-actions.js +4 -3
  66. package/dist/features/admin/components/AdminAdsView.d.ts +2 -3
  67. package/dist/features/admin/components/AdminAdsView.js +86 -89
  68. package/dist/features/admin/components/AdminAllEventEntriesView.js +18 -3
  69. package/dist/features/admin/components/AdminAuditLogView.d.ts +11 -0
  70. package/dist/features/admin/components/AdminAuditLogView.js +95 -0
  71. package/dist/features/admin/components/AdminBlogEditorView.js +37 -3
  72. package/dist/features/admin/components/AdminBrandEditorView.js +10 -6
  73. package/dist/features/admin/components/AdminBundleEditorView.js +18 -2
  74. package/dist/features/admin/components/AdminCarouselEditorView.js +2 -2
  75. package/dist/features/admin/components/AdminCarouselGroupEditorView.js +2 -2
  76. package/dist/features/admin/components/AdminCartsView.js +34 -4
  77. package/dist/features/admin/components/AdminCategoryEditorView.js +5 -4
  78. package/dist/features/admin/components/AdminCouponEditorView.js +2 -2
  79. package/dist/features/admin/components/AdminFaqEditorView.js +2 -2
  80. package/dist/features/admin/components/AdminHistoryView.js +11 -1
  81. package/dist/features/admin/components/AdminNotificationsView.js +27 -1
  82. package/dist/features/admin/components/AdminOrderEditorView.d.ts +10 -1
  83. package/dist/features/admin/components/AdminOrderEditorView.js +4 -3
  84. package/dist/features/admin/components/AdminOrdersView.js +92 -24
  85. package/dist/features/admin/components/AdminPayoutMarkPaidModal.d.ts +7 -0
  86. package/dist/features/admin/components/AdminPayoutMarkPaidModal.js +47 -0
  87. package/dist/features/admin/components/AdminPayoutsView.js +15 -31
  88. package/dist/features/admin/components/AdminProductEditorView.js +26 -3
  89. package/dist/features/admin/components/AdminSiteSettingsView.js +20 -1
  90. package/dist/features/admin/components/AdminStoreAddressesView.js +22 -2
  91. package/dist/features/admin/components/AdminStoresView.js +7 -0
  92. package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +2 -2
  93. package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +2 -2
  94. package/dist/features/admin/components/AdminUserEditorView.d.ts +2 -2
  95. package/dist/features/admin/components/AdminUserEditorView.js +4 -2
  96. package/dist/features/admin/components/AdminUsersView.js +1 -1
  97. package/dist/features/admin/components/AdminWishlistsView.js +14 -1
  98. package/dist/features/admin/components/DataListingView.d.ts +2 -2
  99. package/dist/features/admin/components/ViewAuditLogEntryModal.d.ts +19 -0
  100. package/dist/features/admin/components/ViewAuditLogEntryModal.js +22 -0
  101. package/dist/features/admin/components/ViewNotificationModal.d.ts +21 -0
  102. package/dist/features/admin/components/ViewNotificationModal.js +15 -0
  103. package/dist/features/admin/components/analytics/AdminPageViewsReportView.d.ts +4 -7
  104. package/dist/features/admin/components/analytics/AdminPageViewsReportView.js +56 -36
  105. package/dist/features/admin/components/index.d.ts +8 -1
  106. package/dist/features/admin/components/index.js +4 -0
  107. package/dist/features/admin/constants/filter-tabs.d.ts +49 -0
  108. package/dist/features/admin/constants/filter-tabs.js +27 -0
  109. package/dist/features/admin/hooks/useAdminListing.d.ts +6 -0
  110. package/dist/features/admin/hooks/useAdminListing.js +3 -1
  111. package/dist/features/admin/hooks/useAdminListingData.d.ts +9 -1
  112. package/dist/features/admin/hooks/useAdminListingData.js +9 -2
  113. package/dist/features/admin/repository/site-settings.repository.d.ts +5 -0
  114. package/dist/features/admin/schemas/firestore.d.ts +12 -0
  115. package/dist/features/analytics/types.d.ts +1 -1
  116. package/dist/features/analytics/types.js +8 -0
  117. package/dist/features/auctions/schemas/index.d.ts +5 -0
  118. package/dist/features/audit-log/repository/audit-log.repository.d.ts +45 -0
  119. package/dist/features/audit-log/repository/audit-log.repository.js +30 -0
  120. package/dist/features/audit-log/schemas/firestore.d.ts +59 -0
  121. package/dist/features/audit-log/schemas/firestore.js +35 -0
  122. package/dist/features/auth/actions/index.d.ts +0 -1
  123. package/dist/features/auth/actions/index.js +0 -1
  124. package/dist/features/auth/hooks/useAuth.d.ts +8 -35
  125. package/dist/features/auth/hooks/useAuth.js +21 -37
  126. package/dist/features/auth/permissions/constants.d.ts +1 -1
  127. package/dist/features/auth/permissions/constants.js +2 -0
  128. package/dist/features/blog/schemas/index.d.ts +32 -0
  129. package/dist/features/catalogue/components/AdminCatalogueApprovalsView.js +31 -3
  130. package/dist/features/catalogue/components/CatalogueItemEditorView.js +2 -1
  131. package/dist/features/categories/components/BrandDetailPageView.js +14 -12
  132. package/dist/features/categories/components/CategoryDetailPageView.js +7 -3
  133. package/dist/features/categories/components/CategoryHighlightsAndFaqSection.d.ts +14 -0
  134. package/dist/features/categories/components/CategoryHighlightsAndFaqSection.js +22 -0
  135. package/dist/features/categories/components/CategoryProductsView.d.ts +1 -5
  136. package/dist/features/categories/components/CategoryProductsView.js +1 -1
  137. package/dist/features/categories/components/CategorySelectorCreate.js +16 -2
  138. package/dist/features/categories/schemas/firestore.d.ts +19 -2
  139. package/dist/features/categories/schemas/index.d.ts +24 -3
  140. package/dist/features/categories/schemas/index.js +3 -1
  141. package/dist/features/categories/types/index.d.ts +7 -0
  142. package/dist/features/checkout/actions/checkout-value-otp-actions.d.ts +17 -3
  143. package/dist/features/checkout/actions/checkout-value-otp-actions.js +101 -22
  144. package/dist/features/contact/components/ContactForm.js +17 -4
  145. package/dist/features/contact/email.d.ts +1 -0
  146. package/dist/features/contact/email.js +3 -0
  147. package/dist/features/events/components/AdminEventEditorView.js +54 -2
  148. package/dist/features/events/components/AdminEventEntriesView.d.ts +2 -16
  149. package/dist/features/events/components/AdminEventEntriesView.js +56 -89
  150. package/dist/features/events/components/EventFormDrawer.js +5 -1
  151. package/dist/features/events/components/EventRaffleEntryForm.d.ts +1 -3
  152. package/dist/features/events/components/EventRaffleEntryForm.js +1 -1
  153. package/dist/features/events/schemas/index.d.ts +22 -0
  154. package/dist/features/grouped/components/GroupedListingsCarousel.js +4 -1
  155. package/dist/features/grouped/repository/grouped-listings.repository.d.ts +4 -0
  156. package/dist/features/grouped/repository/grouped-listings.repository.js +18 -0
  157. package/dist/features/homepage/components/CharacterHotspotForm.js +202 -187
  158. package/dist/features/homepage/components/SectionCarousel.d.ts +1 -7
  159. package/dist/features/homepage/components/SectionCarousel.js +1 -1
  160. package/dist/features/layout/TitleBarLayout.d.ts +1 -1
  161. package/dist/features/layout/TitleBarLayout.js +3 -3
  162. package/dist/features/media/MediaImage.js +39 -3
  163. package/dist/features/media/types/index.d.ts +10 -0
  164. package/dist/features/media/types/index.js +1 -0
  165. package/dist/features/media/upload/MediaUploadField.d.ts +7 -1
  166. package/dist/features/media/upload/MediaUploadField.js +11 -7
  167. package/dist/features/media/upload/video-poster.d.ts +2 -0
  168. package/dist/features/media/upload/video-poster.js +16 -1
  169. package/dist/features/media/upload/video-poster.test.js +1 -1
  170. package/dist/features/orders/components/OrderStatusTimeline.d.ts +12 -0
  171. package/dist/features/orders/components/OrderStatusTimeline.js +55 -0
  172. package/dist/features/orders/components/index.d.ts +2 -0
  173. package/dist/features/orders/components/index.js +1 -0
  174. package/dist/features/orders/constants/payment-window.d.ts +25 -0
  175. package/dist/features/orders/constants/payment-window.js +25 -0
  176. package/dist/features/orders/repository/orders.repository.d.ts +32 -0
  177. package/dist/features/orders/repository/orders.repository.js +56 -0
  178. package/dist/features/orders/schemas/index.d.ts +24 -24
  179. package/dist/features/orders/types/index.d.ts +33 -0
  180. package/dist/features/pre-orders/schemas/index.d.ts +5 -0
  181. package/dist/features/products/components/BidHistory.js +9 -1
  182. package/dist/features/products/components/GroupSettingsPanel.js +25 -3
  183. package/dist/features/products/components/PrizeDrawDetailPageView.js +1 -1
  184. package/dist/features/products/components/PrizeDrawEntryActions.d.ts +1 -4
  185. package/dist/features/products/components/PrizeDrawEntryActions.js +1 -1
  186. package/dist/features/products/components/ProductDetailActions.d.ts +1 -2
  187. package/dist/features/products/components/ProductDetailActions.js +1 -1
  188. package/dist/features/products/components/ProductGrid.js +15 -1
  189. package/dist/features/products/constants/action-defs.d.ts +1 -0
  190. package/dist/features/products/constants/action-defs.js +1 -0
  191. package/dist/features/products/schemas/index.d.ts +5 -0
  192. package/dist/features/promotions/components/CouponsIndexListing.d.ts +1 -3
  193. package/dist/features/promotions/components/CouponsIndexListing.js +1 -1
  194. package/dist/features/search/components/SearchView.d.ts +1 -3
  195. package/dist/features/search/components/SearchView.js +1 -1
  196. package/dist/features/seller/components/QuickProductForm.js +2 -1
  197. package/dist/features/seller/components/SellerBidsView.js +66 -107
  198. package/dist/features/seller/components/SellerGoogleReviewsView.js +17 -1
  199. package/dist/features/seller/components/SellerOrdersView.d.ts +15 -3
  200. package/dist/features/seller/components/SellerOrdersView.js +134 -163
  201. package/dist/features/seller/components/SellerPayoutMethodsView.js +60 -48
  202. package/dist/features/seller/components/SellerPayoutSettingsView.js +69 -4
  203. package/dist/features/seller/components/SellerPayoutsView.d.ts +12 -0
  204. package/dist/features/seller/components/SellerPayoutsView.js +25 -5
  205. package/dist/features/seller/components/SellerProductShell.d.ts +10 -3
  206. package/dist/features/seller/components/SellerProductShell.js +89 -36
  207. package/dist/features/seller/components/SellerProductsFilterDrawer.d.ts +2 -7
  208. package/dist/features/seller/components/SellerProductsFilterDrawer.js +4 -4
  209. package/dist/features/seller/components/SellerProductsView.d.ts +2 -4
  210. package/dist/features/seller/components/SellerProductsView.js +131 -189
  211. package/dist/features/seller/components/SellerReviewsView.js +95 -133
  212. package/dist/features/seller/components/SellerShippingConfigsView.js +47 -67
  213. package/dist/features/seller/components/SellerShippingView.js +41 -4
  214. package/dist/features/seller/components/SellerStoreCategoriesView.js +51 -59
  215. package/dist/features/seller/components/SellerStorefrontView.d.ts +6 -1
  216. package/dist/features/seller/components/SellerStorefrontView.js +42 -5
  217. package/dist/features/seller/components/index.d.ts +2 -2
  218. package/dist/features/seller/components/index.js +2 -2
  219. package/dist/features/shell/FormShell.d.ts +24 -4
  220. package/dist/features/shell/FormShell.js +12 -6
  221. package/dist/features/shell/QuickFormDrawer.js +67 -12
  222. package/dist/features/shell/StepForm.d.ts +30 -1
  223. package/dist/features/shell/StepForm.js +47 -4
  224. package/dist/features/shell/index.d.ts +1 -1
  225. package/dist/features/shell/index.js +1 -1
  226. package/dist/features/shipments/components/AdminShipmentEditorView.js +2 -2
  227. package/dist/features/shipments/schemas/validation.d.ts +14 -4
  228. package/dist/features/tester/components/AdminTesterFeedbackListView.js +23 -2
  229. package/dist/features/tester/components/TesterChecklistStepRow.js +1 -1
  230. package/dist/features/tester/components/TesterHubView.js +3 -2
  231. package/dist/features/tester/seed-data/orders-tester-seed-data.js +9 -1
  232. package/dist/features/tester/seed-data/products-tester-seed-data.js +43 -32
  233. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +404 -15
  234. package/dist/index.d.ts +15 -3
  235. package/dist/index.js +22 -5
  236. package/dist/next/routing/route-map.d.ts +11 -0
  237. package/dist/next/routing/route-map.js +5 -0
  238. package/dist/providers/email-resend/provider.js +1 -0
  239. package/dist/providers/firebase-client/auth.d.ts +1 -0
  240. package/dist/providers/firebase-client/auth.js +7 -1
  241. package/dist/repositories/index.d.ts +1 -0
  242. package/dist/repositories/index.js +1 -0
  243. package/dist/schemas/registry.d.ts +61 -25
  244. package/dist/security/pii-mask.js +1 -1
  245. package/dist/seed/categories-seed-data.js +69 -0
  246. package/dist/seed/products-auctions-seed-data.js +11 -0
  247. package/dist/seed/products-standard-seed-data.js +93 -4
  248. package/dist/seed/site-settings-seed-data.js +13 -1
  249. package/dist/seed/store-extensions-seed-data.js +1 -1
  250. package/dist/server-entry.d.ts +2 -1
  251. package/dist/server-entry.js +20 -2
  252. package/dist/server.d.ts +7 -2
  253. package/dist/server.js +8 -3
  254. package/dist/styles.css +1 -1
  255. package/dist/tailwind-utilities.css +1 -1
  256. package/dist/ui/components/Form.d.ts +11 -2
  257. package/dist/ui/components/Form.js +4 -3
  258. package/dist/ui/components/FormField.d.ts +3 -1
  259. package/dist/ui/components/FormField.js +22 -4
  260. package/dist/ui/components/ListingLayout.d.ts +1 -2
  261. package/dist/ui/components/ListingLayout.js +1 -1
  262. package/dist/ui/components/RecordDetailModal.d.ts +68 -0
  263. package/dist/ui/components/RecordDetailModal.js +8 -0
  264. package/dist/ui/components/SlottedListingView.js +9 -1
  265. package/dist/ui/forms/FormErrorSummary.d.ts +25 -0
  266. package/dist/ui/forms/FormErrorSummary.js +37 -0
  267. package/dist/ui/forms/FormShell.d.ts +37 -2
  268. package/dist/ui/forms/FormShell.js +37 -7
  269. package/dist/ui/forms/FormShell.style.css +17 -0
  270. package/dist/ui/forms/index.d.ts +2 -0
  271. package/dist/ui/forms/index.js +1 -0
  272. package/dist/ui/index.d.ts +4 -0
  273. package/dist/ui/index.js +5 -0
  274. package/dist/utils/media-url.d.ts +3 -1
  275. package/dist/utils/media-url.js +20 -1
  276. package/dist/validation/schemas.d.ts +4 -4
  277. package/package.json +1 -1
  278. package/dist/_internal/client/features/classified/ClassifiedDetailView.d.ts +0 -9
  279. package/dist/_internal/client/features/classified/ClassifiedDetailView.js +0 -55
  280. package/dist/_internal/client/features/digital-code/DigitalCodeDetailView.d.ts +0 -18
  281. package/dist/_internal/client/features/digital-code/DigitalCodeDetailView.js +0 -21
  282. package/dist/_internal/client/features/live/LiveItemDetailView.d.ts +0 -9
  283. package/dist/_internal/client/features/live/LiveItemDetailView.js +0 -25
  284. package/dist/_internal/server/jobs/core/prizeRevealClose.d.ts +0 -2
  285. package/dist/_internal/server/jobs/core/prizeRevealClose.js +0 -28
  286. package/dist/_internal/server/jobs/core/prizeRevealExpiry.d.ts +0 -2
  287. package/dist/_internal/server/jobs/core/prizeRevealExpiry.js +0 -61
  288. package/dist/_internal/server/jobs/core/prizeRevealOpen.d.ts +0 -2
  289. package/dist/_internal/server/jobs/core/prizeRevealOpen.js +0 -68
  290. package/dist/_internal/server/jobs/core/prizeRevealReminder.d.ts +0 -2
  291. package/dist/_internal/server/jobs/core/prizeRevealReminder.js +0 -49
  292. package/dist/_internal/server/jobs/handlers/prizeRevealClose.d.ts +0 -2
  293. package/dist/_internal/server/jobs/handlers/prizeRevealClose.js +0 -2
  294. package/dist/_internal/server/jobs/handlers/prizeRevealExpiry.d.ts +0 -2
  295. package/dist/_internal/server/jobs/handlers/prizeRevealExpiry.js +0 -2
  296. package/dist/_internal/server/jobs/handlers/prizeRevealOpen.d.ts +0 -2
  297. package/dist/_internal/server/jobs/handlers/prizeRevealOpen.js +0 -2
  298. package/dist/_internal/server/jobs/handlers/prizeRevealReminder.d.ts +0 -2
  299. package/dist/_internal/server/jobs/handlers/prizeRevealReminder.js +0 -2
  300. package/dist/features/auth/consent-otp.d.ts +0 -57
  301. package/dist/features/auth/consent-otp.js +0 -127
  302. package/dist/features/cart/components/CheckoutOtpModal.d.ts +0 -15
  303. package/dist/features/cart/components/CheckoutOtpModal.js +0 -12
  304. package/dist/features/checkout/actions/checkout-actions.d.ts +0 -31
  305. package/dist/features/checkout/actions/checkout-actions.js +0 -124
  306. package/dist/features/classified/components/ClassifiedIndexListing.d.ts +0 -5
  307. package/dist/features/classified/components/ClassifiedIndexListing.js +0 -123
  308. package/dist/features/classified/components/ClassifiedListView.d.ts +0 -6
  309. package/dist/features/classified/components/ClassifiedListView.js +0 -44
  310. package/dist/features/digital-codes/components/DigitalCodesIndexListing.d.ts +0 -5
  311. package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +0 -114
  312. package/dist/features/digital-codes/components/DigitalCodesListView.d.ts +0 -6
  313. package/dist/features/digital-codes/components/DigitalCodesListView.js +0 -38
  314. package/dist/features/live/components/LiveItemsIndexListing.d.ts +0 -5
  315. package/dist/features/live/components/LiveItemsIndexListing.js +0 -115
  316. package/dist/features/live/components/LiveItemsListView.d.ts +0 -6
  317. package/dist/features/live/components/LiveItemsListView.js +0 -44
  318. package/dist/features/seller/components/SellerTemplatesView.d.ts +0 -12
  319. package/dist/features/seller/components/SellerTemplatesView.js +0 -276
  320. package/dist/react/hooks/useVisibleItems.d.ts +0 -37
  321. package/dist/react/hooks/useVisibleItems.js +0 -59
  322. package/dist/ui/components/TabStrip.d.ts +0 -34
  323. package/dist/ui/components/TabStrip.js +0 -56
  324. package/dist/ui/components/TabStrip.style.css +0 -97
@@ -1,14 +1,56 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useCallback, useEffect, useState } from "react";
3
+ import { useCallback, useEffect, useMemo, useState } from "react";
4
+ import { z } from "zod";
4
5
  import { Alert, Badge, Checkbox, Div, FormField, FormGroup, Heading, Label, Row, Stack, Text, Toggle } from "../../../ui";
5
6
  import { StackedViewShell } from "../../../ui";
7
+ import { FormShellContext, useFormShellState, applyZodIssues, FormErrorSummary } from "../../../ui/forms";
6
8
  import { StepForm } from "../../shell";
7
9
  import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
8
10
  import { normalizeError } from "../../../errors/normalize";
9
11
  const __P = {
10
12
  p3: "p-[var(--appkit-space-3)]",
11
13
  };
14
+ // No accountNumber format check here on purpose — the UI supports "leave
15
+ // blank to keep the existing saved account number" on re-save (see the
16
+ // accountNumber field's helpText below), and the exact keep-existing
17
+ // semantics live server-side; a client-side format requirement risks
18
+ // blocking that legitimate blank-resave case.
19
+ const payoutSettingsDraftSchema = z.object({
20
+ method: z.enum(["upi", "bank_transfer"]),
21
+ upiId: z.string(),
22
+ accountHolderName: z.string(),
23
+ accountNumber: z.string(),
24
+ ifscCode: z.string(),
25
+ bankName: z.string(),
26
+ accountType: z.enum(["savings", "current"]),
27
+ gstin: z.string(),
28
+ pan: z.string(),
29
+ businessType: z.string(),
30
+ autoPayout: z.boolean(),
31
+ minimumThreshold: z.string(),
32
+ emiEnabled: z.boolean(),
33
+ }).superRefine((v, ctx) => {
34
+ if (v.method === "upi") {
35
+ if (!v.upiId.trim()) {
36
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["upiId"], message: "UPI ID is required" });
37
+ }
38
+ else if (!/^[\w.\-_]{2,256}@[a-zA-Z]{2,64}$/.test(v.upiId.trim())) {
39
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["upiId"], message: "Please enter a valid UPI ID" });
40
+ }
41
+ }
42
+ else {
43
+ if (!v.accountHolderName.trim()) {
44
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["accountHolderName"], message: "Account holder name is required" });
45
+ }
46
+ if (v.ifscCode.trim() && !/^[A-Z]{4}0[A-Z0-9]{6}$/.test(v.ifscCode.trim())) {
47
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["ifscCode"], message: "Invalid IFSC code" });
48
+ }
49
+ if (!v.bankName.trim()) {
50
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["bankName"], message: "Bank name is required" });
51
+ }
52
+ }
53
+ });
12
54
  const DEFAULT_DRAFT = {
13
55
  method: "upi",
14
56
  upiId: "",
@@ -32,6 +74,11 @@ export function SellerPayoutSettingsView({ apiBase = SELLER_ENDPOINTS.PAYOUT_SET
32
74
  const [error, setError] = useState(null);
33
75
  const [success, setSuccess] = useState(false);
34
76
  const [currentStep, setCurrentStep] = useState(0);
77
+ const { shellCtx, setFieldError, clearErrors, validate } = useFormShellState(payoutSettingsDraftSchema);
78
+ useEffect(() => {
79
+ validate(draft);
80
+ // eslint-disable-next-line react-hooks/exhaustive-deps
81
+ }, [draft, validate]);
35
82
  useEffect(() => {
36
83
  fetch(apiBase)
37
84
  .then((r) => r.json())
@@ -97,8 +144,14 @@ export function SellerPayoutSettingsView({ apiBase = SELLER_ENDPOINTS.PAYOUT_SET
97
144
  body: JSON.stringify(body),
98
145
  });
99
146
  const json = await res.json();
100
- if (!res.ok)
101
- throw new Error(json?.error ?? "Failed to save");
147
+ if (!res.ok) {
148
+ if (Array.isArray(json?.issues) && json.issues.length > 0) {
149
+ applyZodIssues(json.issues, setFieldError);
150
+ }
151
+ setError(json?.error ?? "Failed to save");
152
+ return;
153
+ }
154
+ clearErrors();
102
155
  setSuccess(true);
103
156
  const updated = json?.data?.payoutDetails ?? { method: draft.method, isConfigured: false };
104
157
  setCurrent(updated);
@@ -116,6 +169,7 @@ export function SellerPayoutSettingsView({ apiBase = SELLER_ENDPOINTS.PAYOUT_SET
116
169
  const steps = [
117
170
  {
118
171
  label: "Payout Method",
172
+ fields: ["method", "upiId", "accountHolderName", "accountNumber", "ifscCode", "bankName", "accountType"],
119
173
  render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Payout Method" }), current && (_jsx(Row, { className: "mb-2", align: "center", gap: "sm", children: _jsx(Badge, { variant: current.isConfigured ? "success" : "warning", children: current.isConfigured ? "Payout configured" : "Not configured" }) })), current?.isConfigured && (_jsx(Alert, { variant: "info", children: current.method === "upi"
120
174
  ? `Current UPI: ${current.upiId}`
121
175
  : `Current bank: ${current.bankAccount?.bankName ?? ""} — ••••${current.bankAccount?.accountNumberMasked?.slice(-4) ?? "••••"} (${current.bankAccount?.accountType})` })), _jsx(Stack, { gap: "sm", children: ([
@@ -125,14 +179,25 @@ export function SellerPayoutSettingsView({ apiBase = SELLER_ENDPOINTS.PAYOUT_SET
125
179
  },
126
180
  {
127
181
  label: "Tax Info",
182
+ fields: ["gstin", "pan", "businessType"],
128
183
  render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Tax Information" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: "Optional \u2014 required only for GST invoice generation and TDS compliance." }), _jsx(FormField, { name: "gstin", label: "GSTIN (optional)", type: "text", value: values.gstin, onChange: (v) => onChange({ gstin: v.toUpperCase() }), placeholder: "e.g. 22AAAAA0000A1Z5", helpText: "15-character Goods and Services Tax Identification Number.", disabled: busy }), _jsx(FormField, { name: "pan", label: "PAN (optional)", type: "text", value: values.pan, onChange: (v) => onChange({ pan: v.toUpperCase() }), placeholder: "e.g. ABCDE1234F", helpText: "Required for payouts above \u20B950,000 per year (TDS threshold).", disabled: busy }), _jsx(FormField, { name: "businessType", label: "Business Type (optional)", type: "text", value: values.businessType, onChange: (v) => onChange({ businessType: v }), placeholder: "e.g. Individual, Sole Proprietor, Private Limited", disabled: busy })] })),
129
184
  },
130
185
  {
131
186
  label: "Preferences",
187
+ fields: ["autoPayout", "minimumThreshold", "emiEnabled"],
132
188
  render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Payout Preferences" }), _jsx(Toggle, { checked: values.autoPayout, onChange: (checked) => onChange({ autoPayout: checked }), label: "Enable auto-payout \u2014 automatically transfer earnings on schedule", disabled: busy }), _jsx(FormField, { name: "minimumThreshold", label: "Minimum Payout Threshold (\u20B9)", type: "number", value: values.minimumThreshold, onChange: (v) => onChange({ minimumThreshold: v }), placeholder: "e.g. 500", helpText: "Payouts are held until your balance exceeds this amount. Leave blank for no minimum.", disabled: busy }), _jsxs(Div, { className: `${__P.p3} bg-[var(--appkit-color-surface-alt)] border border-[var(--appkit-color-border)]`, rounded: "lg", children: [_jsx(Text, { className: "mb-1", size: "sm", weight: "medium", children: "Payout Schedule" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: "Auto-payouts run every Monday for the previous week's settled orders. Manual payouts can be requested from the Payouts page at any time." })] }), _jsx(Toggle, { checked: values.emiEnabled, onChange: (checked) => onChange({ emiEnabled: checked }), label: "Offer EMI financing on eligible orders", disabled: busy }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: "Only shown to buyers when platform-wide EMI is also enabled and their cart subtotal from your store exceeds the site's minimum order value. Orders on an EMI plan hold your payout until every installment is paid, unless you mark the item \"ship before EMI completes\"." })] })),
133
189
  },
134
190
  ];
191
+ const fieldToStepIndex = useMemo(() => {
192
+ const map = {};
193
+ steps.forEach((step, i) => {
194
+ step.fields?.forEach((field) => { map[field] = i; });
195
+ });
196
+ return map;
197
+ // eslint-disable-next-line react-hooks/exhaustive-deps
198
+ }, [steps.length]);
199
+ const wizardShellCtx = useMemo(() => ({ ...shellCtx, fieldToStepIndex, goToStep: (n) => setCurrentStep(n) }), [shellCtx, fieldToStepIndex, setCurrentStep]);
135
200
  return (_jsx(StackedViewShell, { portal: "seller", title: "Payout Settings", sections: [
136
- _jsxs(Div, { children: [error && _jsx(Alert, { variant: "error", className: "mb-4", children: error }), success && _jsx(Alert, { variant: "success", className: "mb-4", children: "Payout details saved." }), _jsx(StepForm, { steps: steps, values: draft, onChange: update, onComplete: handleSave, formId: "seller-payout-settings", currentStep: currentStep, onStepChange: setCurrentStep, completeLabel: "Save Payout Details", isLoading: busy })] }, "payout"),
201
+ _jsxs(Div, { children: [error && _jsx(Alert, { variant: "error", className: "mb-4", children: error }), success && _jsx(Alert, { variant: "success", className: "mb-4", children: "Payout details saved." }), _jsxs(FormShellContext.Provider, { value: wizardShellCtx, children: [_jsx(FormErrorSummary, {}), _jsx(StepForm, { steps: steps, values: draft, onChange: update, onComplete: handleSave, formId: "seller-payout-settings", currentStep: currentStep, onStepChange: setCurrentStep, completeLabel: "Save Payout Details", isLoading: busy })] })] }, "payout"),
137
202
  ] }));
138
203
  }
@@ -1,4 +1,16 @@
1
1
  import React from "react";
2
2
  import type { ListingLayoutProps } from "../../../ui";
3
+ /**
4
+ * SellerPayoutDetailContent — the payout detail body (status progress,
5
+ * amount breakdown, refund deductions, dates, orders, reminder toggle).
6
+ * Shared by the seller payouts list's SideDrawer and the standalone
7
+ * `/store/payouts/[id]/view` page so the two surfaces can't drift — same
8
+ * pattern as SellerOrderDetailPanel for orders.
9
+ */
10
+ export declare function SellerPayoutDetailContent({ payout, onToggleReminder, reminderPending, }: {
11
+ payout: Record<string, unknown>;
12
+ onToggleReminder: (next: boolean) => void;
13
+ reminderPending: boolean;
14
+ }): React.JSX.Element;
3
15
  export type SellerPayoutsViewProps = ListingLayoutProps;
4
16
  export declare function SellerPayoutsView({ children, ...props }: SellerPayoutsViewProps): React.JSX.Element;
@@ -4,8 +4,10 @@ import { normalizeError } from "../../../errors/normalize";
4
4
  import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit/client";
5
5
  import { sortBy } from "@mohasinac/appkit/client";
6
6
  import React, { useState } from "react";
7
+ import { useRouter } from "next/navigation";
7
8
  import { Badge, Div, FilterChipGroup, ListingLayout, Row, RowActionMenu, SideDrawer, Span, Stack, Text, Toggle, useToast } from "../../../ui";
8
9
  import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
10
+ import { ROUTES } from "../../../next/routing/route-map";
9
11
  import { ADMIN_PAYOUT_STATUS_TABS } from "../../admin/constants/filter-tabs";
10
12
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
11
13
  import { SELLER_BULK_ACTIONS, ROW_ACTION_META } from "../../products/constants/action-defs";
@@ -28,7 +30,25 @@ function StatusProgress({ status }) {
28
30
  const currentIndex = PAYOUT_STAGES.indexOf(normalized);
29
31
  return (_jsx(Row, { gap: "xs", align: "center", children: PAYOUT_STAGES.map((stage, i) => (_jsxs(React.Fragment, { children: [i > 0 && _jsx(Div, { className: `h-0.5 w-6 ${i <= currentIndex ? "bg-primary" : "bg-[var(--appkit-color-border)]"}` }), _jsx(Span, { size: "xs", weight: i === currentIndex ? "bold" : "medium", className: i <= currentIndex ? "text-primary" : "text-[var(--appkit-color-text-muted)]", children: stage[0].toUpperCase() + stage.slice(1) })] }, stage))) }));
30
32
  }
33
+ /**
34
+ * SellerPayoutDetailContent — the payout detail body (status progress,
35
+ * amount breakdown, refund deductions, dates, orders, reminder toggle).
36
+ * Shared by the seller payouts list's SideDrawer and the standalone
37
+ * `/store/payouts/[id]/view` page so the two surfaces can't drift — same
38
+ * pattern as SellerOrderDetailPanel for orders.
39
+ */
40
+ export function SellerPayoutDetailContent({ payout, onToggleReminder, reminderPending, }) {
41
+ const expectedByDate = payout.requestedAt
42
+ ? new Date(new Date(payout.requestedAt).getTime() + PAYOUT_CYCLE_DAYS * 24 * 60 * 60 * 1000)
43
+ : null;
44
+ const orderIds = Array.isArray(payout.orderIds) ? payout.orderIds : [];
45
+ const refundDeductions = Array.isArray(payout.refundDeductions)
46
+ ? payout.refundDeductions
47
+ : [];
48
+ return (_jsxs(Stack, { gap: "lg", children: [_jsx(StatusProgress, { status: toStringValue(payout.status, "pending") }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Amount" }), _jsx(Text, { size: "xl", weight: "bold", children: toCurrency(payout.netAmount ?? payout.amount ?? payout.totalAmount) })] }), (payout.grossAmount != null || payout.platformFee != null) && (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Breakdown" }), _jsxs(Stack, { gap: "none", children: [payout.grossAmount != null && (_jsxs(Row, { justify: "between", children: [_jsx(Text, { size: "xs", color: "muted", children: "Gross amount" }), _jsx(Text, { size: "xs", children: toCurrency(payout.grossAmount) })] })), payout.platformFee != null && (_jsxs(Row, { justify: "between", children: [_jsx(Text, { size: "xs", color: "muted", children: "Platform fee" }), _jsxs(Text, { size: "xs", children: ["-", toCurrency(payout.platformFee)] })] })), refundDeductions.length > 0 && (_jsxs(Row, { justify: "between", children: [_jsx(Text, { size: "xs", color: "muted", children: "Refund deductions" }), _jsxs(Text, { size: "xs", className: "text-error", children: ["-", toCurrency(refundDeductions.reduce((sum, d) => sum + Number(d.deductedAmount ?? 0), 0))] })] }))] })] })), refundDeductions.length > 0 && (_jsxs(Stack, { gap: "xs", children: [_jsxs(Text, { size: "xs", color: "muted", children: ["Refund deductions (", refundDeductions.length, ")"] }), _jsx(Stack, { gap: "xs", children: refundDeductions.map((d, i) => (_jsxs(Div, { rounded: "lg", padding: "inlineSm", surface: "muted", border: "default", children: [_jsxs(Row, { justify: "between", children: [_jsx(Text, { size: "xs", className: "font-mono", children: d.orderId }), _jsxs(Text, { size: "xs", className: "text-error", children: ["-", toCurrency(d.deductedAmount)] })] }), _jsx(Text, { size: "xs", color: "muted", children: d.reason })] }, `${d.orderId}-${i}`))) })] })), payout.transactionId ? (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Transaction / reference ID" }), _jsx(Text, { size: "sm", className: "font-mono", children: String(payout.transactionId) })] })) : null, _jsxs(Row, { gap: "lg", wrap: true, children: [_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Requested" }), _jsx(Text, { size: "sm", children: formatDate(payout.requestedAt ?? payout.createdAt) })] }), payout.status === "paid" ? (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Paid on" }), _jsx(Text, { size: "sm", children: formatDate(payout.processedAt) })] })) : (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Expected by" }), _jsx(Text, { size: "sm", children: expectedByDate ? formatDate(expectedByDate.toISOString()) : "—" })] })), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Payment method" }), _jsx(Text, { size: "sm", className: "capitalize", children: toStringValue(payout.paymentMethod, "—").replace("_", " ") })] })] }), orderIds.length > 0 && (_jsxs(Stack, { gap: "xs", children: [_jsxs(Text, { size: "xs", color: "muted", children: ["Orders included (", orderIds.length, ")"] }), _jsx(Div, { className: "max-h-40", overflow: "y-auto", children: _jsx(Stack, { gap: "xs", children: orderIds.map((oid) => (_jsx(Text, { size: "xs", className: "font-mono", color: "muted", children: oid }, oid))) }) })] })), _jsxs(Row, { align: "center", justify: "between", border: "default", rounded: "lg", padding: "inline", children: [_jsxs(Stack, { gap: "none", children: [_jsx(Text, { size: "sm", weight: "medium", children: "Remind me" }), _jsx(Text, { size: "xs", color: "muted", children: "Flag this payout for a personal follow-up" })] }), _jsx(Toggle, { checked: Boolean(payout.sellerReminderFlag), onChange: onToggleReminder, disabled: reminderPending, size: "md", "aria-label": ACTIONS.STORE["set-payout-reminder"].ariaLabel })] })] }));
49
+ }
31
50
  export function SellerPayoutsView({ children, ...props }) {
51
+ const router = useRouter();
32
52
  const { showToast } = useToast();
33
53
  const [selectedPayout, setSelectedPayout] = useState(null);
34
54
  const [reminderPending, setReminderPending] = useState(false);
@@ -132,6 +152,10 @@ export function SellerPayoutsView({ children, ...props }) {
132
152
  label: ACTIONS.STORE["view-payout"].label,
133
153
  onClick: () => setSelectedPayout(rawByIdRef.current[row.id] ?? { id: row.id }),
134
154
  },
155
+ {
156
+ label: "Open full page",
157
+ onClick: () => router.push(String(ROUTES.STORE.PAYOUT_DETAIL(row.id))),
158
+ },
135
159
  {
136
160
  label: ACTIONS.STORE["export-payout"].label,
137
161
  onClick: () => handleExport([rawByIdRef.current[row.id] ?? { id: row.id }]),
@@ -142,9 +166,5 @@ export function SellerPayoutsView({ children, ...props }) {
142
166
  { id: "true", label: "Show all" },
143
167
  ], value: pendingFilters.showAllPayouts ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, showAllPayouts: id })), allId: "" })] })),
144
168
  };
145
- const expectedByDate = selectedPayout?.requestedAt
146
- ? new Date(new Date(selectedPayout.requestedAt).getTime() + PAYOUT_CYCLE_DAYS * 24 * 60 * 60 * 1000)
147
- : null;
148
- const orderIds = Array.isArray(selectedPayout?.orderIds) ? selectedPayout.orderIds : [];
149
- return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(SideDrawer, { isOpen: Boolean(selectedPayout), onClose: () => setSelectedPayout(null), title: selectedPayout ? `Payout #${toStringValue(selectedPayout.payoutNumber ?? selectedPayout.id, "")}` : "Payout", mode: "view", children: selectedPayout && (_jsxs(Stack, { gap: "lg", children: [_jsx(StatusProgress, { status: toStringValue(selectedPayout.status, "pending") }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Amount" }), _jsx(Text, { size: "xl", weight: "bold", children: toCurrency(selectedPayout.amount ?? selectedPayout.totalAmount) })] }), selectedPayout.transactionId ? (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Transaction / reference ID" }), _jsx(Text, { size: "sm", className: "font-mono", children: String(selectedPayout.transactionId) })] })) : null, _jsxs(Row, { gap: "lg", wrap: true, children: [_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Requested" }), _jsx(Text, { size: "sm", children: formatDate(selectedPayout.requestedAt ?? selectedPayout.createdAt) })] }), selectedPayout.status === "paid" ? (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Paid on" }), _jsx(Text, { size: "sm", children: formatDate(selectedPayout.processedAt) })] })) : (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Expected by" }), _jsx(Text, { size: "sm", children: expectedByDate ? formatDate(expectedByDate.toISOString()) : "—" })] })), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Payment method" }), _jsx(Text, { size: "sm", className: "capitalize", children: toStringValue(selectedPayout.paymentMethod, "—").replace("_", " ") })] })] }), orderIds.length > 0 && (_jsxs(Stack, { gap: "xs", children: [_jsxs(Text, { size: "xs", color: "muted", children: ["Orders included (", orderIds.length, ")"] }), _jsx(Div, { className: "max-h-40", overflow: "y-auto", children: _jsx(Stack, { gap: "xs", children: orderIds.map((oid) => (_jsx(Text, { size: "xs", className: "font-mono", color: "muted", children: oid }, oid))) }) })] })), _jsxs(Row, { align: "center", justify: "between", border: "default", rounded: "lg", padding: "inline", children: [_jsxs(Stack, { gap: "none", children: [_jsx(Text, { size: "sm", weight: "medium", children: "Remind me" }), _jsx(Text, { size: "xs", color: "muted", children: "Flag this payout for a personal follow-up" })] }), _jsx(Toggle, { checked: Boolean(selectedPayout.sellerReminderFlag), onChange: handleToggleReminder, disabled: reminderPending, size: "md", "aria-label": ACTIONS.STORE["set-payout-reminder"].ariaLabel })] })] })) })] }));
169
+ return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(SideDrawer, { isOpen: Boolean(selectedPayout), onClose: () => setSelectedPayout(null), title: selectedPayout ? `Payout #${toStringValue(selectedPayout.payoutNumber ?? selectedPayout.id, "")}` : "Payout", mode: "view", children: selectedPayout && (_jsx(SellerPayoutDetailContent, { payout: selectedPayout, onToggleReminder: handleToggleReminder, reminderPending: reminderPending })) })] }));
150
170
  }
@@ -1,4 +1,5 @@
1
1
  import React from "react";
2
+ import type { MediaField } from "../../media/types";
2
3
  export type ProductListingMode = "standard" | "auction" | "pre-order" | "prize-draw" | "bundle" | "classified" | "digital-code" | "live" | "art" | "stickers";
3
4
  export interface SellerProductDraft {
4
5
  title?: string;
@@ -10,7 +11,7 @@ export interface SellerProductDraft {
10
11
  tags?: string[];
11
12
  mainImage?: string;
12
13
  images?: string[];
13
- video?: string;
14
+ video?: MediaField;
14
15
  youtubeId?: string;
15
16
  price?: number;
16
17
  compareAtPrice?: number;
@@ -70,13 +71,19 @@ export interface SellerProductDraft {
70
71
  printFinish?: string;
71
72
  printEditionSize?: number;
72
73
  }
74
+ /** Shape returned by `onSave`/`onPublish` — structurally compatible with appkit's `ActionResult<T>` failure/success arms, without importing the server-only type into this client component. */
75
+ export interface ProductActionResult {
76
+ ok: boolean;
77
+ error?: string;
78
+ issues?: unknown[];
79
+ }
73
80
  export interface SellerProductShellProps {
74
81
  mode: "create" | "edit";
75
82
  listingType?: ProductListingMode;
76
83
  initialValues?: SellerProductDraft;
77
84
  productId?: string;
78
- onSave: (draft: SellerProductDraft) => void | Promise<void>;
79
- onPublish: (draft: SellerProductDraft) => void | Promise<void>;
85
+ onSave: (draft: SellerProductDraft) => Promise<ProductActionResult>;
86
+ onPublish: (draft: SellerProductDraft) => Promise<ProductActionResult>;
80
87
  onDiscard?: () => void;
81
88
  isLoading?: boolean;
82
89
  storeSlug?: string;
@@ -4,7 +4,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
4
  import { useRouter } from "next/navigation";
5
5
  import { z } from "zod";
6
6
  import { FormShell, StepForm, StepFormActions, useFormShell } from "../../shell";
7
- import { FormShellProvider } from "../../../ui/forms";
7
+ import { FormShellContext, useFormShellState, applyZodIssues, FormErrorSummary } from "../../../ui/forms";
8
8
  import { Alert, Button, Div, FormField, FormGroup, Heading, Section, Stack, TagInput, Text, Toggle, useToast } from "../../../ui";
9
9
  import { ImageUpload, MediaUploadField, MediaUploadList, useMediaUpload } from "../../media";
10
10
  import { StoreAddressSelectorCreate } from "../../stores/components/StoreAddressSelectorCreate";
@@ -25,6 +25,18 @@ const BUNDLE_PLUGIN_FALLBACK = {
25
25
  function pluginForMode(mode) {
26
26
  return mode === "bundle" ? BUNDLE_PLUGIN_FALLBACK : pluginFor(mode);
27
27
  }
28
+ // Video duration is required for a directly-uploaded file (captured
29
+ // automatically off the video element — see video-poster.ts) but can't be
30
+ // obtained client-side for a YouTube/External-URL-sourced video without a
31
+ // server round-trip, so it's optional for those two sources only.
32
+ const productVideoSchema = z.object({
33
+ url: z.string().min(1),
34
+ type: z.literal("video").optional(),
35
+ thumbnailUrl: z.string().optional(),
36
+ source: z.enum(["upload", "youtube", "external"]).optional(),
37
+ youtubeId: z.string().optional(),
38
+ duration: z.number().positive().max(600).optional(),
39
+ }).refine((v) => v.source === "youtube" || v.source === "external" || (v.duration != null && v.duration > 0), { message: "Video duration could not be detected — try re-uploading the file.", path: ["duration"] });
28
40
  const sellerProductSchema = z.object({
29
41
  title: z.string().min(1, "Product title is required").max(200),
30
42
  description: z.string().max(10000).optional().or(z.literal("")),
@@ -32,6 +44,8 @@ const sellerProductSchema = z.object({
32
44
  category: z.string().optional(),
33
45
  brand: z.string().optional(),
34
46
  isActive: z.boolean().optional(),
47
+ images: z.array(z.string()).max(5, "Up to 5 gallery images allowed").optional(),
48
+ video: productVideoSchema.optional(),
35
49
  }).passthrough();
36
50
  const CONDITION_OPTIONS = [
37
51
  { value: "new", label: "New" },
@@ -70,7 +84,7 @@ function StepMedia({ values, onChange, storeSlug = "store", }) {
70
84
  name: values.title ?? "product",
71
85
  store: storeSlug,
72
86
  category: values.category ?? "uncategorized",
73
- }), onChange: (url) => onChange({ mainImage: url }), label: "Main Image", helperText: "Recommended: 800\u00D7800px square (JPG, PNG, WebP \u2014 max 10 MB)", enableAdvancedCrop: true, cropAspectRatio: 1 }), _jsx(MediaUploadList, { label: "Gallery Images (up to 10)", value: galleryFields, onChange: (fields) => onChange({ images: fields.map((f) => f.url) }), onUpload: (file) => {
87
+ }), onChange: (url) => onChange({ mainImage: url }), label: "Main Image", helperText: "Recommended: 800\u00D7800px square (JPG, PNG, WebP \u2014 max 10 MB)", enableAdvancedCrop: true, cropAspectRatio: 1 }), _jsx(MediaUploadList, { label: "Gallery Images (up to 5)", value: galleryFields, onChange: (fields) => onChange({ images: fields.map((f) => f.url) }), onUpload: (file) => {
74
88
  idxRef.current += 1;
75
89
  return upload(file, "products", true, {
76
90
  type: "product-image",
@@ -79,7 +93,11 @@ function StepMedia({ values, onChange, storeSlug = "store", }) {
79
93
  store: storeSlug,
80
94
  category: values.category ?? "uncategorized",
81
95
  });
82
- }, accept: "image/*,video/*", maxItems: 10, maxSizeMB: 10, helperText: "Show multiple angles, grading details, or box contents." }), _jsx(MediaUploadField, { label: "Product Video (optional)", value: values.video ?? "", onChange: (url) => onChange({ video: url }), onUpload: (file) => upload(file, "products", true, {
96
+ }, accept: "image/*,video/*", maxItems: 5, maxSizeMB: 10, helperText: "Show multiple angles, grading details, or box contents." }), _jsx(MediaUploadField, { label: "Product Video (optional)", value: values.video?.url ?? "", onChange: (url) => onChange({
97
+ video: url
98
+ ? { ...(values.video ?? { type: "video", source: "upload" }), url }
99
+ : undefined,
100
+ }), onChangeField: (media) => onChange({ video: media ?? undefined }), onThumbnailChange: (thumbnailUrl) => onChange({ video: values.video ? { ...values.video, thumbnailUrl } : undefined }), onDurationChange: (duration) => onChange({ video: values.video ? { ...values.video, duration } : undefined }), onUpload: (file) => upload(file, "products", true, {
83
101
  type: "product-video",
84
102
  name: values.title ?? "product",
85
103
  store: storeSlug,
@@ -223,25 +241,7 @@ export function SellerProductShell({ mode, listingType = "standard", initialValu
223
241
  const router = useRouter();
224
242
  const { showToast } = useToast();
225
243
  const { upload: shellUpload } = useMediaUpload();
226
- // Auto-save in create mode debounce 2s on any draft change
227
- const autoSaveTimer = useRef(null);
228
- const draftRef = useRef(draft);
229
- draftRef.current = draft;
230
- const onSaveRef = useRef(onSave);
231
- onSaveRef.current = onSave;
232
- useEffect(() => {
233
- if (mode !== "create" || !isDirty)
234
- return;
235
- if (autoSaveTimer.current)
236
- clearTimeout(autoSaveTimer.current);
237
- autoSaveTimer.current = setTimeout(() => {
238
- const result = onSaveRef.current(draftRef.current);
239
- if (result && typeof result.catch === "function")
240
- result.catch(console.error);
241
- }, 2000);
242
- return () => { if (autoSaveTimer.current)
243
- clearTimeout(autoSaveTimer.current); };
244
- }, [draft, isDirty, mode]);
244
+ const { shellCtx, setFieldError, clearErrors, validate } = useFormShellState(sellerProductSchema);
245
245
  const update = useCallback((partial) => {
246
246
  setDraft((prev) => {
247
247
  const next = { ...prev, ...partial };
@@ -275,22 +275,35 @@ export function SellerProductShell({ mode, listingType = "standard", initialValu
275
275
  router.back();
276
276
  }, [onDiscard, router]);
277
277
  // `silent` suppresses the success toast — used by the debounced auto-save
278
- // path (FormShellProvider's onSaveDraft) so it doesn't pop a "Saved." toast
279
- // every couple of seconds while the seller is still typing. The manual
280
- // "Save Draft"/"Save Changes" button click stays loud (silent=false).
278
+ // effect above so it doesn't pop a "Saved." toast every couple of seconds
279
+ // while the seller is still typing. The manual "Save Draft"/"Save Changes"
280
+ // button click stays loud (silent=false).
281
+ //
282
+ // `onSave`/`onPublish` never throw in normal operation (backed by
283
+ // `wrapAction`-wrapped server actions, which always resolve to a
284
+ // `{ok, ...}` envelope) — the try/catch here is a defensive fallback for
285
+ // a genuinely unexpected rejection (e.g. a network failure during the RSC
286
+ // round-trip itself), not the primary error path.
281
287
  const handleSave = useCallback(async (silent = false) => {
282
288
  try {
283
- await onSave(draft);
284
- markClean();
289
+ const result = await onSave(draft);
290
+ if (result.ok) {
291
+ markClean();
292
+ clearErrors();
293
+ if (!silent)
294
+ showToast("Saved.", "success");
295
+ return;
296
+ }
297
+ applyZodIssues(result.issues ?? [], setFieldError);
285
298
  if (!silent)
286
- showToast("Saved.", "success");
299
+ showToast(result.error || "Fix the highlighted errors and try again.", "error");
287
300
  }
288
301
  catch (err) {
289
302
  void normalizeError(err);
290
303
  if (!silent)
291
304
  showToast(err instanceof Error ? err.message : "Failed to save.", "error");
292
305
  }
293
- }, [draft, onSave, markClean, showToast]);
306
+ }, [draft, onSave, markClean, clearErrors, setFieldError, showToast]);
294
307
  const handleAutoSave = useCallback(async () => {
295
308
  try {
296
309
  await handleSave(true);
@@ -299,22 +312,39 @@ export function SellerProductShell({ mode, listingType = "standard", initialValu
299
312
  void normalizeError(err);
300
313
  }
301
314
  }, [handleSave]);
315
+ // Auto-save in create mode — debounce 2s on any draft change. Routed
316
+ // through handleAutoSave/handleSave (not a direct onSave call) so a
317
+ // validation failure during auto-save applies field errors + populates
318
+ // FormErrorSummary the same way a manual save does.
319
+ useEffect(() => {
320
+ if (mode !== "create" || !isDirty)
321
+ return;
322
+ const timer = setTimeout(() => { void handleAutoSave(); }, 2000);
323
+ return () => clearTimeout(timer);
324
+ }, [draft, isDirty, mode, handleAutoSave]);
302
325
  const handlePublish = useCallback(async () => {
303
326
  try {
304
- await onPublish({ ...draft, status: "published" });
305
- markClean();
306
- showToast("Published.", "success");
327
+ const result = await onPublish({ ...draft, status: "published" });
328
+ if (result.ok) {
329
+ markClean();
330
+ clearErrors();
331
+ showToast("Published.", "success");
332
+ return;
333
+ }
334
+ applyZodIssues(result.issues ?? [], setFieldError);
335
+ showToast(result.error || "Fix the highlighted errors and try again.", "error");
307
336
  }
308
337
  catch (err) {
309
338
  void normalizeError(err);
310
339
  showToast(err instanceof Error ? err.message : "Failed to publish.", "error");
311
340
  }
312
- }, [draft, onPublish, markClean, showToast]);
341
+ }, [draft, onPublish, markClean, clearErrors, setFieldError, showToast]);
313
342
  const listingTypeLabel = pluginForMode(listingType).typeLabel;
314
343
  const typeSpecificStep = TYPE_SPECIFIC_STEPS[listingType] ?? null;
315
344
  const steps = [
316
345
  {
317
346
  label: "Basic",
347
+ fields: ["title", "description", "category", "brand", "condition", "tags", "barcodeId"],
318
348
  render: ({ values, onChange }) => (_jsx(StepBasic, { values: values, onChange: onChange, renderCategorySelector: renderCategorySelector, renderBrandSelector: renderBrandSelector, renderTemplateSelector: renderTemplateSelector })),
319
349
  validate: (v) => {
320
350
  if (!v.title?.trim() || v.title.trim().length < 3)
@@ -326,12 +356,14 @@ export function SellerProductShell({ mode, listingType = "standard", initialValu
326
356
  },
327
357
  {
328
358
  label: "Media",
359
+ fields: ["mainImage", "images", "video", "video.url", "video.duration", "video.thumbnailUrl", "youtubeId", "externalVideoUrl"],
329
360
  render: ({ values, onChange }) => (_jsx(StepMedia, { values: values, onChange: onChange, storeSlug: storeSlug })),
330
361
  validate: (v) => (!v.mainImage ? "A main image is required" : null),
331
362
  },
332
363
  ...(typeSpecificStep ? [typeSpecificStep] : []),
333
364
  {
334
365
  label: "Pricing",
366
+ fields: ["price", "compareAtPrice", "stockQuantity", "allowOffers", "minOfferPercent", "gstRate", "hsnCode"],
335
367
  render: ({ values, onChange }) => (_jsx(StepPricing, { values: values, onChange: onChange, listingType: listingType })),
336
368
  validate: (v) => {
337
369
  if (!v.price)
@@ -345,13 +377,34 @@ export function SellerProductShell({ mode, listingType = "standard", initialValu
345
377
  },
346
378
  {
347
379
  label: "Shipping",
380
+ fields: ["shippingPaidBy", "pickupAddressId", "insurance", "insuranceCost"],
348
381
  render: ({ values, onChange }) => (_jsx(StepShipping, { values: values, onChange: onChange, renderAddressSelector: renderAddressSelector })),
349
382
  },
350
383
  {
351
384
  label: "Publish",
385
+ fields: ["seoTitle", "seoDescription", "isOnSale", "status"],
352
386
  render: ({ values, onChange }) => (_jsx(StepPublish, { values: values, onChange: onChange })),
353
387
  },
354
388
  ];
389
+ // Field-name → owning-step-index map for FormErrorSummary's step
390
+ // attribution/jump-to-step links (full-wizard create mode only — quick
391
+ // and edit modes don't have step navigation).
392
+ const fieldToStepIndex = useMemo(() => {
393
+ const map = {};
394
+ steps.forEach((step, i) => {
395
+ step.fields?.forEach((field) => { map[field] = i; });
396
+ });
397
+ return map;
398
+ // eslint-disable-next-line react-hooks/exhaustive-deps
399
+ }, [steps.length, typeSpecificStep]);
400
+ // Live validation — re-run on every draft change, not just on submit, so
401
+ // FormErrorSummary and inline field errors both stay current as the
402
+ // seller types (per the "even on-change errors must be shown" requirement).
403
+ useEffect(() => {
404
+ validate(draft);
405
+ // eslint-disable-next-line react-hooks/exhaustive-deps
406
+ }, [draft, validate]);
407
+ const wizardShellCtx = useMemo(() => ({ ...shellCtx, fieldToStepIndex, goToStep: (n) => setCurrentStep(n) }), [shellCtx, fieldToStepIndex, setCurrentStep]);
355
408
  const handleNext = useCallback(async () => {
356
409
  const step = steps[currentStep];
357
410
  if (step?.validate) {
@@ -384,7 +437,7 @@ export function SellerProductShell({ mode, listingType = "standard", initialValu
384
437
  ? `New ${listingTypeLabel}`
385
438
  : draft.title ?? `Edit ${listingTypeLabel}`;
386
439
  if (mode === "create" && formMode === "quick") {
387
- return (_jsx(FormShellProvider, { isDirty: isDirty, values: draft, onSaveDraft: handleAutoSave, children: _jsx(FormShell, { isOpen: true, onClose: handleDiscard, title: title, breadcrumb: breadcrumb, isDirty: isDirty, isLoading: isLoading, schema: sellerProductSchema, children: _jsx(QuickProductForm, { values: draft, onChange: update, onPublish: () => void handlePublish(), onSave: () => void handleSave(), onSwitchToFull: () => setFormMode("full"), isLoading: isLoading, renderCategorySelector: renderCategorySelector, storeSlug: storeSlug, onUploadImage: (file) => shellUpload(file, "products", true, {
440
+ return (_jsx(FormShellContext.Provider, { value: shellCtx, children: _jsx(FormShell, { isOpen: true, onClose: handleDiscard, title: title, breadcrumb: breadcrumb, isDirty: isDirty, isLoading: isLoading, schema: sellerProductSchema, children: _jsx(QuickProductForm, { values: draft, onChange: update, onPublish: () => void handlePublish(), onSave: () => void handleSave(), onSwitchToFull: () => setFormMode("full"), isLoading: isLoading, renderCategorySelector: renderCategorySelector, storeSlug: storeSlug, onUploadImage: (file) => shellUpload(file, "products", true, {
388
441
  type: "product-image",
389
442
  index: 1,
390
443
  name: draft.title ?? "product",
@@ -393,12 +446,12 @@ export function SellerProductShell({ mode, listingType = "standard", initialValu
393
446
  }) }) }) }));
394
447
  }
395
448
  if (mode === "create") {
396
- return (_jsx(FormShell, { isOpen: true, onClose: handleDiscard, title: title, breadcrumb: breadcrumb, isDirty: isDirty, isLoading: isLoading, previewSlot: previewSlot, splitPreview: !!previewSlot, renderBottomBar: () => (_jsxs(Div, { className: "flex-shrink-0 border-t border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", children: [_jsx(StepFormActions, { currentStep: currentStep, totalSteps: steps.length, onNext: () => void handleNext(), onPrev: currentStep > 0 ? () => setCurrentStep((c) => c - 1) : undefined, completeLabel: `Publish ${listingTypeLabel}`, isLoading: isLoading && currentStep === steps.length - 1, disabled: isLoading }), currentStep === 0 && (_jsx(Div, { paddingX: "x-5", padding: "b-sm", children: _jsx(Button, { variant: "ghost", size: "sm", onClick: () => void handleSave(), disabled: isLoading || !draft.title?.trim(), children: "Save as draft & finish later" }) })), stepError && (_jsx(Text, { className: "text-[var(--appkit-color-error)] px-[1.25rem] pb-[0.75rem]", size: "sm", children: stepError }))] })), children: _jsx(FormShellProvider, { isDirty: isDirty, values: draft, onSaveDraft: handleAutoSave, children: _jsx(StepForm, { steps: steps, values: draft, onChange: update, onComplete: handlePublish, completeLabel: `Publish ${listingTypeLabel}`, currentStep: currentStep, onStepChange: setCurrentStep, isLoading: isLoading, hideActions: true, stepErrors: stepValidationErrors }) }) }));
449
+ return (_jsx(FormShell, { isOpen: true, onClose: handleDiscard, title: title, breadcrumb: breadcrumb, isDirty: isDirty, isLoading: isLoading, previewSlot: previewSlot, splitPreview: !!previewSlot, renderBottomBar: () => (_jsxs(Div, { className: "flex-shrink-0 border-t border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", children: [_jsx(StepFormActions, { currentStep: currentStep, totalSteps: steps.length, onNext: () => void handleNext(), onPrev: currentStep > 0 ? () => setCurrentStep((c) => c - 1) : undefined, completeLabel: `Publish ${listingTypeLabel}`, isLoading: isLoading && currentStep === steps.length - 1, disabled: isLoading }), currentStep === 0 && (_jsx(Div, { paddingX: "x-5", padding: "b-sm", children: _jsx(Button, { variant: "ghost", size: "sm", onClick: () => void handleSave(), disabled: isLoading || !draft.title?.trim(), children: "Save as draft & finish later" }) })), stepError && (_jsx(Text, { className: "text-[var(--appkit-color-error)] px-[1.25rem] pb-[0.75rem]", size: "sm", children: stepError })), _jsx(FormShellContext.Provider, { value: wizardShellCtx, children: _jsx(Div, { paddingX: "x-5", padding: "b-sm", children: _jsx(FormErrorSummary, {}) }) })] })), children: _jsx(FormShellContext.Provider, { value: wizardShellCtx, children: _jsx(StepForm, { steps: steps, values: draft, onChange: update, onComplete: handlePublish, completeLabel: `Publish ${listingTypeLabel}`, currentStep: currentStep, onStepChange: setCurrentStep, isLoading: isLoading, hideActions: true, stepErrors: stepValidationErrors }) }) }));
397
450
  }
398
451
  // Edit mode — FormShell with section nav + full form
399
452
  const editSections = [
400
453
  ...EDIT_SECTIONS,
401
454
  ...(typeSpecificStep ? [{ id: typeSpecificStep.id, label: typeSpecificStep.label }] : []),
402
455
  ];
403
- return (_jsx(FormShell, { isOpen: true, onClose: handleDiscard, title: title, breadcrumb: breadcrumb, isDirty: isDirty, isLoading: isLoading, sections: editSections, onSaveDraft: handleSave, onPublish: handlePublish, saveLabel: "Save Changes", publishLabel: "Update", previewSlot: previewSlot, children: _jsx(FormShellProvider, { isDirty: isDirty, values: draft, onSaveDraft: handleAutoSave, children: _jsxs(Stack, { gap: "lg", children: [_jsxs(Section, { id: "basic", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Basic Info" }), _jsx(StepBasic, { values: draft, onChange: update, renderCategorySelector: renderCategorySelector, renderBrandSelector: renderBrandSelector, renderTemplateSelector: renderTemplateSelector })] }), _jsxs(Section, { id: "media", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Media" }), _jsx(StepMedia, { values: draft, onChange: update, storeSlug: storeSlug })] }), typeSpecificStep && (_jsxs(Section, { id: typeSpecificStep.id, children: [_jsx(Heading, { level: 3, className: "mb-4", children: typeSpecificStep.sectionHeading ?? typeSpecificStep.label }), typeSpecificStep.render({ values: draft, onChange: update, errors: {} })] })), _jsxs(Section, { id: "pricing", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Pricing" }), _jsx(StepPricing, { values: draft, onChange: update, listingType: listingType })] }), _jsxs(Section, { id: "shipping", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Shipping" }), _jsx(StepShipping, { values: draft, onChange: update, renderAddressSelector: renderAddressSelector })] }), _jsxs(Section, { id: "publish", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Publish" }), _jsx(StepPublish, { values: draft, onChange: update }), onSaveAsTemplate && (_jsxs(Div, { className: "mt-4 border-t border-[var(--appkit-color-border)]", padding: "t-md", children: [_jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => onSaveAsTemplate(draft), children: "Save as Template" }), _jsx(Text, { className: "mt-1 text-[var(--appkit-color-secondary-text)]", size: "xs", children: "Save these settings as a reusable template for future listings." })] }))] })] }) }) }));
456
+ return (_jsx(FormShell, { isOpen: true, onClose: handleDiscard, title: title, breadcrumb: breadcrumb, isDirty: isDirty, isLoading: isLoading, sections: editSections, onSaveDraft: handleSave, onPublish: handlePublish, saveLabel: "Save Changes", publishLabel: "Update", previewSlot: previewSlot, footerTopSlot: _jsx(FormShellContext.Provider, { value: shellCtx, children: _jsx(FormErrorSummary, {}) }), children: _jsx(FormShellContext.Provider, { value: shellCtx, children: _jsxs(Stack, { gap: "lg", children: [_jsxs(Section, { id: "basic", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Basic Info" }), _jsx(StepBasic, { values: draft, onChange: update, renderCategorySelector: renderCategorySelector, renderBrandSelector: renderBrandSelector, renderTemplateSelector: renderTemplateSelector })] }), _jsxs(Section, { id: "media", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Media" }), _jsx(StepMedia, { values: draft, onChange: update, storeSlug: storeSlug })] }), typeSpecificStep && (_jsxs(Section, { id: typeSpecificStep.id, children: [_jsx(Heading, { level: 3, className: "mb-4", children: typeSpecificStep.sectionHeading ?? typeSpecificStep.label }), typeSpecificStep.render({ values: draft, onChange: update, errors: {} })] })), _jsxs(Section, { id: "pricing", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Pricing" }), _jsx(StepPricing, { values: draft, onChange: update, listingType: listingType })] }), _jsxs(Section, { id: "shipping", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Shipping" }), _jsx(StepShipping, { values: draft, onChange: update, renderAddressSelector: renderAddressSelector })] }), _jsxs(Section, { id: "publish", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Publish" }), _jsx(StepPublish, { values: draft, onChange: update }), onSaveAsTemplate && (_jsxs(Div, { className: "mt-4 border-t border-[var(--appkit-color-border)]", padding: "t-md", children: [_jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => onSaveAsTemplate(draft), children: "Save as Template" }), _jsx(Text, { className: "mt-1 text-[var(--appkit-color-secondary-text)]", size: "xs", children: "Save these settings as a reusable template for future listings." })] }))] })] }) }) }));
404
457
  }
@@ -1,15 +1,10 @@
1
1
  import React from "react";
2
- export interface SellerProductsFilterDrawerProps {
3
- isOpen: boolean;
2
+ export interface SellerProductsFilterFieldsProps {
4
3
  pendingFilters: Record<string, string>;
5
4
  statusOptions: ReadonlyArray<{
6
5
  id: string;
7
6
  label: string;
8
7
  }>;
9
- activeFilterCount: number;
10
8
  onChange: (next: Record<string, string>) => void;
11
- onClear: () => void;
12
- onApply: () => void;
13
- onClose: () => void;
14
9
  }
15
- export declare function SellerProductsFilterDrawer({ isOpen, pendingFilters, statusOptions, activeFilterCount, onChange, onClear, onApply, onClose, }: SellerProductsFilterDrawerProps): React.JSX.Element;
10
+ export declare function SellerProductsFilterFields({ pendingFilters, statusOptions, onChange, }: SellerProductsFilterFieldsProps): React.JSX.Element;
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Div, FilterChipGroup, ListingFilterDrawer, Row, Stack, Text } from "../../../ui";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { Div, FilterChipGroup, Row, Stack, Text } from "../../../ui";
4
4
  import { FieldInput, FieldSelect } from "../../../ui/forms";
5
5
  import { CategoryInlineSelect } from "./CategoryInlineSelect";
6
6
  import { BrandInlineSelect } from "./BrandInlineSelect";
@@ -12,7 +12,7 @@ const CONDITION_OPTIONS = [
12
12
  { value: "refurbished", label: "Refurbished" },
13
13
  { value: "for-parts", label: "For parts" },
14
14
  ];
15
- export function SellerProductsFilterDrawer({ isOpen, pendingFilters, statusOptions, activeFilterCount, onChange, onClear, onApply, onClose, }) {
15
+ export function SellerProductsFilterFields({ pendingFilters, statusOptions, onChange, }) {
16
16
  const patch = (k, v) => onChange({ ...pendingFilters, [k]: v });
17
- return (_jsxs(ListingFilterDrawer, { open: isOpen, onClose: onClose, onApply: onApply, onClear: onClear, activeCount: activeFilterCount, children: [_jsx(FilterChipGroup, { label: "Status", tabs: statusOptions, value: pendingFilters.status ?? "", onChange: (id) => patch("status", id) }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", weight: "semibold", color: "muted", transform: "uppercase", children: "Category" }), _jsx(CategoryInlineSelect, { value: pendingFilters.category ?? "", onChange: (v) => patch("category", v), placeholder: "Search categories\u2026" })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", weight: "semibold", color: "muted", transform: "uppercase", children: "Brand" }), _jsx(BrandInlineSelect, { value: pendingFilters.brand ?? "", onChange: (v) => patch("brand", v), placeholder: "Search brands\u2026", allowCreate: false })] }), _jsx(FieldSelect, { name: "condition", label: "Condition", value: pendingFilters.condition ?? "", onChange: (v) => patch("condition", v), options: CONDITION_OPTIONS }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", weight: "semibold", color: "muted", transform: "uppercase", children: "Price (\u20B9 Rupees)" }), _jsxs(Row, { gap: "sm", children: [_jsx(Div, { className: "flex-1", children: _jsx(FieldInput, { name: "minPrice", type: "number", min: 0, value: pendingFilters.minPrice ?? "", onChange: (v) => patch("minPrice", v), placeholder: "min" }) }), _jsx(Div, { className: "flex-1", children: _jsx(FieldInput, { name: "maxPrice", type: "number", min: 0, value: pendingFilters.maxPrice ?? "", onChange: (v) => patch("maxPrice", v), placeholder: "max" }) })] })] }), _jsx(FieldInput, { name: "tags", label: "Tags (comma-separated)", type: "text", value: pendingFilters.tags ?? "", onChange: (v) => patch("tags", v), placeholder: "pokemon, vintage, holo" }), _jsx(FieldInput, { name: "badges", label: "Badges (feature slugs)", type: "text", value: pendingFilters.badges ?? "", onChange: (v) => patch("badges", v), placeholder: "feature-free-shipping, feature-verified" })] }));
17
+ return (_jsxs(_Fragment, { children: [_jsx(FilterChipGroup, { label: "Status", tabs: statusOptions, value: pendingFilters.status ?? "", onChange: (id) => patch("status", id) }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", weight: "semibold", color: "muted", transform: "uppercase", children: "Category" }), _jsx(CategoryInlineSelect, { value: pendingFilters.category ?? "", onChange: (v) => patch("category", v), placeholder: "Search categories\u2026" })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", weight: "semibold", color: "muted", transform: "uppercase", children: "Brand" }), _jsx(BrandInlineSelect, { value: pendingFilters.brand ?? "", onChange: (v) => patch("brand", v), placeholder: "Search brands\u2026", allowCreate: false })] }), _jsx(FieldSelect, { name: "condition", label: "Condition", value: pendingFilters.condition ?? "", onChange: (v) => patch("condition", v), options: CONDITION_OPTIONS }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", weight: "semibold", color: "muted", transform: "uppercase", children: "Price (\u20B9 Rupees)" }), _jsxs(Row, { gap: "sm", children: [_jsx(Div, { className: "flex-1", children: _jsx(FieldInput, { name: "minPrice", type: "number", min: 0, value: pendingFilters.minPrice ?? "", onChange: (v) => patch("minPrice", v), placeholder: "min" }) }), _jsx(Div, { className: "flex-1", children: _jsx(FieldInput, { name: "maxPrice", type: "number", min: 0, value: pendingFilters.maxPrice ?? "", onChange: (v) => patch("maxPrice", v), placeholder: "max" }) })] })] }), _jsx(FieldInput, { name: "tags", label: "Tags (comma-separated)", type: "text", value: pendingFilters.tags ?? "", onChange: (v) => patch("tags", v), placeholder: "pokemon, vintage, holo" }), _jsx(FieldInput, { name: "badges", label: "Badges (feature slugs)", type: "text", value: pendingFilters.badges ?? "", onChange: (v) => patch("badges", v), placeholder: "feature-free-shipping, feature-verified" })] }));
18
18
  }
@@ -1,8 +1,6 @@
1
1
  import React from "react";
2
- import type { ListingLayoutProps } from "../../../ui";
3
- export interface SellerProductsViewProps extends ListingLayoutProps {
2
+ export interface SellerProductsViewProps {
4
3
  onDeleteProduct?: (id: string) => Promise<void>;
5
- /** S-STORE-2-E — "New Listing" toolbar button. */
6
4
  onCreateClick?: () => void;
7
5
  }
8
- export declare function SellerProductsView({ onDeleteProduct, onCreateClick, children, ...props }: SellerProductsViewProps): React.JSX.Element;
6
+ export declare function SellerProductsView({ onDeleteProduct, onCreateClick, }: SellerProductsViewProps): React.JSX.Element;