@mohasinac/appkit 2.4.10 → 2.5.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 (889) hide show
  1. package/dist/_internal/client/features/products/index.d.ts +1 -0
  2. package/dist/_internal/client/features/products/index.js +3 -0
  3. package/dist/_internal/client/i18n/LabelsProvider.d.ts +13 -0
  4. package/dist/_internal/client/i18n/LabelsProvider.js +38 -0
  5. package/dist/_internal/client/index.d.ts +0 -0
  6. package/dist/_internal/client/index.js +4 -0
  7. package/dist/_internal/client/scaffolds/AppShell.d.ts +39 -0
  8. package/dist/_internal/client/scaffolds/AppShell.js +9 -0
  9. package/dist/_internal/client/scaffolds/DashboardScaffold.d.ts +34 -0
  10. package/dist/_internal/client/scaffolds/DashboardScaffold.js +23 -0
  11. package/dist/_internal/client/scaffolds/index.d.ts +4 -0
  12. package/dist/_internal/client/scaffolds/index.js +2 -0
  13. package/dist/_internal/server/features/account/actions.d.ts +7 -0
  14. package/dist/_internal/server/features/account/actions.js +7 -0
  15. package/dist/_internal/server/features/account/data.d.ts +17 -0
  16. package/dist/_internal/server/features/account/data.js +25 -0
  17. package/dist/_internal/server/features/account/index.d.ts +2 -0
  18. package/dist/_internal/server/features/account/index.js +2 -0
  19. package/dist/_internal/server/features/auctions/actions.d.ts +1 -0
  20. package/dist/_internal/server/features/auctions/actions.js +44 -0
  21. package/dist/_internal/server/features/auctions/data.d.ts +4 -0
  22. package/dist/_internal/server/features/auctions/data.js +9 -0
  23. package/dist/_internal/server/features/auctions/index.d.ts +5 -0
  24. package/dist/_internal/server/features/auctions/index.js +5 -0
  25. package/dist/_internal/server/features/auctions/og.d.ts +19 -0
  26. package/dist/_internal/server/features/auctions/og.js +51 -0
  27. package/dist/_internal/server/features/auctions/service.d.ts +13 -0
  28. package/dist/_internal/server/features/auctions/service.js +57 -0
  29. package/dist/_internal/server/features/auth/actions.d.ts +8 -0
  30. package/dist/_internal/server/features/auth/actions.js +8 -0
  31. package/dist/_internal/server/features/auth/index.d.ts +1 -0
  32. package/dist/_internal/server/features/auth/index.js +1 -0
  33. package/dist/_internal/server/features/blog/actions.d.ts +5 -0
  34. package/dist/_internal/server/features/blog/actions.js +51 -0
  35. package/dist/_internal/server/features/blog/data.d.ts +2 -0
  36. package/dist/_internal/server/features/blog/data.js +8 -0
  37. package/dist/_internal/server/features/blog/index.d.ts +5 -0
  38. package/dist/_internal/server/features/blog/index.js +5 -0
  39. package/dist/_internal/server/features/blog/og.d.ts +23 -0
  40. package/dist/_internal/server/features/blog/og.js +64 -0
  41. package/dist/_internal/server/features/blog/service.d.ts +3 -0
  42. package/dist/_internal/server/features/blog/service.js +18 -0
  43. package/dist/_internal/server/features/brands/actions.d.ts +4 -0
  44. package/dist/_internal/server/features/brands/actions.js +32 -0
  45. package/dist/_internal/server/features/brands/data.d.ts +12 -0
  46. package/dist/_internal/server/features/brands/data.js +16 -0
  47. package/dist/_internal/server/features/brands/index.d.ts +5 -0
  48. package/dist/_internal/server/features/brands/index.js +5 -0
  49. package/dist/_internal/server/features/brands/og.d.ts +17 -0
  50. package/dist/_internal/server/features/brands/og.js +37 -0
  51. package/dist/_internal/server/features/brands/service.d.ts +3 -0
  52. package/dist/_internal/server/features/brands/service.js +14 -0
  53. package/dist/_internal/server/features/bundles/data.d.ts +9 -0
  54. package/dist/_internal/server/features/bundles/data.js +9 -0
  55. package/dist/_internal/server/features/bundles/index.d.ts +2 -0
  56. package/dist/_internal/server/features/bundles/index.js +2 -0
  57. package/dist/_internal/server/features/cart/actions.d.ts +12 -0
  58. package/dist/_internal/server/features/cart/actions.js +35 -0
  59. package/dist/_internal/server/features/cart/data.d.ts +1 -0
  60. package/dist/_internal/server/features/cart/data.js +5 -0
  61. package/dist/_internal/server/features/cart/index.d.ts +4 -0
  62. package/dist/_internal/server/features/cart/index.js +4 -0
  63. package/dist/_internal/server/features/cart/service.d.ts +8 -0
  64. package/dist/_internal/server/features/cart/service.js +25 -0
  65. package/dist/_internal/server/features/categories/data.d.ts +13 -0
  66. package/dist/_internal/server/features/categories/data.js +40 -0
  67. package/dist/_internal/server/features/categories/index.d.ts +2 -0
  68. package/dist/_internal/server/features/categories/index.js +2 -0
  69. package/dist/_internal/server/features/checkout/actions.d.ts +35 -0
  70. package/dist/_internal/server/features/checkout/actions.js +327 -0
  71. package/dist/_internal/server/features/checkout/data.d.ts +13 -0
  72. package/dist/_internal/server/features/checkout/data.js +13 -0
  73. package/dist/_internal/server/features/checkout/index.d.ts +3 -0
  74. package/dist/_internal/server/features/checkout/index.js +3 -0
  75. package/dist/_internal/server/features/events/actions.d.ts +4 -0
  76. package/dist/_internal/server/features/events/actions.js +60 -0
  77. package/dist/_internal/server/features/events/data.d.ts +1 -0
  78. package/dist/_internal/server/features/events/data.js +5 -0
  79. package/dist/_internal/server/features/events/index.d.ts +5 -0
  80. package/dist/_internal/server/features/events/index.js +5 -0
  81. package/dist/_internal/server/features/events/og.d.ts +26 -0
  82. package/dist/_internal/server/features/events/og.js +87 -0
  83. package/dist/_internal/server/features/events/service.d.ts +2 -0
  84. package/dist/_internal/server/features/events/service.js +27 -0
  85. package/dist/_internal/server/features/grouped/data.d.ts +25 -0
  86. package/dist/_internal/server/features/grouped/data.js +116 -0
  87. package/dist/_internal/server/features/grouped/index.d.ts +2 -0
  88. package/dist/_internal/server/features/grouped/index.js +2 -0
  89. package/dist/_internal/server/features/history/actions.d.ts +8 -0
  90. package/dist/_internal/server/features/history/actions.js +15 -0
  91. package/dist/_internal/server/features/history/data.d.ts +7 -0
  92. package/dist/_internal/server/features/history/data.js +6 -0
  93. package/dist/_internal/server/features/history/index.d.ts +3 -0
  94. package/dist/_internal/server/features/history/index.js +3 -0
  95. package/dist/_internal/server/features/homepage/data.d.ts +18 -0
  96. package/dist/_internal/server/features/homepage/data.js +39 -0
  97. package/dist/_internal/server/features/homepage/index.d.ts +2 -0
  98. package/dist/_internal/server/features/homepage/index.js +2 -0
  99. package/dist/_internal/server/features/messages/actions.d.ts +6 -0
  100. package/dist/_internal/server/features/messages/actions.js +6 -0
  101. package/dist/_internal/server/features/messages/data.d.ts +10 -0
  102. package/dist/_internal/server/features/messages/data.js +24 -0
  103. package/dist/_internal/server/features/messages/index.d.ts +2 -0
  104. package/dist/_internal/server/features/messages/index.js +2 -0
  105. package/dist/_internal/server/features/orders/actions.d.ts +4 -0
  106. package/dist/_internal/server/features/orders/actions.js +50 -0
  107. package/dist/_internal/server/features/orders/adapters.d.ts +3 -0
  108. package/dist/_internal/server/features/orders/adapters.js +56 -0
  109. package/dist/_internal/server/features/orders/data.d.ts +10 -0
  110. package/dist/_internal/server/features/orders/data.js +18 -0
  111. package/dist/_internal/server/features/orders/index.d.ts +5 -0
  112. package/dist/_internal/server/features/orders/index.js +5 -0
  113. package/dist/_internal/server/features/orders/service.d.ts +4 -0
  114. package/dist/_internal/server/features/orders/service.js +30 -0
  115. package/dist/_internal/server/features/payments/actions.d.ts +30 -0
  116. package/dist/_internal/server/features/payments/actions.js +45 -0
  117. package/dist/_internal/server/features/payments/data.d.ts +11 -0
  118. package/dist/_internal/server/features/payments/data.js +14 -0
  119. package/dist/_internal/server/features/payments/index.d.ts +3 -0
  120. package/dist/_internal/server/features/payments/index.js +3 -0
  121. package/dist/_internal/server/features/pre-orders/actions.d.ts +7 -0
  122. package/dist/_internal/server/features/pre-orders/actions.js +26 -0
  123. package/dist/_internal/server/features/pre-orders/data.d.ts +4 -0
  124. package/dist/_internal/server/features/pre-orders/data.js +9 -0
  125. package/dist/_internal/server/features/pre-orders/index.d.ts +5 -0
  126. package/dist/_internal/server/features/pre-orders/index.js +5 -0
  127. package/dist/_internal/server/features/pre-orders/og.d.ts +19 -0
  128. package/dist/_internal/server/features/pre-orders/og.js +49 -0
  129. package/dist/_internal/server/features/pre-orders/service.d.ts +7 -0
  130. package/dist/_internal/server/features/pre-orders/service.js +30 -0
  131. package/dist/_internal/server/features/products/actions.d.ts +7 -0
  132. package/dist/_internal/server/features/products/actions.js +74 -0
  133. package/dist/_internal/server/features/products/data.d.ts +14 -0
  134. package/dist/_internal/server/features/products/data.js +48 -0
  135. package/dist/_internal/server/features/products/index.d.ts +5 -0
  136. package/dist/_internal/server/features/products/index.js +5 -0
  137. package/dist/_internal/server/features/products/og.d.ts +19 -0
  138. package/dist/_internal/server/features/products/og.js +43 -0
  139. package/dist/_internal/server/features/products/service.d.ts +11 -0
  140. package/dist/_internal/server/features/products/service.js +55 -0
  141. package/dist/_internal/server/features/profile/index.d.ts +1 -0
  142. package/dist/_internal/server/features/profile/index.js +1 -0
  143. package/dist/_internal/server/features/profile/og.d.ts +26 -0
  144. package/dist/_internal/server/features/profile/og.js +91 -0
  145. package/dist/_internal/server/features/promotions/actions.d.ts +9 -0
  146. package/dist/_internal/server/features/promotions/actions.js +38 -0
  147. package/dist/_internal/server/features/promotions/data.d.ts +1 -0
  148. package/dist/_internal/server/features/promotions/data.js +5 -0
  149. package/dist/_internal/server/features/promotions/index.d.ts +4 -0
  150. package/dist/_internal/server/features/promotions/index.js +4 -0
  151. package/dist/_internal/server/features/promotions/service.d.ts +3 -0
  152. package/dist/_internal/server/features/promotions/service.js +47 -0
  153. package/dist/_internal/server/features/reviews/actions.d.ts +4 -0
  154. package/dist/_internal/server/features/reviews/actions.js +66 -0
  155. package/dist/_internal/server/features/reviews/data.d.ts +10 -0
  156. package/dist/_internal/server/features/reviews/data.js +18 -0
  157. package/dist/_internal/server/features/reviews/index.d.ts +3 -0
  158. package/dist/_internal/server/features/reviews/index.js +3 -0
  159. package/dist/_internal/server/features/reviews/service.d.ts +5 -0
  160. package/dist/_internal/server/features/reviews/service.js +27 -0
  161. package/dist/_internal/server/features/scams/data.d.ts +10 -0
  162. package/dist/_internal/server/features/scams/data.js +22 -0
  163. package/dist/_internal/server/features/scams/index.d.ts +1 -0
  164. package/dist/_internal/server/features/scams/index.js +1 -0
  165. package/dist/_internal/server/features/search/actions.d.ts +15 -0
  166. package/dist/_internal/server/features/search/actions.js +18 -0
  167. package/dist/_internal/server/features/search/data.d.ts +15 -0
  168. package/dist/_internal/server/features/search/data.js +18 -0
  169. package/dist/_internal/server/features/search/index.d.ts +3 -0
  170. package/dist/_internal/server/features/search/index.js +2 -0
  171. package/dist/_internal/server/features/stores/data.d.ts +31 -0
  172. package/dist/_internal/server/features/stores/data.js +58 -0
  173. package/dist/_internal/server/features/stores/index.d.ts +3 -0
  174. package/dist/_internal/server/features/stores/index.js +3 -0
  175. package/dist/_internal/server/features/stores/og.d.ts +19 -0
  176. package/dist/_internal/server/features/stores/og.js +52 -0
  177. package/dist/_internal/server/features/sublisting-categories/data.d.ts +1 -0
  178. package/dist/_internal/server/features/sublisting-categories/data.js +5 -0
  179. package/dist/_internal/server/features/sublisting-categories/index.d.ts +2 -0
  180. package/dist/_internal/server/features/sublisting-categories/index.js +2 -0
  181. package/dist/_internal/server/features/sublisting-categories/og.d.ts +20 -0
  182. package/dist/_internal/server/features/sublisting-categories/og.js +56 -0
  183. package/dist/_internal/server/features/wishlist/actions.d.ts +13 -0
  184. package/dist/_internal/server/features/wishlist/actions.js +40 -0
  185. package/dist/_internal/server/features/wishlist/data.d.ts +8 -0
  186. package/dist/_internal/server/features/wishlist/data.js +9 -0
  187. package/dist/_internal/server/features/wishlist/index.d.ts +4 -0
  188. package/dist/_internal/server/features/wishlist/index.js +4 -0
  189. package/dist/_internal/server/index.d.ts +0 -0
  190. package/dist/_internal/server/index.js +4 -0
  191. package/dist/_internal/server/jobs/handlers/_helpers.d.ts +8 -0
  192. package/dist/_internal/server/jobs/handlers/_helpers.js +19 -0
  193. package/dist/_internal/server/jobs/handlers/adminAnalytics.d.ts +28 -0
  194. package/dist/_internal/server/jobs/handlers/adminAnalytics.js +98 -0
  195. package/dist/_internal/server/jobs/handlers/auctionSettlement.d.ts +2 -0
  196. package/dist/_internal/server/jobs/handlers/auctionSettlement.js +70 -0
  197. package/dist/_internal/server/jobs/handlers/autoPayoutEligibility.d.ts +2 -0
  198. package/dist/_internal/server/jobs/handlers/autoPayoutEligibility.js +110 -0
  199. package/dist/_internal/server/jobs/handlers/cartPrune.d.ts +2 -0
  200. package/dist/_internal/server/jobs/handlers/cartPrune.js +13 -0
  201. package/dist/_internal/server/jobs/handlers/cleanupRtdbEvents.d.ts +2 -0
  202. package/dist/_internal/server/jobs/handlers/cleanupRtdbEvents.js +45 -0
  203. package/dist/_internal/server/jobs/handlers/countersReconcile.d.ts +2 -0
  204. package/dist/_internal/server/jobs/handlers/countersReconcile.js +109 -0
  205. package/dist/_internal/server/jobs/handlers/couponExpiry.d.ts +2 -0
  206. package/dist/_internal/server/jobs/handlers/couponExpiry.js +13 -0
  207. package/dist/_internal/server/jobs/handlers/dailyDataCleanup.d.ts +2 -0
  208. package/dist/_internal/server/jobs/handlers/dailyDataCleanup.js +20 -0
  209. package/dist/_internal/server/jobs/handlers/index.d.ts +35 -0
  210. package/dist/_internal/server/jobs/handlers/index.js +35 -0
  211. package/dist/_internal/server/jobs/handlers/listingProcessor.d.ts +30 -0
  212. package/dist/_internal/server/jobs/handlers/listingProcessor.js +128 -0
  213. package/dist/_internal/server/jobs/handlers/mediaTmpCleanup.d.ts +14 -0
  214. package/dist/_internal/server/jobs/handlers/mediaTmpCleanup.js +69 -0
  215. package/dist/_internal/server/jobs/handlers/messages.d.ts +45 -0
  216. package/dist/_internal/server/jobs/handlers/messages.js +45 -0
  217. package/dist/_internal/server/jobs/handlers/notificationPrune.d.ts +2 -0
  218. package/dist/_internal/server/jobs/handlers/notificationPrune.js +13 -0
  219. package/dist/_internal/server/jobs/handlers/offerExpiry.d.ts +2 -0
  220. package/dist/_internal/server/jobs/handlers/offerExpiry.js +50 -0
  221. package/dist/_internal/server/jobs/handlers/onBidPlaced.d.ts +12 -0
  222. package/dist/_internal/server/jobs/handlers/onBidPlaced.js +63 -0
  223. package/dist/_internal/server/jobs/handlers/onCategoryWrite.d.ts +10 -0
  224. package/dist/_internal/server/jobs/handlers/onCategoryWrite.js +136 -0
  225. package/dist/_internal/server/jobs/handlers/onOrderCreate.d.ts +14 -0
  226. package/dist/_internal/server/jobs/handlers/onOrderCreate.js +83 -0
  227. package/dist/_internal/server/jobs/handlers/onOrderStatusChange.d.ts +14 -0
  228. package/dist/_internal/server/jobs/handlers/onOrderStatusChange.js +141 -0
  229. package/dist/_internal/server/jobs/handlers/onProductWrite.d.ts +8 -0
  230. package/dist/_internal/server/jobs/handlers/onProductWrite.js +92 -0
  231. package/dist/_internal/server/jobs/handlers/onReviewWrite.d.ts +2 -0
  232. package/dist/_internal/server/jobs/handlers/onReviewWrite.js +51 -0
  233. package/dist/_internal/server/jobs/handlers/onStoreWrite.d.ts +10 -0
  234. package/dist/_internal/server/jobs/handlers/onStoreWrite.js +9 -0
  235. package/dist/_internal/server/jobs/handlers/payoutBatch.d.ts +11 -0
  236. package/dist/_internal/server/jobs/handlers/payoutBatch.js +104 -0
  237. package/dist/_internal/server/jobs/handlers/pendingOrderTimeout.d.ts +8 -0
  238. package/dist/_internal/server/jobs/handlers/pendingOrderTimeout.js +33 -0
  239. package/dist/_internal/server/jobs/handlers/positionsReconcile.d.ts +7 -0
  240. package/dist/_internal/server/jobs/handlers/positionsReconcile.js +87 -0
  241. package/dist/_internal/server/jobs/handlers/productStatsSync.d.ts +8 -0
  242. package/dist/_internal/server/jobs/handlers/productStatsSync.js +36 -0
  243. package/dist/_internal/server/jobs/handlers/promotions.d.ts +12 -0
  244. package/dist/_internal/server/jobs/handlers/promotions.js +43 -0
  245. package/dist/_internal/server/jobs/handlers/storeAnalytics.d.ts +30 -0
  246. package/dist/_internal/server/jobs/handlers/storeAnalytics.js +109 -0
  247. package/dist/_internal/server/jobs/handlers/weeklyPayoutEligibility.d.ts +8 -0
  248. package/dist/_internal/server/jobs/handlers/weeklyPayoutEligibility.js +87 -0
  249. package/dist/_internal/server/jobs/index.d.ts +4 -0
  250. package/dist/_internal/server/jobs/index.js +3 -0
  251. package/dist/_internal/server/jobs/runtime/adapters/firebase.d.ts +50 -0
  252. package/dist/_internal/server/jobs/runtime/adapters/firebase.js +156 -0
  253. package/dist/_internal/server/jobs/runtime/types.d.ts +52 -0
  254. package/dist/_internal/server/jobs/runtime/types.js +13 -0
  255. package/dist/_internal/shared/config/index.d.ts +1 -0
  256. package/dist/_internal/shared/config/index.js +1 -0
  257. package/dist/_internal/shared/config/schema.d.ts +82 -0
  258. package/dist/_internal/shared/config/schema.js +1 -0
  259. package/dist/_internal/shared/constants/index.d.ts +1 -0
  260. package/dist/_internal/shared/constants/index.js +1 -0
  261. package/dist/_internal/shared/errors/index.d.ts +24 -0
  262. package/dist/_internal/shared/errors/index.js +46 -0
  263. package/dist/_internal/shared/features/auctions/config.d.ts +6 -0
  264. package/dist/_internal/shared/features/auctions/config.js +6 -0
  265. package/dist/_internal/shared/features/auctions/errors.d.ts +16 -0
  266. package/dist/_internal/shared/features/auctions/errors.js +31 -0
  267. package/dist/_internal/shared/features/auctions/schema.d.ts +30 -0
  268. package/dist/_internal/shared/features/auctions/schema.js +12 -0
  269. package/dist/_internal/shared/features/blog/config.d.ts +6 -0
  270. package/dist/_internal/shared/features/blog/config.js +6 -0
  271. package/dist/_internal/shared/features/blog/errors.d.ts +10 -0
  272. package/dist/_internal/shared/features/blog/errors.js +19 -0
  273. package/dist/_internal/shared/features/blog/schema.d.ts +81 -0
  274. package/dist/_internal/shared/features/blog/schema.js +17 -0
  275. package/dist/_internal/shared/features/brands/config.d.ts +4 -0
  276. package/dist/_internal/shared/features/brands/config.js +4 -0
  277. package/dist/_internal/shared/features/brands/errors.d.ts +7 -0
  278. package/dist/_internal/shared/features/brands/errors.js +13 -0
  279. package/dist/_internal/shared/features/brands/schema.d.ts +69 -0
  280. package/dist/_internal/shared/features/brands/schema.js +15 -0
  281. package/dist/_internal/shared/features/bundles/config.d.ts +6 -0
  282. package/dist/_internal/shared/features/bundles/config.js +6 -0
  283. package/dist/_internal/shared/features/cart/config.d.ts +3 -0
  284. package/dist/_internal/shared/features/cart/config.js +3 -0
  285. package/dist/_internal/shared/features/cart/errors.d.ts +10 -0
  286. package/dist/_internal/shared/features/cart/errors.js +19 -0
  287. package/dist/_internal/shared/features/cart/schema.d.ts +132 -0
  288. package/dist/_internal/shared/features/cart/schema.js +33 -0
  289. package/dist/_internal/shared/features/categories/config.d.ts +6 -0
  290. package/dist/_internal/shared/features/categories/config.js +6 -0
  291. package/dist/_internal/shared/features/checkout/config.d.ts +8 -0
  292. package/dist/_internal/shared/features/checkout/config.js +7 -0
  293. package/dist/_internal/shared/features/events/config.d.ts +5 -0
  294. package/dist/_internal/shared/features/events/config.js +5 -0
  295. package/dist/_internal/shared/features/events/errors.d.ts +16 -0
  296. package/dist/_internal/shared/features/events/errors.js +31 -0
  297. package/dist/_internal/shared/features/events/schema.d.ts +91 -0
  298. package/dist/_internal/shared/features/events/schema.js +21 -0
  299. package/dist/_internal/shared/features/grouped/config.d.ts +3 -0
  300. package/dist/_internal/shared/features/grouped/config.js +3 -0
  301. package/dist/_internal/shared/features/history/config.d.ts +2 -0
  302. package/dist/_internal/shared/features/history/config.js +2 -0
  303. package/dist/_internal/shared/features/homepage/config.d.ts +3 -0
  304. package/dist/_internal/shared/features/homepage/config.js +3 -0
  305. package/dist/_internal/shared/features/orders/config.d.ts +8 -0
  306. package/dist/_internal/shared/features/orders/config.js +8 -0
  307. package/dist/_internal/shared/features/orders/errors.d.ts +13 -0
  308. package/dist/_internal/shared/features/orders/errors.js +25 -0
  309. package/dist/_internal/shared/features/orders/schema.d.ts +114 -0
  310. package/dist/_internal/shared/features/orders/schema.js +33 -0
  311. package/dist/_internal/shared/features/payments/config.d.ts +2 -0
  312. package/dist/_internal/shared/features/payments/config.js +2 -0
  313. package/dist/_internal/shared/features/pre-orders/config.d.ts +4 -0
  314. package/dist/_internal/shared/features/pre-orders/config.js +4 -0
  315. package/dist/_internal/shared/features/pre-orders/errors.d.ts +13 -0
  316. package/dist/_internal/shared/features/pre-orders/errors.js +25 -0
  317. package/dist/_internal/shared/features/pre-orders/schema.d.ts +25 -0
  318. package/dist/_internal/shared/features/pre-orders/schema.js +10 -0
  319. package/dist/_internal/shared/features/products/config.d.ts +5 -0
  320. package/dist/_internal/shared/features/products/config.js +5 -0
  321. package/dist/_internal/shared/features/products/errors.d.ts +16 -0
  322. package/dist/_internal/shared/features/products/errors.js +31 -0
  323. package/dist/_internal/shared/features/products/schema.d.ts +364 -0
  324. package/dist/_internal/shared/features/products/schema.js +58 -0
  325. package/dist/_internal/shared/features/products/types.d.ts +46 -0
  326. package/dist/_internal/shared/features/products/types.js +1 -0
  327. package/dist/_internal/shared/features/promotions/config.d.ts +3 -0
  328. package/dist/_internal/shared/features/promotions/config.js +3 -0
  329. package/dist/_internal/shared/features/promotions/errors.d.ts +19 -0
  330. package/dist/_internal/shared/features/promotions/errors.js +37 -0
  331. package/dist/_internal/shared/features/promotions/schema.d.ts +242 -0
  332. package/dist/_internal/shared/features/promotions/schema.js +37 -0
  333. package/dist/_internal/shared/features/reviews/config.d.ts +8 -0
  334. package/dist/_internal/shared/features/reviews/config.js +8 -0
  335. package/dist/_internal/shared/features/reviews/errors.d.ts +13 -0
  336. package/dist/_internal/shared/features/reviews/errors.js +25 -0
  337. package/dist/_internal/shared/features/reviews/schema.d.ts +44 -0
  338. package/dist/_internal/shared/features/reviews/schema.js +18 -0
  339. package/dist/_internal/shared/features/stores/config.d.ts +4 -0
  340. package/dist/_internal/shared/features/stores/config.js +4 -0
  341. package/dist/_internal/shared/features/wishlist/config.d.ts +2 -0
  342. package/dist/_internal/shared/features/wishlist/config.js +2 -0
  343. package/dist/_internal/shared/features/wishlist/errors.d.ts +4 -0
  344. package/dist/_internal/shared/features/wishlist/errors.js +7 -0
  345. package/dist/_internal/shared/index.d.ts +2 -0
  346. package/dist/_internal/shared/index.js +4 -0
  347. package/dist/_internal/shared/serialization/index.d.ts +17 -0
  348. package/dist/_internal/shared/serialization/index.js +42 -0
  349. package/dist/_internal/shared/tokens/index.d.ts +137 -0
  350. package/dist/_internal/shared/tokens/index.js +159 -0
  351. package/dist/client-entry.d.ts +23 -0
  352. package/dist/client-entry.js +27 -0
  353. package/dist/client.d.ts +47 -5
  354. package/dist/client.js +68 -33
  355. package/dist/configs/eslint.d.ts +29 -0
  356. package/dist/configs/eslint.js +38 -0
  357. package/dist/configs/index.d.ts +14 -0
  358. package/dist/configs/index.js +14 -0
  359. package/dist/configs/next.d.ts +38 -0
  360. package/dist/configs/next.js +116 -0
  361. package/dist/configs/postcss.d.ts +22 -0
  362. package/dist/configs/postcss.js +22 -0
  363. package/dist/configs/tailwind.d.ts +59 -0
  364. package/dist/configs/tailwind.js +62 -0
  365. package/dist/constants/api-endpoints.d.ts +24 -0
  366. package/dist/constants/api-endpoints.js +8 -0
  367. package/dist/constants/index.d.ts +1 -0
  368. package/dist/constants/index.js +1 -0
  369. package/dist/constants/limits.d.ts +15 -0
  370. package/dist/constants/limits.js +15 -0
  371. package/dist/contracts/client-auth.d.ts +2 -0
  372. package/dist/errors/messages.d.ts +23 -0
  373. package/dist/errors/messages.js +25 -0
  374. package/dist/features/about/components/PublicProfileView.js +16 -9
  375. package/dist/features/account/components/AddressBook.d.ts +2 -1
  376. package/dist/features/account/components/AddressBook.js +2 -2
  377. package/dist/features/account/components/UserReturnsView.d.ts +10 -0
  378. package/dist/features/account/components/UserReturnsView.js +5 -0
  379. package/dist/features/account/components/index.d.ts +2 -0
  380. package/dist/features/account/components/index.js +1 -0
  381. package/dist/features/account/hooks/useProfile.d.ts +2 -0
  382. package/dist/features/account/schemas/index.d.ts +18 -18
  383. package/dist/features/admin/actions/chat-actions.d.ts +1 -1
  384. package/dist/features/admin/actions/chat-actions.js +10 -10
  385. package/dist/features/admin/components/AdminBlogEditorView.d.ts +2 -1
  386. package/dist/features/admin/components/AdminBlogEditorView.js +16 -14
  387. package/dist/features/admin/components/AdminBlogView.js +6 -3
  388. package/dist/features/admin/components/AdminBrandEditorView.d.ts +3 -1
  389. package/dist/features/admin/components/AdminBrandEditorView.js +16 -14
  390. package/dist/features/admin/components/AdminBrandsView.js +6 -3
  391. package/dist/features/admin/components/AdminCategoriesView.js +6 -3
  392. package/dist/features/admin/components/AdminCategoryEditorView.d.ts +2 -1
  393. package/dist/features/admin/components/AdminCategoryEditorView.js +16 -14
  394. package/dist/features/admin/components/AdminCouponEditorView.d.ts +2 -1
  395. package/dist/features/admin/components/AdminCouponEditorView.js +16 -14
  396. package/dist/features/admin/components/AdminCouponsView.js +6 -3
  397. package/dist/features/admin/components/AdminFaqEditorView.d.ts +2 -1
  398. package/dist/features/admin/components/AdminFaqEditorView.js +16 -14
  399. package/dist/features/admin/components/AdminFaqsView.js +6 -3
  400. package/dist/features/admin/components/AdminFeatureEditorView.d.ts +19 -0
  401. package/dist/features/admin/components/AdminFeatureEditorView.js +150 -0
  402. package/dist/features/admin/components/AdminFeaturesView.d.ts +4 -0
  403. package/dist/features/admin/components/AdminFeaturesView.js +95 -0
  404. package/dist/features/admin/components/AdminHistoryView.d.ts +4 -0
  405. package/dist/features/admin/components/AdminHistoryView.js +57 -0
  406. package/dist/features/admin/components/AdminMediaView.js +64 -2
  407. package/dist/features/admin/components/AdminOrdersView.js +31 -4
  408. package/dist/features/admin/components/AdminProductEditorView.d.ts +2 -1
  409. package/dist/features/admin/components/AdminProductEditorView.js +30 -19
  410. package/dist/features/admin/components/AdminProductsView.js +40 -3
  411. package/dist/features/admin/components/AdminSectionsView.js +138 -2
  412. package/dist/features/admin/components/AdminSiteSettingsView.js +22 -2
  413. package/dist/features/admin/components/AdminStoresView.js +5 -4
  414. package/dist/features/admin/components/AdminUserEditorView.d.ts +4 -1
  415. package/dist/features/admin/components/AdminUserEditorView.js +2 -2
  416. package/dist/features/admin/components/AdminUsersView.js +1 -1
  417. package/dist/features/admin/components/AdminWishlistsView.js +17 -15
  418. package/dist/features/admin/components/DataTable.d.ts +2 -1
  419. package/dist/features/admin/components/DataTable.js +14 -12
  420. package/dist/features/admin/components/DrawerFormFooter.d.ts +9 -21
  421. package/dist/features/admin/components/DrawerFormFooter.js +10 -2
  422. package/dist/features/admin/components/QuickEditMenu.d.ts +20 -0
  423. package/dist/features/admin/components/QuickEditMenu.js +31 -0
  424. package/dist/features/admin/components/analytics/AdminAnalyticsCharts.js +11 -23
  425. package/dist/features/admin/components/index.d.ts +8 -0
  426. package/dist/features/admin/components/index.js +4 -0
  427. package/dist/features/admin/components/sections/adminSectionsBuildParse.d.ts +9 -1
  428. package/dist/features/admin/components/sections/adminSectionsBuildParse.js +169 -9
  429. package/dist/features/admin/components/sections/adminSectionsTypes.d.ts +62 -1
  430. package/dist/features/admin/components/sections/adminSectionsTypes.js +57 -4
  431. package/dist/features/admin/hooks/useChat.d.ts +1 -1
  432. package/dist/features/admin/repository/chat.repository.d.ts +2 -2
  433. package/dist/features/admin/repository/chat.repository.js +7 -7
  434. package/dist/features/admin/schemas/firestore.d.ts +42 -7
  435. package/dist/features/admin/schemas/firestore.js +7 -7
  436. package/dist/features/admin/types/product.types.d.ts +2 -2
  437. package/dist/features/auctions/actions/bid-actions.js +3 -2
  438. package/dist/features/auctions/components/AuctionDetailPageView.d.ts +11 -1
  439. package/dist/features/auctions/components/AuctionDetailPageView.js +80 -68
  440. package/dist/features/auctions/components/AuctionsListView.js +11 -6
  441. package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +2 -1
  442. package/dist/features/auctions/hooks/useAuctions.js +2 -1
  443. package/dist/features/auctions/repository/auctions.repository.js +4 -4
  444. package/dist/features/auctions/schemas/index.d.ts +24 -24
  445. package/dist/features/auctions/types/index.d.ts +2 -1
  446. package/dist/features/auth/hooks/useAuth.d.ts +8 -0
  447. package/dist/features/auth/hooks/useAuth.js +9 -0
  448. package/dist/features/auth/schemas/index.d.ts +2 -2
  449. package/dist/features/before-after/schemas/index.d.ts +2 -2
  450. package/dist/features/blog/actions/blog-actions.d.ts +63 -63
  451. package/dist/features/blog/components/BlogPostView.d.ts +3 -1
  452. package/dist/features/blog/components/BlogPostView.js +3 -2
  453. package/dist/features/blog/schemas/index.d.ts +41 -41
  454. package/dist/features/bundles/components/AdminBundleEditorView.d.ts +8 -0
  455. package/dist/features/bundles/components/AdminBundleEditorView.js +7 -0
  456. package/dist/features/bundles/components/BundleDetailPageView.d.ts +9 -0
  457. package/dist/features/bundles/components/BundleDetailPageView.js +45 -0
  458. package/dist/features/bundles/components/BundleForm.d.ts +12 -0
  459. package/dist/features/bundles/components/BundleForm.js +126 -0
  460. package/dist/features/bundles/components/BundleItemsPicker.d.ts +9 -0
  461. package/dist/features/bundles/components/BundleItemsPicker.js +77 -0
  462. package/dist/features/bundles/components/BundlesListingView.d.ts +17 -0
  463. package/dist/features/bundles/components/BundlesListingView.js +50 -0
  464. package/dist/features/bundles/components/FeaturedBundlesSection.d.ts +5 -0
  465. package/dist/features/bundles/components/FeaturedBundlesSection.js +55 -0
  466. package/dist/features/bundles/components/SellerBundleCreateView.d.ts +8 -0
  467. package/dist/features/bundles/components/SellerBundleCreateView.js +7 -0
  468. package/dist/features/bundles/components/SellerBundleEditView.d.ts +9 -0
  469. package/dist/features/bundles/components/SellerBundleEditView.js +7 -0
  470. package/dist/features/bundles/components/index.d.ts +16 -0
  471. package/dist/features/bundles/components/index.js +8 -0
  472. package/dist/features/bundles/constants/index.d.ts +32 -0
  473. package/dist/features/bundles/constants/index.js +35 -0
  474. package/dist/features/bundles/index.d.ts +2 -0
  475. package/dist/features/bundles/index.js +2 -0
  476. package/dist/features/bundles/repository/bundles.repository.d.ts +36 -0
  477. package/dist/features/bundles/repository/bundles.repository.js +148 -0
  478. package/dist/features/bundles/repository/index.d.ts +1 -0
  479. package/dist/features/bundles/repository/index.js +1 -0
  480. package/dist/features/bundles/schemas/firestore.d.ts +88 -0
  481. package/dist/features/bundles/schemas/firestore.js +29 -0
  482. package/dist/features/bundles/schemas/index.d.ts +1 -0
  483. package/dist/features/bundles/schemas/index.js +1 -0
  484. package/dist/features/cart/actions/cart-actions.js +2 -1
  485. package/dist/features/cart/repository/cart.repository.js +1 -2
  486. package/dist/features/cart/schemas/firestore.d.ts +9 -6
  487. package/dist/features/cart/schemas/firestore.js +1 -2
  488. package/dist/features/cart/schemas/index.d.ts +7 -7
  489. package/dist/features/cart/utils/guest-cart.d.ts +6 -0
  490. package/dist/features/cart/utils/guest-cart.js +14 -0
  491. package/dist/features/categories/components/BrandDetailPageView.d.ts +3 -1
  492. package/dist/features/categories/components/BrandDetailPageView.js +6 -6
  493. package/dist/features/categories/components/CategoryDetailPageView.js +3 -3
  494. package/dist/features/categories/components/CategoryProductsListing.js +1 -1
  495. package/dist/features/categories/schemas/index.d.ts +24 -24
  496. package/dist/features/collections/schemas/index.d.ts +3 -3
  497. package/dist/features/consultation/schemas/index.d.ts +7 -7
  498. package/dist/features/corporate/schemas/index.d.ts +1 -1
  499. package/dist/features/events/components/AdminEventEditorView.d.ts +2 -1
  500. package/dist/features/events/components/AdminEventEditorView.js +10 -8
  501. package/dist/features/events/components/AdminEventsView.js +6 -3
  502. package/dist/features/events/components/EventDetailView.d.ts +7 -1
  503. package/dist/features/events/components/EventDetailView.js +4 -1
  504. package/dist/features/events/components/EventRafflesSection.d.ts +12 -0
  505. package/dist/features/events/components/EventRafflesSection.js +17 -0
  506. package/dist/features/events/components/index.d.ts +2 -0
  507. package/dist/features/events/components/index.js +1 -0
  508. package/dist/features/events/schemas/index.d.ts +41 -41
  509. package/dist/features/faq/actions/faq-actions.d.ts +16 -16
  510. package/dist/features/faq/schemas/index.d.ts +12 -12
  511. package/dist/features/history/actions/history-actions.d.ts +24 -0
  512. package/dist/features/history/actions/history-actions.js +43 -0
  513. package/dist/features/history/actions/index.d.ts +1 -0
  514. package/dist/features/history/actions/index.js +1 -0
  515. package/dist/features/history/components/HistoryTracker.d.ts +8 -0
  516. package/dist/features/history/components/HistoryTracker.js +18 -0
  517. package/dist/features/history/hooks/useHistory.d.ts +16 -0
  518. package/dist/features/history/hooks/useHistory.js +148 -0
  519. package/dist/features/history/hooks/useHistoryMergeOnLogin.d.ts +1 -0
  520. package/dist/features/history/hooks/useHistoryMergeOnLogin.js +41 -0
  521. package/dist/features/history/index.d.ts +5 -0
  522. package/dist/features/history/index.js +4 -0
  523. package/dist/features/history/repository/user-history.repository.d.ts +59 -0
  524. package/dist/features/history/repository/user-history.repository.js +203 -0
  525. package/dist/features/history/server.d.ts +6 -0
  526. package/dist/features/history/server.js +6 -0
  527. package/dist/features/history/utils/guest-history.d.ts +24 -0
  528. package/dist/features/history/utils/guest-history.js +66 -0
  529. package/dist/features/homepage/actions/homepage-section-actions.d.ts +4 -4
  530. package/dist/features/homepage/components/BrandsSection.d.ts +7 -1
  531. package/dist/features/homepage/components/BrandsSection.js +26 -4
  532. package/dist/features/homepage/components/CollectionCardsSection.d.ts +13 -0
  533. package/dist/features/homepage/components/CollectionCardsSection.js +41 -0
  534. package/dist/features/homepage/components/FAQSection.d.ts +14 -4
  535. package/dist/features/homepage/components/FAQSection.js +63 -13
  536. package/dist/features/homepage/components/FeaturedProductsSection.d.ts +8 -1
  537. package/dist/features/homepage/components/FeaturedProductsSection.js +42 -2
  538. package/dist/features/homepage/components/MarketplaceHomepageView.js +17 -8
  539. package/dist/features/homepage/components/ShopByCategorySection.d.ts +8 -1
  540. package/dist/features/homepage/components/ShopByCategorySection.js +44 -4
  541. package/dist/features/homepage/components/SocialFeedSection.js +22 -2
  542. package/dist/features/homepage/components/SocialPostCard.js +20 -5
  543. package/dist/features/homepage/components/WelcomeSection.js +2 -2
  544. package/dist/features/homepage/components/WhatsAppCommunitySection.d.ts +0 -1
  545. package/dist/features/homepage/components/WhatsAppCommunitySection.js +4 -4
  546. package/dist/features/homepage/lib/live-stats.d.ts +18 -5
  547. package/dist/features/homepage/lib/live-stats.js +60 -29
  548. package/dist/features/homepage/lib/section-renderer.d.ts +2 -1
  549. package/dist/features/homepage/lib/section-renderer.js +50 -11
  550. package/dist/features/homepage/repository/carousels.repository.d.ts +38 -0
  551. package/dist/features/homepage/repository/carousels.repository.js +142 -0
  552. package/dist/features/homepage/schemas/firestore.d.ts +177 -21
  553. package/dist/features/homepage/schemas/firestore.js +24 -0
  554. package/dist/features/layout/AppLayoutShell.d.ts +3 -1
  555. package/dist/features/layout/AppLayoutShell.js +2 -2
  556. package/dist/features/layout/TitleBarLayout.d.ts +3 -1
  557. package/dist/features/layout/TitleBarLayout.js +5 -4
  558. package/dist/features/layout/index.d.ts +1 -1
  559. package/dist/features/media/MediaPickerModal.js +67 -3
  560. package/dist/features/media/types/index.d.ts +2 -2
  561. package/dist/features/media/upload/MediaUploadField.js +21 -5
  562. package/dist/features/messages/actions/index.d.ts +2 -0
  563. package/dist/features/messages/actions/index.js +2 -0
  564. package/dist/features/messages/actions/messages-actions.d.ts +15 -0
  565. package/dist/features/messages/actions/messages-actions.js +33 -0
  566. package/dist/features/messages/actions/ping-rtdb.d.ts +2 -0
  567. package/dist/features/messages/actions/ping-rtdb.js +24 -0
  568. package/dist/features/messages/hooks/useConversation.d.ts +22 -0
  569. package/dist/features/messages/hooks/useConversation.js +125 -0
  570. package/dist/features/messages/hooks/useConversations.d.ts +9 -0
  571. package/dist/features/messages/hooks/useConversations.js +62 -0
  572. package/dist/features/messages/index.d.ts +6 -0
  573. package/dist/features/messages/index.js +4 -0
  574. package/dist/features/messages/realtime.d.ts +32 -0
  575. package/dist/features/messages/realtime.js +39 -0
  576. package/dist/features/messages/repository/conversations.repository.d.ts +35 -0
  577. package/dist/features/messages/repository/conversations.repository.js +180 -0
  578. package/dist/features/messages/server.d.ts +6 -0
  579. package/dist/features/messages/server.js +6 -0
  580. package/dist/features/orders/schemas/firestore.d.ts +21 -0
  581. package/dist/features/orders/schemas/index.d.ts +28 -28
  582. package/dist/features/orders/utils/order-splitter.d.ts +12 -2
  583. package/dist/features/orders/utils/order-splitter.js +13 -2
  584. package/dist/features/payments/schemas/index.d.ts +6 -6
  585. package/dist/features/pre-orders/api/route.js +10 -11
  586. package/dist/features/pre-orders/components/PreOrderDetailPageView.d.ts +11 -1
  587. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +45 -35
  588. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +24 -7
  589. package/dist/features/pre-orders/components/PreOrdersListView.js +10 -5
  590. package/dist/features/pre-orders/schemas/index.d.ts +6 -6
  591. package/dist/features/products/actions/product-actions.d.ts +2 -2
  592. package/dist/features/products/actions/product-actions.js +21 -16
  593. package/dist/features/products/api/[id]/route.js +4 -4
  594. package/dist/features/products/api/route.js +21 -6
  595. package/dist/features/products/components/AuctionsIndexListing.js +1 -1
  596. package/dist/features/products/components/CompareOverlay.d.ts +51 -0
  597. package/dist/features/products/components/CompareOverlay.js +154 -0
  598. package/dist/features/products/components/FeatureBadge.d.ts +28 -0
  599. package/dist/features/products/components/FeatureBadge.js +63 -0
  600. package/dist/features/products/components/GroupSettingsPanel.js +1 -1
  601. package/dist/features/products/components/NonRefundableConsentModal.d.ts +23 -0
  602. package/dist/features/products/components/NonRefundableConsentModal.js +55 -0
  603. package/dist/features/products/components/PrizeDrawsSection.d.ts +12 -0
  604. package/dist/features/products/components/PrizeDrawsSection.js +17 -0
  605. package/dist/features/products/components/ProductDetailPageView.d.ts +16 -1
  606. package/dist/features/products/components/ProductDetailPageView.js +65 -60
  607. package/dist/features/products/components/ProductFeaturesContext.d.ts +9 -0
  608. package/dist/features/products/components/ProductFeaturesContext.js +11 -0
  609. package/dist/features/products/components/ProductFeaturesSelector.d.ts +12 -0
  610. package/dist/features/products/components/ProductFeaturesSelector.js +72 -0
  611. package/dist/features/products/components/ProductForm.js +9 -3
  612. package/dist/features/products/components/ProductGrid.js +9 -3
  613. package/dist/features/products/components/ProductsIndexListing.js +24 -8
  614. package/dist/features/products/components/ProductsIndexPageView.js +12 -7
  615. package/dist/features/products/components/ShowGroupSection.js +2 -1
  616. package/dist/features/products/components/SublistingCarouselSection.js +3 -2
  617. package/dist/features/products/components/index.d.ts +12 -0
  618. package/dist/features/products/components/index.js +6 -0
  619. package/dist/features/products/constants/action-defs.d.ts +209 -0
  620. package/dist/features/products/constants/action-defs.js +270 -0
  621. package/dist/features/products/constants/product-features.constants.d.ts +23 -0
  622. package/dist/features/products/constants/product-features.constants.js +50 -0
  623. package/dist/features/products/hooks/useProducts.d.ts +1 -0
  624. package/dist/features/products/hooks/useProducts.js +15 -6
  625. package/dist/features/products/hooks/useRelatedProducts.d.ts +5 -0
  626. package/dist/features/products/hooks/useRelatedProducts.js +9 -1
  627. package/dist/features/products/index.d.ts +3 -1
  628. package/dist/features/products/index.js +3 -1
  629. package/dist/features/products/repository/loadProductFeatures.d.ts +2 -0
  630. package/dist/features/products/repository/loadProductFeatures.js +23 -0
  631. package/dist/features/products/repository/product-features.repository.d.ts +27 -0
  632. package/dist/features/products/repository/product-features.repository.js +141 -0
  633. package/dist/features/products/repository/product-templates.repository.d.ts +12 -0
  634. package/dist/features/products/repository/product-templates.repository.js +61 -0
  635. package/dist/features/products/repository/products.repository.d.ts +16 -1
  636. package/dist/features/products/repository/products.repository.js +126 -6
  637. package/dist/features/products/schemas/firestore.d.ts +43 -5
  638. package/dist/features/products/schemas/firestore.js +6 -7
  639. package/dist/features/products/schemas/index.d.ts +147 -51
  640. package/dist/features/products/schemas/index.js +32 -3
  641. package/dist/features/products/schemas/product-features.d.ts +84 -0
  642. package/dist/features/products/schemas/product-features.js +33 -0
  643. package/dist/features/products/schemas/product-features.validators.d.ts +107 -0
  644. package/dist/features/products/schemas/product-features.validators.js +64 -0
  645. package/dist/features/products/schemas/product-templates.d.ts +28 -0
  646. package/dist/features/products/schemas/product-templates.js +6 -0
  647. package/dist/features/products/types/index.d.ts +13 -5
  648. package/dist/features/products/utils/listing-type.d.ts +23 -2
  649. package/dist/features/products/utils/listing-type.js +14 -7
  650. package/dist/features/products/utils/sanitize.d.ts +2 -0
  651. package/dist/features/products/utils/sanitize.js +25 -0
  652. package/dist/features/promotions/actions/coupon-actions.d.ts +2 -2
  653. package/dist/features/promotions/components/CouponsIndexListing.d.ts +4 -4
  654. package/dist/features/promotions/components/CouponsIndexListing.js +3 -3
  655. package/dist/features/promotions/hooks/useCouponValidate.d.ts +2 -2
  656. package/dist/features/promotions/repository/coupons.repository.d.ts +2 -2
  657. package/dist/features/promotions/repository/coupons.repository.js +5 -5
  658. package/dist/features/promotions/schemas/index.d.ts +18 -18
  659. package/dist/features/reviews/schemas/index.d.ts +16 -16
  660. package/dist/features/search/actions/search-actions.js +4 -5
  661. package/dist/features/search/api/route.js +13 -10
  662. package/dist/features/search/columns/index.d.ts +1 -1
  663. package/dist/features/search/columns/index.js +4 -4
  664. package/dist/features/search/repository/search.repository.js +4 -6
  665. package/dist/features/search/schemas/index.d.ts +5 -5
  666. package/dist/features/search/types/index.d.ts +4 -3
  667. package/dist/features/seller/actions/offer-actions.js +1 -2
  668. package/dist/features/seller/components/BrandInlineSelect.d.ts +9 -0
  669. package/dist/features/seller/components/BrandInlineSelect.js +26 -0
  670. package/dist/features/seller/components/CategoryInlineSelect.d.ts +9 -0
  671. package/dist/features/seller/components/CategoryInlineSelect.js +26 -0
  672. package/dist/features/seller/components/SellerFeaturesView.d.ts +1 -0
  673. package/dist/features/seller/components/SellerFeaturesView.js +61 -0
  674. package/dist/features/seller/components/SellerProductShell.d.ts +15 -1
  675. package/dist/features/seller/components/SellerProductShell.js +7 -7
  676. package/dist/features/seller/components/SellerProductsView.js +17 -17
  677. package/dist/features/seller/components/SellerStorefrontView.d.ts +7 -0
  678. package/dist/features/seller/components/SellerStorefrontView.js +12 -2
  679. package/dist/features/seller/components/analytics/SellerRevenueChart.js +9 -17
  680. package/dist/features/seller/components/index.d.ts +6 -0
  681. package/dist/features/seller/components/index.js +4 -0
  682. package/dist/features/seller/schemas/index.d.ts +26 -26
  683. package/dist/features/shell/FormShell.d.ts +9 -1
  684. package/dist/features/shell/FormShell.js +5 -3
  685. package/dist/features/stores/actions/store-query-actions.js +2 -2
  686. package/dist/features/stores/api/[storeSlug]/auctions/route.js +11 -15
  687. package/dist/features/stores/api/[storeSlug]/products/route.js +11 -15
  688. package/dist/features/stores/api/route.js +12 -14
  689. package/dist/features/stores/components/StoreAuctionsListing.d.ts +2 -4
  690. package/dist/features/stores/components/StoreAuctionsListing.js +3 -4
  691. package/dist/features/stores/components/StoreAuctionsPageView.js +1 -1
  692. package/dist/features/stores/components/StoreDetailLayoutView.js +3 -3
  693. package/dist/features/stores/components/StorePreOrdersListing.d.ts +1 -3
  694. package/dist/features/stores/components/StorePreOrdersListing.js +2 -3
  695. package/dist/features/stores/components/StorePreOrdersPageView.js +1 -1
  696. package/dist/features/stores/components/StoreProductsListing.d.ts +2 -4
  697. package/dist/features/stores/components/StoreProductsListing.js +2 -3
  698. package/dist/features/stores/components/StoreProductsPageView.d.ts +4 -1
  699. package/dist/features/stores/components/StoreProductsPageView.js +17 -11
  700. package/dist/features/stores/repository/store.repository.d.ts +10 -0
  701. package/dist/features/stores/repository/store.repository.js +39 -0
  702. package/dist/features/stores/schemas/firestore.d.ts +7 -0
  703. package/dist/features/stores/schemas/index.d.ts +8 -8
  704. package/dist/features/stores/types/index.d.ts +4 -3
  705. package/dist/features/wishlist/actions/wishlist-actions.d.ts +8 -6
  706. package/dist/features/wishlist/actions/wishlist-actions.js +9 -7
  707. package/dist/features/wishlist/components/WishlistCapWatcher.d.ts +1 -0
  708. package/dist/features/wishlist/components/WishlistCapWatcher.js +24 -0
  709. package/dist/features/wishlist/components/index.d.ts +1 -0
  710. package/dist/features/wishlist/components/index.js +1 -0
  711. package/dist/features/wishlist/hooks/useWishlistCount.d.ts +17 -0
  712. package/dist/features/wishlist/hooks/useWishlistCount.js +36 -1
  713. package/dist/features/wishlist/index.d.ts +2 -0
  714. package/dist/features/wishlist/index.js +1 -0
  715. package/dist/features/wishlist/repository/user-wishlist.repository.d.ts +52 -7
  716. package/dist/features/wishlist/repository/user-wishlist.repository.js +154 -44
  717. package/dist/features/wishlist/schemas/index.d.ts +2 -2
  718. package/dist/features/wishlist/server.d.ts +1 -1
  719. package/dist/features/wishlist/server.js +1 -1
  720. package/dist/features/wishlist/types/index.d.ts +2 -2
  721. package/dist/index.d.ts +87 -5
  722. package/dist/index.js +101 -12
  723. package/dist/next/api/routeHandler.d.ts +7 -0
  724. package/dist/next/api/routeHandler.js +8 -0
  725. package/dist/next/routing/route-map.d.ts +68 -0
  726. package/dist/next/routing/route-map.js +32 -0
  727. package/dist/providers/db-firebase/filter-aliases.d.ts +20 -0
  728. package/dist/providers/db-firebase/filter-aliases.js +29 -0
  729. package/dist/providers/db-firebase/index.d.ts +2 -2
  730. package/dist/providers/db-firebase/index.js +1 -1
  731. package/dist/providers/db-firebase/sieve.d.ts +9 -0
  732. package/dist/providers/db-firebase/sieve.js +24 -6
  733. package/dist/providers/firebase-client/auth.d.ts +1 -0
  734. package/dist/providers/firebase-client/auth.js +9 -1
  735. package/dist/providers/shipping-shiprocket/index.d.ts +9 -0
  736. package/dist/providers/shipping-shiprocket/index.js +11 -0
  737. package/dist/react/hooks/use-action-dispatch.d.ts +25 -0
  738. package/dist/react/hooks/use-action-dispatch.js +30 -0
  739. package/dist/react/hooks/use-panel-url-sync.d.ts +15 -0
  740. package/dist/react/hooks/use-panel-url-sync.js +46 -0
  741. package/dist/react/hooks/useInfiniteScroll.d.ts +52 -0
  742. package/dist/react/hooks/useInfiniteScroll.js +45 -0
  743. package/dist/repositories/index.d.ts +9 -1
  744. package/dist/repositories/index.js +8 -1
  745. package/dist/seed/_bundle-constants.d.ts +14 -0
  746. package/dist/seed/_bundle-constants.js +14 -0
  747. package/dist/seed/actions/demo-seed-actions.d.ts +1 -1
  748. package/dist/seed/bids-seed-data.js +165 -0
  749. package/dist/seed/blog-posts-seed-data.js +393 -0
  750. package/dist/seed/bundles-seed-data.d.ts +13 -0
  751. package/dist/seed/bundles-seed-data.js +229 -0
  752. package/dist/seed/carousels-seed-data.d.ts +2 -0
  753. package/dist/seed/carousels-seed-data.js +16 -0
  754. package/dist/seed/cart-seed-data.js +161 -16
  755. package/dist/seed/categories-seed-data.js +168 -0
  756. package/dist/seed/coupons-seed-data.js +174 -0
  757. package/dist/seed/events-seed-data.js +161 -0
  758. package/dist/seed/history-seed-data.d.ts +19 -0
  759. package/dist/seed/history-seed-data.js +61 -0
  760. package/dist/seed/homepage-sections-seed-data.js +97 -1
  761. package/dist/seed/index.d.ts +4 -3
  762. package/dist/seed/index.js +9 -3
  763. package/dist/seed/manifest.js +23 -1
  764. package/dist/seed/notifications-seed-data.js +60 -0
  765. package/dist/seed/orders-seed-data.js +2 -2
  766. package/dist/seed/product-features-seed-data.d.ts +10 -0
  767. package/dist/seed/product-features-seed-data.js +162 -0
  768. package/dist/seed/products-auctions-seed-data.d.ts +6 -1
  769. package/dist/seed/products-auctions-seed-data.js +495 -24
  770. package/dist/seed/products-preorders-seed-data.d.ts +6 -1
  771. package/dist/seed/products-preorders-seed-data.js +27 -18
  772. package/dist/seed/products-standard-seed-data.d.ts +5 -0
  773. package/dist/seed/products-standard-seed-data.js +208 -297
  774. package/dist/seed/runner.js +95 -16
  775. package/dist/seed/server.d.ts +2 -0
  776. package/dist/seed/server.js +7 -0
  777. package/dist/seed/site-settings-seed-data.js +11 -1
  778. package/dist/seed/types.d.ts +58 -1
  779. package/dist/seed/types.js +14 -1
  780. package/dist/seed/wishlists-seed-data.d.ts +14 -7
  781. package/dist/seed/wishlists-seed-data.js +52 -109
  782. package/dist/seo/json-ld.d.ts +2 -1
  783. package/dist/server-entry.d.ts +60 -0
  784. package/dist/server-entry.js +93 -0
  785. package/dist/server.d.ts +26 -3
  786. package/dist/server.js +39 -7
  787. package/dist/stores/panel-store.d.ts +9 -0
  788. package/dist/stores/panel-store.js +8 -0
  789. package/dist/tailwind-utilities.css +1 -1
  790. package/dist/tokens/tokens.css +182 -12
  791. package/dist/ui/DataTable.style.css +192 -190
  792. package/dist/ui/components/Accordion.style.css +82 -82
  793. package/dist/ui/components/ActiveFilterChips.style.css +12 -12
  794. package/dist/ui/components/Alert.style.css +187 -187
  795. package/dist/ui/components/Avatar.style.css +71 -71
  796. package/dist/ui/components/AvatarDisplay.style.css +3 -3
  797. package/dist/ui/components/Badge.style.css +114 -114
  798. package/dist/ui/components/BaseListingCard.style.css +86 -86
  799. package/dist/ui/components/Breadcrumb.style.css +10 -10
  800. package/dist/ui/components/BulkActionBar.style.css +196 -196
  801. package/dist/ui/components/BulkActionsBar.d.ts +2 -0
  802. package/dist/ui/components/BulkActionsBar.js +5 -2
  803. package/dist/ui/components/Button.d.ts +3 -1
  804. package/dist/ui/components/Button.js +12 -2
  805. package/dist/ui/components/Button.style.css +160 -160
  806. package/dist/ui/components/Card.style.css +190 -190
  807. package/dist/ui/components/Checkbox.style.css +111 -111
  808. package/dist/ui/components/ConfirmDeleteModal.style.css +89 -89
  809. package/dist/ui/components/DashboardStatsCard.style.css +68 -68
  810. package/dist/ui/components/DescriptionField.style.css +36 -36
  811. package/dist/ui/components/DetailViewShell.js +1 -2
  812. package/dist/ui/components/Divider.style.css +39 -39
  813. package/dist/ui/components/Drawer.style.css +150 -150
  814. package/dist/ui/components/Dropdown.style.css +110 -110
  815. package/dist/ui/components/DynamicSelect.style.css +101 -101
  816. package/dist/ui/components/EmptyState.style.css +2 -2
  817. package/dist/ui/components/FilterDrawer.style.css +61 -61
  818. package/dist/ui/components/FlowDiagram.style.css +3 -3
  819. package/dist/ui/components/Form.style.css +27 -27
  820. package/dist/ui/components/FormActionBar.d.ts +22 -0
  821. package/dist/ui/components/FormActionBar.js +8 -0
  822. package/dist/ui/components/FormActionBar.style.css +77 -0
  823. package/dist/ui/components/FormField.style.css +30 -30
  824. package/dist/ui/components/HorizontalScroller.style.css +10 -10
  825. package/dist/ui/components/IconButton.style.css +103 -103
  826. package/dist/ui/components/ImageGallery.style.css +4 -4
  827. package/dist/ui/components/InlineCreateSelect.d.ts +13 -3
  828. package/dist/ui/components/InlineCreateSelect.js +9 -4
  829. package/dist/ui/components/Input.style.css +28 -28
  830. package/dist/ui/components/Layout.d.ts +2 -0
  831. package/dist/ui/components/Layout.js +2 -0
  832. package/dist/ui/components/Layout.style.css +22 -5
  833. package/dist/ui/components/ListingLayout.style.css +491 -491
  834. package/dist/ui/components/Modal.style.css +106 -106
  835. package/dist/ui/components/Pagination.style.css +76 -76
  836. package/dist/ui/components/PasswordStrengthIndicator.style.css +56 -56
  837. package/dist/ui/components/PriceDisplay.style.css +47 -47
  838. package/dist/ui/components/Progress.style.css +81 -81
  839. package/dist/ui/components/Radio.style.css +153 -153
  840. package/dist/ui/components/RatingDisplay.style.css +50 -50
  841. package/dist/ui/components/RowActionMenu.style.css +91 -91
  842. package/dist/ui/components/SectionTabs.style.css +18 -18
  843. package/dist/ui/components/Select.style.css +177 -177
  844. package/dist/ui/components/SideDrawer.style.css +206 -206
  845. package/dist/ui/components/SideModal.style.css +73 -73
  846. package/dist/ui/components/SiteLogo.d.ts +26 -0
  847. package/dist/ui/components/SiteLogo.js +18 -0
  848. package/dist/ui/components/Skeleton.style.css +55 -55
  849. package/dist/ui/components/SkipToMain.style.css +3 -3
  850. package/dist/ui/components/Slider.style.css +15 -15
  851. package/dist/ui/components/Spinner.style.css +84 -84
  852. package/dist/ui/components/StarRating.style.css +44 -44
  853. package/dist/ui/components/StatsGrid.style.css +96 -96
  854. package/dist/ui/components/StepperNav.style.css +110 -110
  855. package/dist/ui/components/SummaryCard.style.css +80 -82
  856. package/dist/ui/components/TabStrip.style.css +97 -97
  857. package/dist/ui/components/TablePagination.style.css +89 -89
  858. package/dist/ui/components/Tabs.style.css +44 -44
  859. package/dist/ui/components/TagInput.style.css +121 -121
  860. package/dist/ui/components/TextLink.style.css +94 -94
  861. package/dist/ui/components/Textarea.style.css +30 -30
  862. package/dist/ui/components/Toast.style.css +112 -112
  863. package/dist/ui/components/Toggle.style.css +105 -105
  864. package/dist/ui/components/Tooltip.style.css +114 -114
  865. package/dist/ui/components/Typography.style.css +178 -178
  866. package/dist/ui/components/UnsavedChangesModal.style.css +1 -1
  867. package/dist/ui/components/ViewToggle.style.css +8 -8
  868. package/dist/ui/components/index.style.css +1 -0
  869. package/dist/ui/index.d.ts +4 -0
  870. package/dist/ui/index.js +2 -0
  871. package/dist/ui/rich-text/RichText.style.css +40 -40
  872. package/dist/utils/index.d.ts +1 -0
  873. package/dist/utils/index.js +1 -0
  874. package/dist/utils/listing-params.d.ts +86 -0
  875. package/dist/utils/listing-params.js +121 -0
  876. package/dist/validation/schemas.d.ts +22 -22
  877. package/package.json +62 -10
  878. package/scripts/audit-violations.mjs +77 -0
  879. package/scripts/init-config.mjs +76 -0
  880. package/scripts/labels-extract.mjs +64 -0
  881. package/scripts/seed-cli-loader.mjs +37 -0
  882. package/scripts/seed-cli.mjs +660 -0
  883. package/scripts/sieve-audit.mjs +475 -0
  884. package/scripts/smoke-bundle.mjs +60 -0
  885. package/scripts/smoke-ssr.mjs +81 -0
  886. package/scripts/smoke-theme.mjs +105 -0
  887. package/scripts/verify-css-build.mjs +49 -0
  888. package/scripts/verify-entries.mjs +55 -0
  889. package/tsconfig.base.json +16 -0
@@ -39,7 +39,7 @@ function toDateInputValue(val) {
39
39
  }
40
40
  }
41
41
  // --- Component ---------------------------------------------------------------
42
- export function AdminBlogEditorView({ postId, onSaved, onDeleted, ...rest }) {
42
+ export function AdminBlogEditorView({ postId, onSaved, onDeleted, embedded, ...rest }) {
43
43
  const isEdit = Boolean(postId);
44
44
  const [title, setTitle] = React.useState("");
45
45
  const [slug, setSlug] = React.useState("");
@@ -146,17 +146,19 @@ export function AdminBlogEditorView({ postId, onSaved, onDeleted, ...rest }) {
146
146
  });
147
147
  const isSubmitting = saveMutation.isPending || postQuery.isLoading;
148
148
  const canSave = Boolean(title);
149
- return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Post" : "New Blog Post", sections: [
150
- _jsxs(Form, { onSubmit: (e) => {
151
- e.preventDefault();
152
- saveMutation.mutate();
153
- }, className: "space-y-5", children: [_jsx(Input, { label: "Title", value: title, onChange: (e) => handleTitleChange(e.target.value), required: true, placeholder: "e.g. How to Grade Pok\u00E9mon Cards" }), _jsx(Input, { label: "Slug", value: slug, onChange: (e) => {
154
- setSlug(e.target.value);
155
- setSlugManual(true);
156
- }, placeholder: "blog-how-to-grade-pokemon-cards", helperText: "Auto-generated from title. Must start with 'blog-'." }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Select, { label: "Category", options: CATEGORY_OPTIONS, value: category, onValueChange: (v) => setCategory(v) }), _jsx(Select, { label: "Status", options: STATUS_OPTIONS, value: status, onValueChange: (v) => setStatus(v) })] }), _jsx(Input, { label: "Excerpt", value: excerpt, onChange: (e) => setExcerpt(e.target.value), placeholder: "Short summary shown in listings and cards" }), _jsx(ImageUpload, { label: "Cover image", currentImage: coverImage, onUpload: (file) => upload(file, "blog", true, { type: "blog-cover", title: title || slug, category }), onChange: setCoverImage }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Content" }), _jsx(RichTextEditor, { value: content, onChange: setContent, placeholder: "Write your article here...", minHeightClassName: "min-h-[320px]" })] }), _jsx(TagInput, { label: "Tags", value: tags, onChange: setTags, placeholder: "e.g. pokemon, grading, tcg" }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Author name", value: authorName, onChange: (e) => setAuthorName(e.target.value), placeholder: "Author display name" }), _jsx(Input, { label: "Publish date (optional)", value: publishedAt, onChange: (e) => setPublishedAt(e.target.value), type: "date", helperText: "Auto-set to now when publishing." })] }), _jsx(Toggle, { label: "Featured post", checked: isFeatured, onChange: setIsFeatured }), _jsx(Input, { label: "Meta title (optional)", value: metaTitle, onChange: (e) => setMetaTitle(e.target.value), placeholder: "Defaults to post title" }), _jsx(Input, { label: "Meta description (optional)", value: metaDescription, onChange: (e) => setMetaDescription(e.target.value), placeholder: "SEO description \u2014 max 160 chars", maxLength: 160 }), _jsxs("div", { className: "flex gap-3 pt-2", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !canSave || isSubmitting, children: isEdit ? "Save changes" : "Create post" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => {
157
- if (confirm("Delete this post? This cannot be undone.")) {
158
- deleteMutation.mutate();
159
- }
160
- }, children: "Delete post" }))] })] }, "blog-form"),
161
- ] }));
149
+ const formSection = (_jsxs(Form, { onSubmit: (e) => {
150
+ e.preventDefault();
151
+ saveMutation.mutate();
152
+ }, className: "space-y-5", children: [_jsx(Input, { label: "Title", value: title, onChange: (e) => handleTitleChange(e.target.value), required: true, placeholder: "e.g. How to Grade Pok\u00E9mon Cards" }), _jsx(Input, { label: "Slug", value: slug, onChange: (e) => {
153
+ setSlug(e.target.value);
154
+ setSlugManual(true);
155
+ }, placeholder: "blog-how-to-grade-pokemon-cards", helperText: "Auto-generated from title. Must start with 'blog-'." }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Select, { label: "Category", options: CATEGORY_OPTIONS, value: category, onValueChange: (v) => setCategory(v) }), _jsx(Select, { label: "Status", options: STATUS_OPTIONS, value: status, onValueChange: (v) => setStatus(v) })] }), _jsx(Input, { label: "Excerpt", value: excerpt, onChange: (e) => setExcerpt(e.target.value), placeholder: "Short summary shown in listings and cards" }), _jsx(ImageUpload, { label: "Cover image", currentImage: coverImage, onUpload: (file) => upload(file, "blog", true, { type: "blog-cover", title: title || slug, category }), onChange: setCoverImage }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Content" }), _jsx(RichTextEditor, { value: content, onChange: setContent, placeholder: "Write your article here...", minHeightClassName: "min-h-[320px]" })] }), _jsx(TagInput, { label: "Tags", value: tags, onChange: setTags, placeholder: "e.g. pokemon, grading, tcg" }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Author name", value: authorName, onChange: (e) => setAuthorName(e.target.value), placeholder: "Author display name" }), _jsx(Input, { label: "Publish date (optional)", value: publishedAt, onChange: (e) => setPublishedAt(e.target.value), type: "date", helperText: "Auto-set to now when publishing." })] }), _jsx(Toggle, { label: "Featured post", checked: isFeatured, onChange: setIsFeatured }), _jsx(Input, { label: "Meta title (optional)", value: metaTitle, onChange: (e) => setMetaTitle(e.target.value), placeholder: "Defaults to post title" }), _jsx(Input, { label: "Meta description (optional)", value: metaDescription, onChange: (e) => setMetaDescription(e.target.value), placeholder: "SEO description \u2014 max 160 chars", maxLength: 160 }), _jsxs("div", { className: "flex gap-3 pt-2", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !canSave || isSubmitting, children: isEdit ? "Save changes" : "Create post" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => {
156
+ if (confirm("Delete this post? This cannot be undone.")) {
157
+ deleteMutation.mutate();
158
+ }
159
+ }, children: "Delete post" }))] })] }, "blog-form"));
160
+ if (embedded) {
161
+ return _jsx("div", { className: "overflow-y-auto p-4", children: formSection });
162
+ }
163
+ return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Post" : "New Blog Post", sections: [formSection] }));
162
164
  }
@@ -1,12 +1,14 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import React, { useState, useCallback } from "react";
4
- import { X } from "lucide-react";
4
+ import { Plus, X } from "lucide-react";
5
5
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
- import { ListingToolbar, Pagination, ListingViewShell } from "../../../ui";
6
+ import { usePanelUrlSync } from "../../../react/hooks/use-panel-url-sync";
7
+ import { Button, ListingToolbar, Pagination, ListingViewShell, SideDrawer } from "../../../ui";
7
8
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
8
9
  import { toRecordArray, toRelativeDate, toStringValue, useAdminListingData, } from "../hooks/useAdminListingData";
9
10
  import { DataTable } from "./DataTable";
11
+ import { AdminBlogEditorView } from "./AdminBlogEditorView";
10
12
  const PAGE_SIZE = 25;
11
13
  const FILTER_KEYS = ["status", "isFeatured"];
12
14
  const DEFAULT_SORT = "-publishedAt";
@@ -20,6 +22,7 @@ const STATUS_OPTIONS = ["All", "published", "draft", "archived"];
20
22
  export function AdminBlogView({ children, getRowHref, ...props }) {
21
23
  const hasChildren = React.Children.count(children) > 0;
22
24
  const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
25
+ const { openCreatePanel, openEditPanel, closePanel, isCreateOpen, isEditOpen, editId } = usePanelUrlSync();
23
26
  const [searchInput, setSearchInput] = useState(table.get("q") || "");
24
27
  const [filterOpen, setFilterOpen] = useState(false);
25
28
  const [pendingFilters, setPendingFilters] = useState(() => Object.fromEntries(FILTER_KEYS.map((k) => [k, table.get(k)])));
@@ -87,5 +90,5 @@ export function AdminBlogView({ children, getRowHref, ...props }) {
87
90
  if (hasChildren) {
88
91
  return _jsx(ListingViewShell, { portal: "admin", ...props, children: children });
89
92
  }
90
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search articles, authors, or tags", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); table.setPage(1); }, hideViewToggle: true, onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-200", children: errorMessage })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No blog posts found", getRowHref: getRowHref })] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsxs("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Status" }), _jsx("div", { className: "flex flex-wrap gap-2", children: STATUS_OPTIONS.map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, status: opt === "All" ? "" : opt })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.status || "All") === opt ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt }, opt))) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Featured" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Featured only", value: "true" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isFeatured: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isFeatured || "") === opt.value ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] })] }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }))] }));
93
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search articles, authors, or tags", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); table.setPage(1); }, hideViewToggle: true, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: openCreatePanel, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), "New Post"] }) }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-200", children: errorMessage })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No blog posts found", onRowClick: (row) => openEditPanel(row.id) })] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsxs("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Status" }), _jsx("div", { className: "flex flex-wrap gap-2", children: STATUS_OPTIONS.map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, status: opt === "All" ? "" : opt })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.status || "All") === opt ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt }, opt))) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Featured" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Featured only", value: "true" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isFeatured: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isFeatured || "") === opt.value ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] })] }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] })), _jsx(SideDrawer, { isOpen: isCreateOpen || isEditOpen, onClose: closePanel, title: isCreateOpen ? "New Post" : "Edit Post", mode: isCreateOpen ? "create" : "edit", children: (isCreateOpen || isEditOpen) && (_jsx(AdminBlogEditorView, { postId: editId ?? undefined, onSaved: closePanel, onDeleted: closePanel, embedded: true })) })] }));
91
94
  }
@@ -3,5 +3,7 @@ export interface AdminBrandEditorViewProps extends Omit<StackedViewShellProps, "
3
3
  brandId?: string;
4
4
  onSaved?: (id: string) => void;
5
5
  onDeleted?: () => void;
6
+ /** When true, renders form only (no StackedViewShell) for use inside a SideDrawer. */
7
+ embedded?: boolean;
6
8
  }
7
- export declare function AdminBrandEditorView({ brandId, onSaved, onDeleted, ...rest }: AdminBrandEditorViewProps): import("react/jsx-runtime").JSX.Element;
9
+ export declare function AdminBrandEditorView({ brandId, onSaved, onDeleted, embedded, ...rest }: AdminBrandEditorViewProps): import("react/jsx-runtime").JSX.Element;
@@ -11,7 +11,7 @@ function toBrandSlug(str) {
11
11
  const base = str.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
12
12
  return base.startsWith("brand-") ? base : `brand-${base}`;
13
13
  }
14
- export function AdminBrandEditorView({ brandId, onSaved, onDeleted, ...rest }) {
14
+ export function AdminBrandEditorView({ brandId, onSaved, onDeleted, embedded, ...rest }) {
15
15
  const isEdit = Boolean(brandId);
16
16
  const [name, setName] = React.useState("");
17
17
  const [slug, setSlug] = React.useState("");
@@ -88,17 +88,19 @@ export function AdminBrandEditorView({ brandId, onSaved, onDeleted, ...rest }) {
88
88
  });
89
89
  const { upload } = useMediaUpload();
90
90
  const isSubmitting = saveMutation.isPending || brandQuery.isLoading;
91
- return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Brand" : "Create Brand", sections: [
92
- _jsxs(Form, { onSubmit: (e) => {
93
- e.preventDefault();
94
- saveMutation.mutate();
95
- }, className: "space-y-4", children: [_jsxs("div", { className: "grid sm:grid-cols-2 gap-4", children: [_jsx(Input, { label: "Brand name", value: name, onChange: (e) => handleNameChange(e.target.value), required: true, placeholder: "e.g. Hot Wheels" }), _jsx(Input, { label: "Slug", value: slug, onChange: (e) => {
96
- setSlug(e.target.value);
97
- setSlugManual(true);
98
- }, placeholder: "brand-hot-wheels", helperText: "Auto-generated from name. Must start with 'brand-'." })] }), _jsx(Input, { label: "Description", value: description, onChange: (e) => setDescription(e.target.value), placeholder: "Brief description of the brand" }), _jsxs("div", { className: "grid sm:grid-cols-2 gap-4", children: [_jsx(ImageUpload, { label: "Logo", currentImage: logoURL, onUpload: (file) => upload(file, "brands", true, { type: "brand-logo", brand: name || slug }), onChange: setLogoURL }), _jsx(ImageUpload, { label: "Banner", currentImage: bannerURL, onUpload: (file) => upload(file, "brands", true, { type: "brand-banner", brand: name || slug }), onChange: setBannerURL })] }), _jsxs("div", { className: "grid sm:grid-cols-2 gap-4", children: [_jsx(Input, { label: "Website", value: website, onChange: (e) => setWebsite(e.target.value), placeholder: "https://brand.com", type: "url" }), _jsx(Input, { label: "Display order", value: displayOrder, onChange: (e) => setDisplayOrder(e.target.value), type: "number", min: 0, placeholder: "0" })] }), _jsx(Toggle, { label: "Active", checked: isActive, onChange: setIsActive }), _jsxs("div", { className: "flex gap-3 pt-2", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !name || isSubmitting, children: isEdit ? "Save changes" : "Create brand" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => {
99
- if (confirm("Delete this brand? This cannot be undone.")) {
100
- deleteMutation.mutate();
101
- }
102
- }, children: "Delete brand" }))] })] }, "brand-form"),
103
- ] }));
91
+ const formSection = (_jsxs(Form, { onSubmit: (e) => {
92
+ e.preventDefault();
93
+ saveMutation.mutate();
94
+ }, className: "space-y-4", children: [_jsxs("div", { className: "grid sm:grid-cols-2 gap-4", children: [_jsx(Input, { label: "Brand name", value: name, onChange: (e) => handleNameChange(e.target.value), required: true, placeholder: "e.g. Hot Wheels" }), _jsx(Input, { label: "Slug", value: slug, onChange: (e) => {
95
+ setSlug(e.target.value);
96
+ setSlugManual(true);
97
+ }, placeholder: "brand-hot-wheels", helperText: "Auto-generated from name. Must start with 'brand-'." })] }), _jsx(Input, { label: "Description", value: description, onChange: (e) => setDescription(e.target.value), placeholder: "Brief description of the brand" }), _jsxs("div", { className: "grid sm:grid-cols-2 gap-4", children: [_jsx(ImageUpload, { label: "Logo", currentImage: logoURL, onUpload: (file) => upload(file, "brands", true, { type: "brand-logo", brand: name || slug }), onChange: setLogoURL }), _jsx(ImageUpload, { label: "Banner", currentImage: bannerURL, onUpload: (file) => upload(file, "brands", true, { type: "brand-banner", brand: name || slug }), onChange: setBannerURL })] }), _jsxs("div", { className: "grid sm:grid-cols-2 gap-4", children: [_jsx(Input, { label: "Website", value: website, onChange: (e) => setWebsite(e.target.value), placeholder: "https://brand.com", type: "url" }), _jsx(Input, { label: "Display order", value: displayOrder, onChange: (e) => setDisplayOrder(e.target.value), type: "number", min: 0, placeholder: "0" })] }), _jsx(Toggle, { label: "Active", checked: isActive, onChange: setIsActive }), _jsxs("div", { className: "flex gap-3 pt-2", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !name || isSubmitting, children: isEdit ? "Save changes" : "Create brand" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => {
98
+ if (confirm("Delete this brand? This cannot be undone.")) {
99
+ deleteMutation.mutate();
100
+ }
101
+ }, children: "Delete brand" }))] })] }, "brand-form"));
102
+ if (embedded) {
103
+ return _jsx("div", { className: "overflow-y-auto p-4", children: formSection });
104
+ }
105
+ return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Brand" : "Create Brand", sections: [formSection] }));
104
106
  }
@@ -1,12 +1,14 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import React, { useState, useCallback } from "react";
4
- import { X } from "lucide-react";
4
+ import { Plus, X } from "lucide-react";
5
5
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
- import { ListingToolbar, Pagination, ListingViewShell } from "../../../ui";
6
+ import { usePanelUrlSync } from "../../../react/hooks/use-panel-url-sync";
7
+ import { Button, ListingToolbar, Pagination, ListingViewShell, SideDrawer } from "../../../ui";
7
8
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
8
9
  import { toRecordArray, toRelativeDate, toStringValue, useAdminListingData, } from "../hooks/useAdminListingData";
9
10
  import { DataTable } from "./DataTable";
11
+ import { AdminBrandEditorView } from "./AdminBrandEditorView";
10
12
  const PAGE_SIZE = 25;
11
13
  const FILTER_KEYS = ["isActive"];
12
14
  const DEFAULT_SORT = "displayOrder";
@@ -19,6 +21,7 @@ const SORT_OPTIONS = [
19
21
  export function AdminBrandsView({ children, ...props }) {
20
22
  const hasChildren = React.Children.count(children) > 0;
21
23
  const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
24
+ const { openCreatePanel, openEditPanel, closePanel, isCreateOpen, isEditOpen, editId } = usePanelUrlSync();
22
25
  const [searchInput, setSearchInput] = useState(table.get("q") || "");
23
26
  const [filterOpen, setFilterOpen] = useState(false);
24
27
  const [pendingFilters, setPendingFilters] = useState(() => Object.fromEntries(FILTER_KEYS.map((k) => [k, table.get(k)])));
@@ -72,5 +75,5 @@ export function AdminBrandsView({ children, ...props }) {
72
75
  if (hasChildren) {
73
76
  return _jsx(ListingViewShell, { portal: "admin", ...props, children: children });
74
77
  }
75
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search brands by name or slug", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); table.setPage(1); }, hideViewToggle: true, onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-200", children: errorMessage })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No brands found" })] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Status" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Active", value: "true" }, { label: "Inactive", value: "false" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isActive: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isActive || "") === opt.value ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }))] }));
78
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search brands by name or slug", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); table.setPage(1); }, hideViewToggle: true, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: openCreatePanel, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), "Add Brand"] }) }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-200", children: errorMessage })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No brands found", onRowClick: (row) => openEditPanel(row.id) })] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Status" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Active", value: "true" }, { label: "Inactive", value: "false" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isActive: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isActive || "") === opt.value ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] })), _jsx(SideDrawer, { isOpen: isCreateOpen || isEditOpen, onClose: closePanel, title: isCreateOpen ? "Add Brand" : "Edit Brand", mode: isCreateOpen ? "create" : "edit", children: (isCreateOpen || isEditOpen) && (_jsx(AdminBrandEditorView, { brandId: editId ?? undefined, onSaved: closePanel, onDeleted: closePanel, embedded: true })) })] }));
76
79
  }
@@ -1,12 +1,14 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import React, { useState, useCallback } from "react";
4
- import { X } from "lucide-react";
4
+ import { Plus, X } from "lucide-react";
5
5
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
- import { ListingToolbar, Pagination, ListingViewShell } from "../../../ui";
6
+ import { usePanelUrlSync } from "../../../react/hooks/use-panel-url-sync";
7
+ import { Button, ListingToolbar, Pagination, ListingViewShell, SideDrawer } from "../../../ui";
7
8
  import { CATEGORY_ENDPOINTS } from "../../../constants/api-endpoints";
8
9
  import { toRecordArray, toRelativeDate, toStringValue, useAdminListingData, } from "../hooks/useAdminListingData";
9
10
  import { DataTable } from "./DataTable";
11
+ import { AdminCategoryEditorView } from "./AdminCategoryEditorView";
10
12
  const PAGE_SIZE = 50;
11
13
  const FILTER_KEYS = ["isActive", "isFeatured"];
12
14
  const DEFAULT_SORT = "name";
@@ -18,6 +20,7 @@ const SORT_OPTIONS = [
18
20
  export function AdminCategoriesView({ children, getRowHref, ...props }) {
19
21
  const hasChildren = React.Children.count(children) > 0;
20
22
  const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
23
+ const { openCreatePanel, openEditPanel, closePanel, isCreateOpen, isEditOpen, editId } = usePanelUrlSync();
21
24
  const [searchInput, setSearchInput] = useState(table.get("q") || "");
22
25
  const [filterOpen, setFilterOpen] = useState(false);
23
26
  const [pendingFilters, setPendingFilters] = useState(() => Object.fromEntries(FILTER_KEYS.map((k) => [k, table.get(k)])));
@@ -80,5 +83,5 @@ export function AdminCategoriesView({ children, getRowHref, ...props }) {
80
83
  if (hasChildren) {
81
84
  return _jsx(ListingViewShell, { portal: "admin", ...props, children: children });
82
85
  }
83
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search categories, slugs, or parent category", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); table.setPage(1); }, hideViewToggle: true, onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-200", children: errorMessage })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No categories found", getRowHref: getRowHref })] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsxs("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Active" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Active", value: "true" }, { label: "Inactive", value: "false" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isActive: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isActive || "") === opt.value ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Featured" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Featured only", value: "true" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isFeatured: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isFeatured || "") === opt.value ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] })] }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }))] }));
86
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search categories, slugs, or parent category", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); table.setPage(1); }, hideViewToggle: true, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: openCreatePanel, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), "Add Category"] }) }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-200", children: errorMessage })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No categories found", onRowClick: (row) => openEditPanel(row.id) })] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsxs("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Active" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Active", value: "true" }, { label: "Inactive", value: "false" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isActive: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isActive || "") === opt.value ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Featured" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Featured only", value: "true" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isFeatured: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isFeatured || "") === opt.value ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] })] }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] })), _jsx(SideDrawer, { isOpen: isCreateOpen || isEditOpen, onClose: closePanel, title: isCreateOpen ? "Add Category" : "Edit Category", mode: isCreateOpen ? "create" : "edit", children: (isCreateOpen || isEditOpen) && (_jsx(AdminCategoryEditorView, { categoryId: editId ?? undefined, onSaved: closePanel, onDeleted: closePanel, embedded: true })) })] }));
84
87
  }
@@ -3,5 +3,6 @@ export interface AdminCategoryEditorViewProps extends Omit<StackedViewShellProps
3
3
  categoryId?: string;
4
4
  onSaved?: (id: string) => void;
5
5
  onDeleted?: () => void;
6
+ embedded?: boolean;
6
7
  }
7
- export declare function AdminCategoryEditorView({ categoryId, onSaved, onDeleted, ...rest }: AdminCategoryEditorViewProps): import("react/jsx-runtime").JSX.Element;
8
+ export declare function AdminCategoryEditorView({ categoryId, onSaved, onDeleted, embedded, ...rest }: AdminCategoryEditorViewProps): import("react/jsx-runtime").JSX.Element;
@@ -26,7 +26,7 @@ function toCategorySlug(str) {
26
26
  .replace(/[^a-z0-9]+/g, "-")
27
27
  .replace(/^-+|-+$/g, "");
28
28
  }
29
- export function AdminCategoryEditorView({ categoryId, onSaved, onDeleted, ...rest }) {
29
+ export function AdminCategoryEditorView({ categoryId, onSaved, onDeleted, embedded, ...rest }) {
30
30
  const isEdit = Boolean(categoryId);
31
31
  const [name, setName] = React.useState("");
32
32
  const [slug, setSlug] = React.useState("");
@@ -99,17 +99,19 @@ export function AdminCategoryEditorView({ categoryId, onSaved, onDeleted, ...res
99
99
  onError: (err) => showToast(err?.message ?? "Failed to delete category.", "error"),
100
100
  });
101
101
  const isSubmitting = saveMutation.isPending || categoryQuery.isLoading;
102
- return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Category" : "Create Category", sections: [
103
- _jsxs(Form, { onSubmit: (e) => {
104
- e.preventDefault();
105
- saveMutation.mutate();
106
- }, className: "space-y-4", children: [_jsxs("div", { className: "grid sm:grid-cols-2 gap-4", children: [_jsx(Input, { label: "Category name", value: name, onChange: (e) => handleNameChange(e.target.value), required: true, placeholder: "e.g. Toys & Games" }), _jsx(Input, { label: "Slug", value: slug, onChange: (e) => {
107
- setSlug(e.target.value);
108
- setSlugManual(true);
109
- }, placeholder: "toys-and-games", helperText: "Auto-generated from name. Used in URLs." })] }), _jsx(Input, { label: "Description", value: description, onChange: (e) => setDescription(e.target.value), placeholder: "Brief description of the category" }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("label", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Parent category" }), _jsx(InlineCreateSelect, { value: parentId || null, onChange: (v) => setParentId(v ?? ""), loadOptions: loadCategoryOptions, placeholder: "Search categories\u2026 (leave empty for root)", searchPlaceholder: "Type category name\u2026", noResultsText: "No categories found", ariaLabel: "Parent category", createLabel: "Category", renderCreateForm: ({ onCreated, onCancel }) => (_jsx(CategoryQuickCreateForm, { onSaved: (id, name) => { setParentId(id); onCreated({ value: id, label: name }); }, onCancel: onCancel })) }), _jsx("p", { className: "text-xs text-neutral-500 dark:text-neutral-400", children: "Leave empty to create a root category." })] }), _jsx(Input, { label: "Display order", value: order, onChange: (e) => setOrder(e.target.value), type: "number", min: 0, placeholder: "0" }), _jsx(Toggle, { label: "Active", checked: isActive, onChange: setIsActive }), _jsx(Toggle, { label: "Show in menu", checked: showInMenu, onChange: setShowInMenu }), _jsxs("div", { className: "flex gap-3 pt-2", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !name || isSubmitting, children: isEdit ? "Save changes" : "Create category" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => {
110
- if (confirm("Delete this category? Products in this category will become uncategorized.")) {
111
- deleteMutation.mutate();
112
- }
113
- }, children: "Delete category" }))] })] }, "cat-form"),
114
- ] }));
102
+ const formSection = (_jsxs(Form, { onSubmit: (e) => {
103
+ e.preventDefault();
104
+ saveMutation.mutate();
105
+ }, className: "space-y-4", children: [_jsxs("div", { className: "grid sm:grid-cols-2 gap-4", children: [_jsx(Input, { label: "Category name", value: name, onChange: (e) => handleNameChange(e.target.value), required: true, placeholder: "e.g. Toys & Games" }), _jsx(Input, { label: "Slug", value: slug, onChange: (e) => {
106
+ setSlug(e.target.value);
107
+ setSlugManual(true);
108
+ }, placeholder: "toys-and-games", helperText: "Auto-generated from name. Used in URLs." })] }), _jsx(Input, { label: "Description", value: description, onChange: (e) => setDescription(e.target.value), placeholder: "Brief description of the category" }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("label", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Parent category" }), _jsx(InlineCreateSelect, { value: parentId || null, onChange: (v) => setParentId(v ?? ""), loadOptions: loadCategoryOptions, placeholder: "Search categories\u2026 (leave empty for root)", searchPlaceholder: "Type category name\u2026", noResultsText: "No categories found", ariaLabel: "Parent category", createLabel: "Category", renderCreateForm: ({ onCreated, onCancel }) => (_jsx(CategoryQuickCreateForm, { onSaved: (id, name) => { setParentId(id); onCreated({ value: id, label: name }); }, onCancel: onCancel })) }), _jsx("p", { className: "text-xs text-neutral-500 dark:text-neutral-400", children: "Leave empty to create a root category." })] }), _jsx(Input, { label: "Display order", value: order, onChange: (e) => setOrder(e.target.value), type: "number", min: 0, placeholder: "0" }), _jsx(Toggle, { label: "Active", checked: isActive, onChange: setIsActive }), _jsx(Toggle, { label: "Show in menu", checked: showInMenu, onChange: setShowInMenu }), _jsxs("div", { className: "flex gap-3 pt-2", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !name || isSubmitting, children: isEdit ? "Save changes" : "Create category" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => {
109
+ if (confirm("Delete this category? Products in this category will become uncategorized.")) {
110
+ deleteMutation.mutate();
111
+ }
112
+ }, children: "Delete category" }))] })] }, "cat-form"));
113
+ if (embedded) {
114
+ return _jsx("div", { className: "overflow-y-auto p-4", children: formSection });
115
+ }
116
+ return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Category" : "Create Category", sections: [formSection] }));
115
117
  }
@@ -3,5 +3,6 @@ export interface AdminCouponEditorViewProps extends Omit<StackedViewShellProps,
3
3
  couponId?: string;
4
4
  onSaved?: (id: string) => void;
5
5
  onDeleted?: () => void;
6
+ embedded?: boolean;
6
7
  }
7
- export declare function AdminCouponEditorView({ couponId, onSaved, onDeleted, ...rest }: AdminCouponEditorViewProps): import("react/jsx-runtime").JSX.Element;
8
+ export declare function AdminCouponEditorView({ couponId, onSaved, onDeleted, embedded, ...rest }: AdminCouponEditorViewProps): import("react/jsx-runtime").JSX.Element;
@@ -26,7 +26,7 @@ function toDateInputValue(val) {
26
26
  }
27
27
  }
28
28
  // --- Component ---------------------------------------------------------------
29
- export function AdminCouponEditorView({ couponId, onSaved, onDeleted, ...rest }) {
29
+ export function AdminCouponEditorView({ couponId, onSaved, onDeleted, embedded, ...rest }) {
30
30
  const isEdit = Boolean(couponId);
31
31
  // --- form state ---
32
32
  const [code, setCode] = React.useState("");
@@ -163,17 +163,19 @@ export function AdminCouponEditorView({ couponId, onSaved, onDeleted, ...rest })
163
163
  : type === "fixed"
164
164
  ? "Discount amount (paise)"
165
165
  : "Discount value";
166
- return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Coupon" : "Create Coupon", sections: [
167
- _jsxs(Form, { onSubmit: (e) => {
168
- e.preventDefault();
169
- saveMutation.mutate();
170
- }, className: "space-y-5", children: [_jsx(Select, { label: "Coupon type", options: TYPE_OPTIONS, value: type, onValueChange: (v) => setType(v), required: true }), _jsx(Input, { label: "Campaign name", value: name, onChange: (e) => handleNameChange(e.target.value), required: true, placeholder: "e.g. Summer Sale 20%" }), !isEdit && (_jsx(Input, { label: "Coupon code", value: code, onChange: (e) => {
171
- setCode(toCouponCode(e.target.value));
172
- setCodeManual(true);
173
- }, required: true, placeholder: "e.g. SUMMER20", helperText: "Auto-generated from name. Uppercase alphanumeric + hyphens only." })), isEdit && (_jsx(Input, { label: "Coupon code", value: code, disabled: true, helperText: "Code cannot be changed after creation." })), _jsx(Input, { label: "Description (optional)", value: description, onChange: (e) => setDescription(e.target.value), placeholder: "Internal notes about this coupon" }), type !== "free_shipping" && type !== "buy_x_get_y" && (_jsx(Input, { label: discountLabel, value: discountValue, onChange: (e) => setDiscountValue(e.target.value), type: "number", min: 0, required: true, placeholder: type === "percentage" ? "e.g. 20" : "e.g. 5000" })), type === "percentage" && (_jsx(Input, { label: "Max discount cap (paise, optional)", value: maxDiscount, onChange: (e) => setMaxDiscount(e.target.value), type: "number", min: 0, placeholder: "e.g. 20000", helperText: "Leave blank for no cap." })), (type === "percentage" || type === "fixed") && (_jsx(Input, { label: "Min order value (paise, optional)", value: minPurchase, onChange: (e) => setMinPurchase(e.target.value), type: "number", min: 0, placeholder: "e.g. 50000", helperText: "Leave blank for no minimum." })), type === "buy_x_get_y" && (_jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Buy quantity", value: buyQty, onChange: (e) => setBuyQty(e.target.value), type: "number", min: 1, required: true }), _jsx(Input, { label: "Get quantity", value: getQty, onChange: (e) => setGetQty(e.target.value), type: "number", min: 1, required: true })] })), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Total usage limit (optional)", value: totalLimit, onChange: (e) => setTotalLimit(e.target.value), type: "number", min: 0, placeholder: "Unlimited" }), _jsx(Input, { label: "Per-user limit (optional)", value: perUserLimit, onChange: (e) => setPerUserLimit(e.target.value), type: "number", min: 0, placeholder: "Unlimited" })] }), isEdit && (_jsx(Input, { label: "Current usage", value: String(currentUsage), disabled: true, helperText: "Read-only \u2014 updated by orders." })), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Start date", value: startDate, onChange: (e) => setStartDate(e.target.value), type: "date", required: true }), _jsx(Input, { label: "End date (optional)", value: endDate, onChange: (e) => setEndDate(e.target.value), type: "date", helperText: "Leave blank for no expiry." })] }), _jsx(Toggle, { label: "Active", checked: isActive, onChange: setIsActive }), _jsx(Toggle, { label: "First-time users only", checked: firstTimeOnly, onChange: setFirstTimeOnly }), _jsx(Toggle, { label: "Allow stacking with seller coupons", checked: combinable, onChange: setCombinable }), _jsx(Toggle, { label: "Applies to auctions", checked: appliesToAuctions, onChange: setAppliesToAuctions }), _jsxs("div", { className: "flex gap-3 pt-2", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !canSave || isSubmitting, children: isEdit ? "Save changes" : "Create coupon" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => {
174
- if (confirm("Delete this coupon? This cannot be undone.")) {
175
- deleteMutation.mutate();
176
- }
177
- }, children: "Delete coupon" }))] })] }, "coupon-form"),
178
- ] }));
166
+ const formSection = (_jsxs(Form, { onSubmit: (e) => {
167
+ e.preventDefault();
168
+ saveMutation.mutate();
169
+ }, className: "space-y-5", children: [_jsx(Select, { label: "Coupon type", options: TYPE_OPTIONS, value: type, onValueChange: (v) => setType(v), required: true }), _jsx(Input, { label: "Campaign name", value: name, onChange: (e) => handleNameChange(e.target.value), required: true, placeholder: "e.g. Summer Sale 20%" }), !isEdit && (_jsx(Input, { label: "Coupon code", value: code, onChange: (e) => {
170
+ setCode(toCouponCode(e.target.value));
171
+ setCodeManual(true);
172
+ }, required: true, placeholder: "e.g. SUMMER20", helperText: "Auto-generated from name. Uppercase alphanumeric + hyphens only." })), isEdit && (_jsx(Input, { label: "Coupon code", value: code, disabled: true, helperText: "Code cannot be changed after creation." })), _jsx(Input, { label: "Description (optional)", value: description, onChange: (e) => setDescription(e.target.value), placeholder: "Internal notes about this coupon" }), type !== "free_shipping" && type !== "buy_x_get_y" && (_jsx(Input, { label: discountLabel, value: discountValue, onChange: (e) => setDiscountValue(e.target.value), type: "number", min: 0, required: true, placeholder: type === "percentage" ? "e.g. 20" : "e.g. 5000" })), type === "percentage" && (_jsx(Input, { label: "Max discount cap (paise, optional)", value: maxDiscount, onChange: (e) => setMaxDiscount(e.target.value), type: "number", min: 0, placeholder: "e.g. 20000", helperText: "Leave blank for no cap." })), (type === "percentage" || type === "fixed") && (_jsx(Input, { label: "Min order value (paise, optional)", value: minPurchase, onChange: (e) => setMinPurchase(e.target.value), type: "number", min: 0, placeholder: "e.g. 50000", helperText: "Leave blank for no minimum." })), type === "buy_x_get_y" && (_jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Buy quantity", value: buyQty, onChange: (e) => setBuyQty(e.target.value), type: "number", min: 1, required: true }), _jsx(Input, { label: "Get quantity", value: getQty, onChange: (e) => setGetQty(e.target.value), type: "number", min: 1, required: true })] })), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Total usage limit (optional)", value: totalLimit, onChange: (e) => setTotalLimit(e.target.value), type: "number", min: 0, placeholder: "Unlimited" }), _jsx(Input, { label: "Per-user limit (optional)", value: perUserLimit, onChange: (e) => setPerUserLimit(e.target.value), type: "number", min: 0, placeholder: "Unlimited" })] }), isEdit && (_jsx(Input, { label: "Current usage", value: String(currentUsage), disabled: true, helperText: "Read-only \u2014 updated by orders." })), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Start date", value: startDate, onChange: (e) => setStartDate(e.target.value), type: "date", required: true }), _jsx(Input, { label: "End date (optional)", value: endDate, onChange: (e) => setEndDate(e.target.value), type: "date", helperText: "Leave blank for no expiry." })] }), _jsx(Toggle, { label: "Active", checked: isActive, onChange: setIsActive }), _jsx(Toggle, { label: "First-time users only", checked: firstTimeOnly, onChange: setFirstTimeOnly }), _jsx(Toggle, { label: "Allow stacking with seller coupons", checked: combinable, onChange: setCombinable }), _jsx(Toggle, { label: "Applies to auctions", checked: appliesToAuctions, onChange: setAppliesToAuctions }), _jsxs("div", { className: "flex gap-3 pt-2", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !canSave || isSubmitting, children: isEdit ? "Save changes" : "Create coupon" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => {
173
+ if (confirm("Delete this coupon? This cannot be undone.")) {
174
+ deleteMutation.mutate();
175
+ }
176
+ }, children: "Delete coupon" }))] })] }, "coupon-form"));
177
+ if (embedded) {
178
+ return _jsx("div", { className: "overflow-y-auto p-4", children: formSection });
179
+ }
180
+ return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Coupon" : "Create Coupon", sections: [formSection] }));
179
181
  }
@@ -1,12 +1,14 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import React, { useState, useCallback } from "react";
4
- import { X } from "lucide-react";
4
+ import { Plus, X } from "lucide-react";
5
5
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
- import { ListingToolbar, Pagination, ListingViewShell } from "../../../ui";
6
+ import { usePanelUrlSync } from "../../../react/hooks/use-panel-url-sync";
7
+ import { Button, ListingToolbar, Pagination, ListingViewShell, SideDrawer } from "../../../ui";
7
8
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
8
9
  import { toRecordArray, toRelativeDate, toStringValue, useAdminListingData, } from "../hooks/useAdminListingData";
9
10
  import { DataTable } from "./DataTable";
11
+ import { AdminCouponEditorView } from "./AdminCouponEditorView";
10
12
  const PAGE_SIZE = 25;
11
13
  const FILTER_KEYS = ["type"];
12
14
  const DEFAULT_SORT = "-createdAt";
@@ -19,6 +21,7 @@ const TYPE_OPTIONS = ["All", "percentage", "fixed", "free_shipping", "buy_x_get_
19
21
  export function AdminCouponsView({ children, getRowHref, ...props }) {
20
22
  const hasChildren = React.Children.count(children) > 0;
21
23
  const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
24
+ const { openCreatePanel, openEditPanel, closePanel, isCreateOpen, isEditOpen, editId } = usePanelUrlSync();
22
25
  const [searchInput, setSearchInput] = useState(table.get("q") || "");
23
26
  const [filterOpen, setFilterOpen] = useState(false);
24
27
  const [pendingFilters, setPendingFilters] = useState(() => Object.fromEntries(FILTER_KEYS.map((k) => [k, table.get(k)])));
@@ -75,5 +78,5 @@ export function AdminCouponsView({ children, getRowHref, ...props }) {
75
78
  if (hasChildren) {
76
79
  return _jsx(ListingViewShell, { portal: "admin", ...props, children: children });
77
80
  }
78
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search codes, campaigns, or seller scopes", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); table.setPage(1); }, hideViewToggle: true, onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-200", children: errorMessage })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No coupons found", getRowHref: getRowHref })] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Type" }), _jsx("div", { className: "flex flex-wrap gap-2", children: TYPE_OPTIONS.map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, type: opt === "All" ? "" : opt })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.type || "All") === opt ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt }, opt))) })] }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }))] }));
81
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search codes, campaigns, or seller scopes", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); table.setPage(1); }, hideViewToggle: true, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: openCreatePanel, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), "Add Coupon"] }) }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-200", children: errorMessage })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No coupons found", onRowClick: (row) => openEditPanel(row.id) })] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Type" }), _jsx("div", { className: "flex flex-wrap gap-2", children: TYPE_OPTIONS.map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, type: opt === "All" ? "" : opt })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.type || "All") === opt ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt }, opt))) })] }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] })), _jsx(SideDrawer, { isOpen: isCreateOpen || isEditOpen, onClose: closePanel, title: isCreateOpen ? "Add Coupon" : "Edit Coupon", mode: isCreateOpen ? "create" : "edit", children: (isCreateOpen || isEditOpen) && (_jsx(AdminCouponEditorView, { couponId: editId ?? undefined, onSaved: closePanel, onDeleted: closePanel, embedded: true })) })] }));
79
82
  }
@@ -3,5 +3,6 @@ export interface AdminFaqEditorViewProps extends Omit<StackedViewShellProps, "se
3
3
  faqId?: string;
4
4
  onSaved?: (id: string) => void;
5
5
  onDeleted?: () => void;
6
+ embedded?: boolean;
6
7
  }
7
- export declare function AdminFaqEditorView({ faqId, onSaved, onDeleted, ...rest }: AdminFaqEditorViewProps): import("react/jsx-runtime").JSX.Element;
8
+ export declare function AdminFaqEditorView({ faqId, onSaved, onDeleted, embedded, ...rest }: AdminFaqEditorViewProps): import("react/jsx-runtime").JSX.Element;
@@ -23,7 +23,7 @@ function toSlug(str) {
23
23
  return base.startsWith("faq-") ? base : `faq-${base}`;
24
24
  }
25
25
  // --- Component ---------------------------------------------------------------
26
- export function AdminFaqEditorView({ faqId, onSaved, onDeleted, ...rest }) {
26
+ export function AdminFaqEditorView({ faqId, onSaved, onDeleted, embedded, ...rest }) {
27
27
  const isEdit = Boolean(faqId);
28
28
  const [question, setQuestion] = React.useState("");
29
29
  const [slug, setSlug] = React.useState("");
@@ -112,17 +112,19 @@ export function AdminFaqEditorView({ faqId, onSaved, onDeleted, ...rest }) {
112
112
  });
113
113
  const isSubmitting = saveMutation.isPending || faqQuery.isLoading;
114
114
  const canSave = Boolean(question.trim()) && Boolean(answer.trim());
115
- return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit FAQ" : "New FAQ", sections: [
116
- _jsxs(Form, { onSubmit: (e) => {
117
- e.preventDefault();
118
- saveMutation.mutate();
119
- }, className: "space-y-5", children: [_jsx(Input, { label: "Question", value: question, onChange: (e) => handleQuestionChange(e.target.value), required: true, placeholder: "e.g. How does bidding work on LetItRip?" }), _jsx(Input, { label: "Slug", value: slug, onChange: (e) => {
120
- setSlug(e.target.value);
121
- setSlugManual(true);
122
- }, placeholder: "faq-how-does-bidding-work", helperText: "Auto-generated from question. Must start with 'faq-'." }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Answer" }), _jsx(RichTextEditor, { value: answer, onChange: setAnswer, placeholder: "Write a clear, helpful answer...", minHeightClassName: "min-h-[200px]" })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Select, { label: "Category", options: CATEGORY_OPTIONS, value: category, onValueChange: setCategory }), _jsx(Input, { label: "Display order", value: String(order), onChange: (e) => setOrder(parseInt(e.target.value, 10) || 0), type: "number", min: 0, helperText: "Lower = shown first within category." })] }), _jsx(Input, { label: "Priority", value: String(priority), onChange: (e) => setPriority(parseInt(e.target.value, 10) || 0), type: "number", min: 0, helperText: "Higher priority FAQs appear first in search results." }), _jsx(TagInput, { label: "Tags", value: tags, onChange: setTags, placeholder: "e.g. shipping, pokemon, returns" }), _jsxs("div", { className: "space-y-3 rounded-lg border border-zinc-200 dark:border-zinc-700 p-4", children: [_jsx("p", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Visibility" }), _jsx(Toggle, { label: "Active (visible to users)", checked: isActive, onChange: setIsActive }), _jsx(Toggle, { label: "Pinned (always shown at top)", checked: isPinned, onChange: setIsPinned }), _jsx(Toggle, { label: "Show on homepage FAQ section", checked: showOnHomepage, onChange: setShowOnHomepage }), _jsx(Toggle, { label: "Show in footer FAQ links", checked: showInFooter, onChange: setShowInFooter })] }), _jsxs("div", { className: "flex gap-3 pt-2", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !canSave || isSubmitting, children: isEdit ? "Save changes" : "Create FAQ" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => {
123
- if (confirm("Delete this FAQ? This cannot be undone.")) {
124
- deleteMutation.mutate();
125
- }
126
- }, children: "Delete FAQ" }))] })] }, "faq-form"),
127
- ] }));
115
+ const formSection = (_jsxs(Form, { onSubmit: (e) => {
116
+ e.preventDefault();
117
+ saveMutation.mutate();
118
+ }, className: "space-y-5", children: [_jsx(Input, { label: "Question", value: question, onChange: (e) => handleQuestionChange(e.target.value), required: true, placeholder: "e.g. How does bidding work on LetItRip?" }), _jsx(Input, { label: "Slug", value: slug, onChange: (e) => {
119
+ setSlug(e.target.value);
120
+ setSlugManual(true);
121
+ }, placeholder: "faq-how-does-bidding-work", helperText: "Auto-generated from question. Must start with 'faq-'." }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Answer" }), _jsx(RichTextEditor, { value: answer, onChange: setAnswer, placeholder: "Write a clear, helpful answer...", minHeightClassName: "min-h-[200px]" })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Select, { label: "Category", options: CATEGORY_OPTIONS, value: category, onValueChange: setCategory }), _jsx(Input, { label: "Display order", value: String(order), onChange: (e) => setOrder(parseInt(e.target.value, 10) || 0), type: "number", min: 0, helperText: "Lower = shown first within category." })] }), _jsx(Input, { label: "Priority", value: String(priority), onChange: (e) => setPriority(parseInt(e.target.value, 10) || 0), type: "number", min: 0, helperText: "Higher priority FAQs appear first in search results." }), _jsx(TagInput, { label: "Tags", value: tags, onChange: setTags, placeholder: "e.g. shipping, pokemon, returns" }), _jsxs("div", { className: "space-y-3 rounded-lg border border-zinc-200 dark:border-zinc-700 p-4", children: [_jsx("p", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Visibility" }), _jsx(Toggle, { label: "Active (visible to users)", checked: isActive, onChange: setIsActive }), _jsx(Toggle, { label: "Pinned (always shown at top)", checked: isPinned, onChange: setIsPinned }), _jsx(Toggle, { label: "Show on homepage FAQ section", checked: showOnHomepage, onChange: setShowOnHomepage }), _jsx(Toggle, { label: "Show in footer FAQ links", checked: showInFooter, onChange: setShowInFooter })] }), _jsxs("div", { className: "flex gap-3 pt-2", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !canSave || isSubmitting, children: isEdit ? "Save changes" : "Create FAQ" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => {
122
+ if (confirm("Delete this FAQ? This cannot be undone.")) {
123
+ deleteMutation.mutate();
124
+ }
125
+ }, children: "Delete FAQ" }))] })] }, "faq-form"));
126
+ if (embedded) {
127
+ return _jsx("div", { className: "overflow-y-auto p-4", children: formSection });
128
+ }
129
+ return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit FAQ" : "New FAQ", sections: [formSection] }));
128
130
  }
@@ -1,12 +1,14 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import React, { useState, useCallback } from "react";
4
- import { X } from "lucide-react";
4
+ import { Plus, X } from "lucide-react";
5
5
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
- import { ListingToolbar, Pagination, ListingViewShell } from "../../../ui";
6
+ import { usePanelUrlSync } from "../../../react/hooks/use-panel-url-sync";
7
+ import { Button, ListingToolbar, Pagination, ListingViewShell, SideDrawer } from "../../../ui";
7
8
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
8
9
  import { toRecordArray, toRelativeDate, toStringValue, useAdminListingData, } from "../hooks/useAdminListingData";
9
10
  import { DataTable } from "./DataTable";
11
+ import { AdminFaqEditorView } from "./AdminFaqEditorView";
10
12
  const PAGE_SIZE = 25;
11
13
  const FILTER_KEYS = ["isActive"];
12
14
  const DEFAULT_SORT = "priority";
@@ -18,6 +20,7 @@ const SORT_OPTIONS = [
18
20
  export function AdminFaqsView({ children, getRowHref, ...props }) {
19
21
  const hasChildren = React.Children.count(children) > 0;
20
22
  const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
23
+ const { openCreatePanel, openEditPanel, closePanel, isCreateOpen, isEditOpen, editId } = usePanelUrlSync();
21
24
  const [searchInput, setSearchInput] = useState(table.get("q") || "");
22
25
  const [filterOpen, setFilterOpen] = useState(false);
23
26
  const [pendingFilters, setPendingFilters] = useState(() => Object.fromEntries(FILTER_KEYS.map((k) => [k, table.get(k)])));
@@ -71,5 +74,5 @@ export function AdminFaqsView({ children, getRowHref, ...props }) {
71
74
  if (hasChildren) {
72
75
  return _jsx(ListingViewShell, { portal: "admin", ...props, children: children });
73
76
  }
74
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search questions, categories, or tokens", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); table.setPage(1); }, hideViewToggle: true, onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-200", children: errorMessage })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No FAQs found", getRowHref: getRowHref })] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Status" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Published", value: "true" }, { label: "Draft", value: "false" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isActive: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isActive || "") === opt.value ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }))] }));
77
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search questions, categories, or tokens", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); table.setPage(1); }, hideViewToggle: true, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: openCreatePanel, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), "Add FAQ"] }) }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-200", children: errorMessage })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No FAQs found", onRowClick: (row) => openEditPanel(row.id) })] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Status" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Published", value: "true" }, { label: "Draft", value: "false" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isActive: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isActive || "") === opt.value ? "bg-primary text-white border-primary" : "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] })), _jsx(SideDrawer, { isOpen: isCreateOpen || isEditOpen, onClose: closePanel, title: isCreateOpen ? "Add FAQ" : "Edit FAQ", mode: isCreateOpen ? "create" : "edit", children: (isCreateOpen || isEditOpen) && (_jsx(AdminFaqEditorView, { faqId: editId ?? undefined, onSaved: closePanel, onDeleted: closePanel, embedded: true })) })] }));
75
78
  }