@mohasinac/appkit 4.30.19 → 4.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (417) hide show
  1. package/dist/_internal/client/features/layout/useSidebarSearch.d.ts +21 -5
  2. package/dist/_internal/client/features/layout/useSidebarSearch.js +27 -6
  3. package/dist/_internal/client/features/lottery/LotteryAdminEditView.d.ts +23 -3
  4. package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +106 -87
  5. package/dist/_internal/client/features/lottery/LotteryPullForm.d.ts +16 -5
  6. package/dist/_internal/client/features/lottery/LotteryPullForm.js +65 -40
  7. package/dist/_internal/server/features/auth/permissions.d.ts +2 -0
  8. package/dist/_internal/server/features/auth/permissions.js +3 -2
  9. package/dist/_internal/server/features/categories/data.js +15 -4
  10. package/dist/_internal/server/features/classified/index.d.ts +0 -1
  11. package/dist/_internal/server/features/classified/index.js +0 -1
  12. package/dist/_internal/server/features/digital-code/index.d.ts +0 -1
  13. package/dist/_internal/server/features/digital-code/index.js +0 -1
  14. package/dist/_internal/server/features/live/index.d.ts +0 -1
  15. package/dist/_internal/server/features/live/index.js +0 -1
  16. package/dist/_internal/server/features/products/data.js +15 -5
  17. package/dist/_internal/server/features/products/list-public.d.ts +9 -0
  18. package/dist/_internal/server/features/products/list-public.js +95 -7
  19. package/dist/_internal/server/features/site-settings/adapters.d.ts +2 -2
  20. package/dist/_internal/server/features/site-settings/adapters.js +8 -5
  21. package/dist/_internal/server/features/tester/visibility.d.ts +2 -1
  22. package/dist/_internal/server/features/tester/visibility.js +2 -2
  23. package/dist/_internal/server/functions/scheduled.d.ts +3 -1
  24. package/dist/_internal/server/functions/scheduled.js +27 -1
  25. package/dist/_internal/server/jobs/core/hardBanCascade.js +4 -0
  26. package/dist/_internal/server/jobs/core/index.d.ts +2 -0
  27. package/dist/_internal/server/jobs/core/index.js +2 -0
  28. package/dist/_internal/server/jobs/core/pageViewPrune.d.ts +10 -0
  29. package/dist/_internal/server/jobs/core/pageViewPrune.js +44 -0
  30. package/dist/_internal/server/jobs/core/pageViewRollup.d.ts +2 -0
  31. package/dist/_internal/server/jobs/core/pageViewRollup.js +87 -0
  32. package/dist/_internal/server/jobs/handlers/index.d.ts +2 -0
  33. package/dist/_internal/server/jobs/handlers/index.js +2 -0
  34. package/dist/_internal/server/jobs/handlers/pageViewPrune.d.ts +2 -0
  35. package/dist/_internal/server/jobs/handlers/pageViewPrune.js +2 -0
  36. package/dist/_internal/server/jobs/handlers/pageViewRollup.d.ts +2 -0
  37. package/dist/_internal/server/jobs/handlers/pageViewRollup.js +2 -0
  38. package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
  39. package/dist/_internal/shared/actions/action-registry.js +69 -22
  40. package/dist/_internal/shared/checkout/rules/classified.rule.d.ts +9 -4
  41. package/dist/_internal/shared/checkout/rules/classified.rule.js +7 -2
  42. package/dist/_internal/shared/features/layout/matchesNavQuery.d.ts +14 -0
  43. package/dist/_internal/shared/features/layout/matchesNavQuery.js +72 -0
  44. package/dist/_internal/shared/features/layout/types.d.ts +37 -1
  45. package/dist/_internal/shared/features/layout/types.js +19 -1
  46. package/dist/_internal/shared/features/notifications/action-url.d.ts +9 -1
  47. package/dist/_internal/shared/features/notifications/action-url.js +47 -0
  48. package/dist/_internal/shared/features/offers/config.d.ts +65 -0
  49. package/dist/_internal/shared/features/offers/config.js +73 -2
  50. package/dist/_internal/shared/features/orders/schema.d.ts +19 -1
  51. package/dist/_internal/shared/features/orders/schema.js +22 -2
  52. package/dist/_internal/shared/features/site-settings/types.d.ts +12 -3
  53. package/dist/_internal/shared/listing-types/capabilities.d.ts +8 -2
  54. package/dist/_internal/shared/listing-types/capabilities.js +6 -1
  55. package/dist/_internal/shared/listing-types/classified/ctas.js +6 -1
  56. package/dist/_internal/shared/listing-types/feature-flags.d.ts +10 -5
  57. package/dist/_internal/shared/listing-types/feature-flags.js +11 -6
  58. package/dist/client.d.ts +37 -20
  59. package/dist/client.js +36 -14
  60. package/dist/configs/next.js +10 -2
  61. package/dist/constants/api-endpoints.d.ts +18 -54
  62. package/dist/constants/api-endpoints.js +6 -26
  63. package/dist/constants/field-names.d.ts +6 -24
  64. package/dist/constants/field-names.js +10 -27
  65. package/dist/constants/geo/countries.d.ts +50 -0
  66. package/dist/constants/geo/countries.js +129 -0
  67. package/dist/constants/geo/subdivisions.d.ts +13 -0
  68. package/dist/constants/geo/subdivisions.js +104 -0
  69. package/dist/constants/index.d.ts +2 -2
  70. package/dist/constants/index.js +2 -2
  71. package/dist/constants/table-keys.d.ts +24 -0
  72. package/dist/constants/table-keys.js +28 -0
  73. package/dist/contracts/extend.d.ts +0 -9
  74. package/dist/contracts/index.d.ts +1 -1
  75. package/dist/contracts/realtime-session.js +7 -0
  76. package/dist/core/browser.d.ts +1 -1
  77. package/dist/core/browser.js +1 -1
  78. package/dist/core/index.d.ts +1 -1
  79. package/dist/core/index.js +1 -1
  80. package/dist/core/site-config.d.ts +0 -3
  81. package/dist/core/site-config.js +0 -3
  82. package/dist/errors/messages.d.ts +0 -8
  83. package/dist/errors/messages.js +0 -9
  84. package/dist/features/about/schemas/index.d.ts +8 -8
  85. package/dist/features/account/components/AddressFilters.js +32 -11
  86. package/dist/features/account/components/AddressForm.d.ts +26 -25
  87. package/dist/features/account/components/AddressForm.js +81 -103
  88. package/dist/features/account/components/AddressesIndexListing.js +8 -4
  89. package/dist/features/account/components/UserSidebar.d.ts +3 -4
  90. package/dist/features/account/components/UserSupportView.js +89 -58
  91. package/dist/features/account/components/index.d.ts +1 -7
  92. package/dist/features/account/components/index.js +0 -3
  93. package/dist/features/account/hooks/useAddresses.d.ts +4 -3
  94. package/dist/features/account/hooks/useAddresses.js +4 -6
  95. package/dist/features/account/hooks/useCollapsedSections.d.ts +51 -10
  96. package/dist/features/account/hooks/useCollapsedSections.js +211 -38
  97. package/dist/features/account/hooks/useProfile.d.ts +8 -0
  98. package/dist/features/account/index.d.ts +0 -3
  99. package/dist/features/account/index.js +0 -3
  100. package/dist/features/account/schemas/index.d.ts +0 -92
  101. package/dist/features/account/schemas/index.js +42 -20
  102. package/dist/features/addresses/components/AddressLocationFields.d.ts +13 -0
  103. package/dist/features/addresses/components/AddressLocationFields.js +41 -0
  104. package/dist/features/addresses/hooks/usePostalLookup.d.ts +17 -0
  105. package/dist/features/addresses/hooks/usePostalLookup.js +133 -0
  106. package/dist/features/addresses/schemas/address-form.d.ts +423 -0
  107. package/dist/features/addresses/schemas/address-form.js +212 -0
  108. package/dist/features/addresses/schemas/index.d.ts +1 -0
  109. package/dist/features/addresses/schemas/index.js +8 -0
  110. package/dist/features/admin/actions/admin-read-actions.d.ts +1 -1
  111. package/dist/features/admin/actions/index.d.ts +0 -1
  112. package/dist/features/admin/actions/index.js +0 -1
  113. package/dist/features/admin/actions/notification-actions.js +1 -41
  114. package/dist/features/admin/components/AdminActionIndexView.d.ts +32 -0
  115. package/dist/features/admin/components/AdminActionIndexView.js +128 -0
  116. package/dist/features/admin/components/AdminAdEditorView.js +159 -163
  117. package/dist/features/admin/components/AdminAddressEditorView.js +97 -55
  118. package/dist/features/admin/components/AdminBrandEditorView.d.ts +15 -0
  119. package/dist/features/admin/components/AdminBrandEditorView.js +113 -77
  120. package/dist/features/admin/components/AdminBundleEditorView.d.ts +19 -9
  121. package/dist/features/admin/components/AdminBundleEditorView.js +136 -168
  122. package/dist/features/admin/components/AdminCategoryEditorView.js +120 -43
  123. package/dist/features/admin/components/AdminCouponEditorView.js +145 -109
  124. package/dist/features/admin/components/AdminEmployeeEditorView.js +125 -56
  125. package/dist/features/admin/components/AdminFaqEditorView.js +112 -58
  126. package/dist/features/admin/components/AdminFeatureEditorView.js +108 -68
  127. package/dist/features/admin/components/AdminNavEditorView.js +69 -44
  128. package/dist/features/admin/components/AdminOrderEditorView.js +47 -10
  129. package/dist/features/admin/components/AdminPrizeDrawsView.js +16 -2
  130. package/dist/features/admin/components/AdminSidebar.d.ts +11 -7
  131. package/dist/features/admin/components/AdminSiteSettingsView.js +37 -37
  132. package/dist/features/admin/components/AdminStoreEditorView.js +75 -52
  133. package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +71 -30
  134. package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +95 -65
  135. package/dist/features/admin/components/BrandQuickCreateForm.d.ts +10 -0
  136. package/dist/features/admin/components/BrandQuickCreateForm.js +49 -26
  137. package/dist/features/admin/components/CategoryQuickCreateForm.d.ts +11 -0
  138. package/dist/features/admin/components/CategoryQuickCreateForm.js +48 -26
  139. package/dist/features/admin/components/index.d.ts +2 -2
  140. package/dist/features/admin/components/index.js +1 -1
  141. package/dist/features/admin/constants/site-settings-tabs.d.ts +120 -0
  142. package/dist/features/admin/constants/site-settings-tabs.js +152 -0
  143. package/dist/features/admin/index.d.ts +0 -3
  144. package/dist/features/admin/index.js +0 -2
  145. package/dist/features/admin/repository/analytics-rollup.repository.d.ts +35 -0
  146. package/dist/features/admin/repository/analytics-rollup.repository.js +30 -0
  147. package/dist/features/admin/schemas/admin-editor-forms.d.ts +56 -57
  148. package/dist/features/admin/schemas/admin-editor-forms.js +97 -54
  149. package/dist/features/admin/schemas/admin-ops-forms.d.ts +57 -5
  150. package/dist/features/admin/schemas/admin-ops-forms.js +104 -20
  151. package/dist/features/admin/schemas/admin-user-form.js +7 -0
  152. package/dist/features/admin/schemas/firestore.d.ts +48 -95
  153. package/dist/features/admin/schemas/firestore.js +15 -151
  154. package/dist/features/admin/schemas/nav-item-form.js +9 -2
  155. package/dist/features/admin/server.d.ts +0 -4
  156. package/dist/features/admin/server.js +0 -2
  157. package/dist/features/admin/types/index.d.ts +0 -7
  158. package/dist/features/analytics/repository/page-views.repository.d.ts +14 -0
  159. package/dist/features/analytics/repository/page-views.repository.js +24 -0
  160. package/dist/features/auth/actions/index.d.ts +0 -1
  161. package/dist/features/auth/actions/index.js +0 -1
  162. package/dist/features/auth/actions/realtime-token-actions.js +1 -12
  163. package/dist/features/auth/auth-helpers.js +5 -7
  164. package/dist/features/auth/components/Guards.js +2 -1
  165. package/dist/features/auth/components/LoginForm.d.ts +0 -2
  166. package/dist/features/auth/components/LoginForm.js +1 -3
  167. package/dist/features/auth/components/RegisterForm.js +62 -19
  168. package/dist/features/auth/permissions/constants.d.ts +27 -1
  169. package/dist/features/auth/role-predicates.d.ts +75 -7
  170. package/dist/features/auth/role-predicates.js +28 -2
  171. package/dist/features/auth/schemas/firestore.d.ts +22 -0
  172. package/dist/features/auth/schemas/index.d.ts +1 -1
  173. package/dist/features/auth/schemas/index.js +44 -8
  174. package/dist/features/auth/types/index.d.ts +14 -1
  175. package/dist/features/blog/api/route.js +10 -2
  176. package/dist/features/blog/components/BlogIndexListing.js +1 -1
  177. package/dist/features/blog/hooks/useBlog.js +2 -2
  178. package/dist/features/blog/schemas/index.d.ts +4 -0
  179. package/dist/features/blog/schemas/index.js +2 -0
  180. package/dist/features/blog/types/index.d.ts +1 -1
  181. package/dist/features/catalogue/components/CatalogueItemEditorView.d.ts +22 -0
  182. package/dist/features/catalogue/components/CatalogueItemEditorView.js +112 -52
  183. package/dist/features/catalogue/schemas/validation.d.ts +4 -4
  184. package/dist/features/catalogue/schemas/validation.js +47 -10
  185. package/dist/features/categories/schemas/bundle-form.d.ts +142 -0
  186. package/dist/features/categories/schemas/bundle-form.js +149 -0
  187. package/dist/features/classified/components/ClassifiedDetailPageView.d.ts +5 -4
  188. package/dist/features/classified/components/ClassifiedDetailPageView.js +37 -16
  189. package/dist/features/consultation/components/ConsultationForm.js +1 -1
  190. package/dist/features/consultation/schemas/index.js +34 -10
  191. package/dist/features/corporate/schemas/index.js +36 -15
  192. package/dist/features/filters/FilterPanel.js +3 -3
  193. package/dist/features/filters/RangeFilter.d.ts +10 -0
  194. package/dist/features/filters/RangeFilter.js +41 -4
  195. package/dist/features/homepage/components/MarketplaceHomepageView.js +24 -5
  196. package/dist/features/homepage/hooks/useBlogArticles.js +1 -1
  197. package/dist/features/layout/BottomActions.js +84 -11
  198. package/dist/features/layout/BottomActionsContext.d.ts +1 -6
  199. package/dist/features/layout/BottomActionsContext.js +1 -1
  200. package/dist/features/layout/hooks/useBottomActions.js +2 -2
  201. package/dist/features/layout/hooks/useFormBottomActions.d.ts +12 -1
  202. package/dist/features/layout/hooks/useFormBottomActions.js +12 -6
  203. package/dist/features/lottery/schemas/config-write.d.ts +9 -5
  204. package/dist/features/lottery/schemas/config-write.js +69 -9
  205. package/dist/features/orders/schemas/buyer-forms.d.ts +6 -3
  206. package/dist/features/orders/schemas/buyer-forms.js +31 -3
  207. package/dist/features/orders/schemas/index.d.ts +2 -2
  208. package/dist/features/products/components/GroupSettingsPanel.js +3 -1
  209. package/dist/features/products/components/MakeOfferButton.d.ts +13 -2
  210. package/dist/features/products/components/MakeOfferButton.js +33 -11
  211. package/dist/features/products/components/ProductDetailActions.js +0 -1
  212. package/dist/features/products/components/ProductDetailPageView.d.ts +7 -3
  213. package/dist/features/products/components/ProductDetailPageView.js +8 -5
  214. package/dist/features/products/constants/action-defs.d.ts +1 -2
  215. package/dist/features/products/constants/action-defs.js +40 -43
  216. package/dist/features/products/repository/products.repository.d.ts +5 -1
  217. package/dist/features/products/repository/products.repository.js +23 -1
  218. package/dist/features/products/schemas/firestore.d.ts +7 -3
  219. package/dist/features/products/schemas/product-features.validators.js +3 -0
  220. package/dist/features/promotions/components/CouponCard.js +8 -7
  221. package/dist/features/scams/schemas/firestore.d.ts +15 -1
  222. package/dist/features/scams/schemas/report-form.d.ts +5 -5
  223. package/dist/features/scams/schemas/report-form.js +18 -3
  224. package/dist/features/search/action-index/derive.d.ts +49 -0
  225. package/dist/features/search/action-index/derive.js +121 -0
  226. package/dist/features/search/action-index/repository.d.ts +42 -0
  227. package/dist/features/search/action-index/repository.js +100 -0
  228. package/dist/features/search/action-index/settings-entries.d.ts +41 -0
  229. package/dist/features/search/action-index/settings-entries.js +268 -0
  230. package/dist/features/search/action-index/types.d.ts +81 -0
  231. package/dist/features/search/action-index/types.js +102 -0
  232. package/dist/features/search/action-index/validate-entry.d.ts +34 -0
  233. package/dist/features/search/action-index/validate-entry.js +114 -0
  234. package/dist/features/search/hooks/useNavSuggestions.d.ts +5 -1
  235. package/dist/features/search/hooks/useNavSuggestions.js +23 -3
  236. package/dist/features/search/repository/search.repository.js +3 -1
  237. package/dist/features/seller/actions/offer-actions.js +43 -24
  238. package/dist/features/seller/actions/seller-actions.js +29 -5
  239. package/dist/features/seller/components/CategoryChipPicker.d.ts +9 -0
  240. package/dist/features/seller/components/CategoryChipPicker.js +12 -0
  241. package/dist/features/seller/components/SellerAddressesView.js +5 -1
  242. package/dist/features/seller/components/SellerAnalyticsAlertsView.js +83 -43
  243. package/dist/features/seller/components/SellerArtView.d.ts +14 -7
  244. package/dist/features/seller/components/SellerArtView.js +4 -119
  245. package/dist/features/seller/components/SellerClassifiedView.d.ts +14 -7
  246. package/dist/features/seller/components/SellerClassifiedView.js +4 -124
  247. package/dist/features/seller/components/SellerCouponEditorView.d.ts +22 -1
  248. package/dist/features/seller/components/SellerCouponEditorView.js +91 -45
  249. package/dist/features/seller/components/SellerDigitalCodesView.d.ts +14 -7
  250. package/dist/features/seller/components/SellerDigitalCodesView.js +4 -126
  251. package/dist/features/seller/components/SellerListingTypeView.d.ts +66 -0
  252. package/dist/features/seller/components/SellerListingTypeView.js +277 -0
  253. package/dist/features/seller/components/SellerLiveView.d.ts +14 -7
  254. package/dist/features/seller/components/SellerLiveView.js +4 -126
  255. package/dist/features/seller/components/SellerSidebar.d.ts +3 -6
  256. package/dist/features/seller/components/SellerStickersView.d.ts +14 -7
  257. package/dist/features/seller/components/SellerStickersView.js +4 -119
  258. package/dist/features/seller/components/SellerSupportView.d.ts +31 -0
  259. package/dist/features/seller/components/SellerSupportView.js +100 -0
  260. package/dist/features/seller/components/index.d.ts +4 -8
  261. package/dist/features/seller/components/index.js +2 -4
  262. package/dist/features/seller/index.d.ts +0 -1
  263. package/dist/features/seller/index.js +0 -1
  264. package/dist/features/seller/schemas/coupon-form.d.ts +214 -0
  265. package/dist/features/seller/schemas/coupon-form.js +155 -23
  266. package/dist/features/seller/schemas/offer-forms.d.ts +16 -7
  267. package/dist/features/seller/schemas/offer-forms.js +28 -12
  268. package/dist/features/shell/FormShell.js +2 -2
  269. package/dist/features/shell/QuickFormDrawer.js +2 -2
  270. package/dist/features/shell/SectionForm.d.ts +19 -1
  271. package/dist/features/shell/SectionForm.js +104 -17
  272. package/dist/features/shell/build-sections.d.ts +23 -0
  273. package/dist/features/shell/build-sections.js +106 -8
  274. package/dist/features/shell/field-ui-meta.d.ts +44 -0
  275. package/dist/features/shell/field-ui-meta.js +14 -7
  276. package/dist/features/shell/form-sections.d.ts +46 -0
  277. package/dist/features/shell/form-sections.js +114 -0
  278. package/dist/features/shipments/components/AdminShipmentEditorView.js +87 -64
  279. package/dist/features/shipments/schemas/validation.d.ts +2 -2
  280. package/dist/features/shipments/schemas/validation.js +44 -13
  281. package/dist/features/store-extensions/schemas/custom-role-form.js +6 -2
  282. package/dist/features/store-extensions/schemas/listing-template-form.d.ts +7 -7
  283. package/dist/features/store-extensions/schemas/payout-method-form.js +14 -0
  284. package/dist/features/stores/actions/store-query-actions.js +3 -2
  285. package/dist/features/stores/api/[storeSlug]/auctions/route.js +3 -1
  286. package/dist/features/stores/api/[storeSlug]/products/route.js +3 -1
  287. package/dist/features/support/repository/support.repository.d.ts +21 -0
  288. package/dist/features/support/repository/support.repository.js +63 -0
  289. package/dist/features/support/schemas/firestore.d.ts +27 -2
  290. package/dist/features/support/schemas/firestore.js +2 -0
  291. package/dist/features/support/schemas/ticket-create-form.js +7 -0
  292. package/dist/features/tester/schemas/checklist-item-form.d.ts +43 -0
  293. package/dist/features/tester/schemas/checklist-item-form.js +109 -0
  294. package/dist/features/tester/seed-data/blog-tester-seed-data.js +2 -2
  295. package/dist/features/tester/seed-data/categories-tester-seed-data.js +2 -2
  296. package/dist/features/tester/seed-data/events-tester-seed-data.js +5 -5
  297. package/dist/features/tester/seed-data/orders-tester-seed-data.js +2 -2
  298. package/dist/features/tester/seed-data/products-tester-seed-data.js +48 -49
  299. package/dist/features/tester/seed-data/stores-tester-seed-data.js +3 -3
  300. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +275 -29
  301. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +48 -12
  302. package/dist/http/api-handler.js +2 -1
  303. package/dist/index.d.ts +24 -103
  304. package/dist/index.js +33 -141
  305. package/dist/jobs.d.ts +1 -1
  306. package/dist/jobs.js +1 -1
  307. package/dist/monitoring/browser.d.ts +0 -2
  308. package/dist/monitoring/browser.js +12 -1
  309. package/dist/monitoring/index.d.ts +0 -2
  310. package/dist/monitoring/index.js +0 -1
  311. package/dist/next/api/routeHandler.js +6 -3
  312. package/dist/next/index.d.ts +7 -2
  313. package/dist/next/index.js +36 -1
  314. package/dist/next/middleware/index.d.ts +0 -2
  315. package/dist/next/middleware/index.js +0 -1
  316. package/dist/next/routing/route-map.d.ts +8 -7
  317. package/dist/next/routing/route-map.js +10 -3
  318. package/dist/providers/db-firebase/admin.js +15 -1
  319. package/dist/providers/db-firebase/sieve.d.ts +22 -0
  320. package/dist/react/hooks/useListingTypeFlags.d.ts +1 -1
  321. package/dist/react/hooks/useListingTypeFlags.js +1 -1
  322. package/dist/react/hooks/usePendingFilters.js +5 -3
  323. package/dist/react/hooks/usePendingTable.js +15 -3
  324. package/dist/repositories/index.d.ts +0 -1
  325. package/dist/repositories/index.js +0 -1
  326. package/dist/schemas/registry.d.ts +197 -232
  327. package/dist/schemas/registry.js +5 -6
  328. package/dist/schemas/webhooks/razorpay.d.ts +50 -50
  329. package/dist/security/authorization.d.ts +9 -0
  330. package/dist/security/authorization.js +16 -2
  331. package/dist/security/browser.d.ts +1 -3
  332. package/dist/security/browser.js +5 -2
  333. package/dist/security/index.d.ts +1 -3
  334. package/dist/security/index.js +19 -2
  335. package/dist/security/pii-encrypt.js +16 -0
  336. package/dist/security/pii-schemas.d.ts +0 -14
  337. package/dist/security/pii-schemas.js +7 -15
  338. package/dist/seed/_helpers/category-forest.js +2 -2
  339. package/dist/seed/_helpers/media.d.ts +19 -0
  340. package/dist/seed/_helpers/media.js +75 -0
  341. package/dist/seed/blog-posts-seed-data.js +17 -17
  342. package/dist/seed/carousel-slides-seed-data.js +7 -7
  343. package/dist/seed/cart-seed-data.js +13 -13
  344. package/dist/seed/categories-seed-data.js +10 -10
  345. package/dist/seed/events-seed-data.js +24 -24
  346. package/dist/seed/factories/product.factory.js +4 -4
  347. package/dist/seed/factories/store.factory.js +3 -3
  348. package/dist/seed/factories/user.factory.js +2 -2
  349. package/dist/seed/grouped-listings-seed-data.js +11 -11
  350. package/dist/seed/homepage-sections-seed-data.js +2 -2
  351. package/dist/seed/index.d.ts +0 -1
  352. package/dist/seed/index.js +0 -1
  353. package/dist/seed/manifest.d.ts +1 -1
  354. package/dist/seed/manifest.js +0 -5
  355. package/dist/seed/notifications-seed-data.js +20 -1
  356. package/dist/seed/orders-seed-data.js +2 -2
  357. package/dist/seed/products-art-seed-data.js +16 -16
  358. package/dist/seed/products-auctions-seed-data.js +34 -34
  359. package/dist/seed/products-classifieds-seed-data.js +35 -37
  360. package/dist/seed/products-digital-codes-seed-data.js +20 -20
  361. package/dist/seed/products-live-items-seed-data.js +11 -11
  362. package/dist/seed/products-preorders-seed-data.js +13 -13
  363. package/dist/seed/products-prize-draws-seed-data.js +43 -43
  364. package/dist/seed/products-standard-seed-data.js +54 -54
  365. package/dist/seed/products-stickers-seed-data.js +15 -15
  366. package/dist/seed/reviews-seed-data.js +4 -4
  367. package/dist/seed/scammers-seed-data.js +3 -3
  368. package/dist/seed/site-settings-seed-data.js +11 -24
  369. package/dist/seed/store-extensions-seed-data.js +10 -10
  370. package/dist/seed/stores-seed-data.js +11 -11
  371. package/dist/seed/support-tickets-seed-data.d.ts +14 -0
  372. package/dist/seed/support-tickets-seed-data.js +20 -1
  373. package/dist/seed/users-seed-data.js +20 -20
  374. package/dist/server-entry.d.ts +0 -1
  375. package/dist/server-entry.js +0 -1
  376. package/dist/server.d.ts +9 -6
  377. package/dist/server.js +7 -13
  378. package/dist/styles.css +248 -68
  379. package/dist/tailwind-utilities.css +1 -1
  380. package/dist/tokens/themes/default-dark.js +2 -2
  381. package/dist/tokens/themes/default-light.js +2 -2
  382. package/dist/tokens/tokens.css +24 -4
  383. package/dist/ui/components/ActionRow.d.ts +50 -0
  384. package/dist/ui/components/ActionRow.js +53 -0
  385. package/dist/ui/components/ActionRow.style.css +145 -0
  386. package/dist/ui/components/Drawer.d.ts +10 -0
  387. package/dist/ui/components/Drawer.js +2 -1
  388. package/dist/ui/components/FilterDrawer.js +4 -1
  389. package/dist/ui/components/FilterDrawer.style.css +6 -12
  390. package/dist/ui/components/FormActionBar.js +14 -1
  391. package/dist/ui/components/FormActionBar.style.css +12 -11
  392. package/dist/ui/components/ListingLayout.js +8 -1
  393. package/dist/ui/components/ListingLayout.style.css +6 -13
  394. package/dist/ui/components/Modal.d.ts +15 -1
  395. package/dist/ui/components/Modal.js +17 -3
  396. package/dist/ui/components/QuickCreateModal.js +2 -2
  397. package/dist/ui/components/QuickCreateModal.style.css +78 -84
  398. package/dist/ui/components/RecordDetailModal.js +2 -2
  399. package/dist/ui/components/SideDrawer.d.ts +8 -0
  400. package/dist/ui/components/SideDrawer.js +2 -1
  401. package/dist/ui/components/SideDrawer.style.css +6 -3
  402. package/dist/ui/components/SideModal.d.ts +11 -1
  403. package/dist/ui/components/SideModal.js +3 -2
  404. package/dist/ui/components/SideModal.style.css +14 -0
  405. package/dist/ui/components/Typography.style.css +33 -24
  406. package/dist/ui/components/index.style.css +1 -0
  407. package/dist/ui/forms/FormShell.style.css +260 -311
  408. package/dist/ui/index.d.ts +2 -0
  409. package/dist/ui/index.js +1 -0
  410. package/dist/utils/index.d.ts +0 -1
  411. package/dist/utils/index.js +0 -1
  412. package/dist/validation/index.d.ts +1 -1
  413. package/dist/validation/index.js +1 -1
  414. package/dist/validation/schemas.d.ts +0 -19
  415. package/dist/validation/schemas.js +8 -19
  416. package/package.json +1 -1
  417. package/scripts/seed-cli.mjs +3 -6
@@ -1,17 +1,33 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { Row } from "@mohasinac/appkit/ui";
4
3
  import { useApiMutation } from "@mohasinac/appkit/client";
5
4
  import React from "react";
6
5
  import { useQuery } from "@tanstack/react-query";
7
6
  import { z } from "zod";
8
- import { Button, ConfirmDeleteModal, Div, Form, Input, StackedViewShell, useToast, } from "../../../ui";
9
- import { FieldInput, FormErrorSummary } from "../../../ui/forms";
7
+ import { ConfirmDeleteModal, Div, Input, Stack, StackedViewShell, useToast, } from "../../../ui";
8
+ import { FieldInput, FormErrorSummary, FormShellContext, useFormShellState } from "../../../ui/forms";
9
+ import { SectionForm, useSectionFormNav } from "../../shell";
10
+ /**
11
+ * Describes the fields this form actually edits.
12
+ *
13
+ * It previously declared `slug` and `parentId` — neither of which the form has
14
+ * a control for or ever sends — while omitting `itemCode`, `description` and
15
+ * `coverImage`, which it does send. `.passthrough()` let the three real fields
16
+ * through unvalidated, and the two phantom ones were `.optional()`, so the
17
+ * mismatch never produced an error: validation was only ever checking `name`.
18
+ */
10
19
  const sublistingCategoryFormSchema = z.object({
11
- name: z.string().min(1, "Name is required").max(120),
12
- slug: z.string().regex(/^[a-z0-9-]+$/, "Lowercase letters, digits and hyphens only").optional().or(z.literal("")),
13
- parentId: z.string().nullable().optional(),
14
- }).passthrough();
20
+ name: z.string().min(1, "Category name is required").max(120),
21
+ itemCode: z.string().max(60, "Keep the item code under 60 characters").optional().or(z.literal("")),
22
+ description: z.string().max(500, "Keep the description under 500 characters").optional().or(z.literal("")),
23
+ coverImage: z.string().optional().or(z.literal("")),
24
+ });
25
+ const EMPTY_VALUES = {
26
+ name: "",
27
+ itemCode: "",
28
+ description: "",
29
+ coverImage: "",
30
+ };
15
31
  import { ImageUpload } from "../../media/upload/ImageUpload";
16
32
  import { useMediaUpload } from "../../media";
17
33
  import { apiClient } from "../../../http";
@@ -19,11 +35,11 @@ import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
19
35
  export function AdminSublistingCategoryEditorView({ categoryId, onSaved, onDeleted, ...rest }) {
20
36
  const isEdit = Boolean(categoryId);
21
37
  const { showToast } = useToast();
22
- const [name, setName] = React.useState("");
23
- const [itemCode, setItemCode] = React.useState("");
24
- const [description, setDescription] = React.useState("");
25
- const [coverImage, setCoverImage] = React.useState("");
38
+ const [values, setValues] = React.useState(EMPTY_VALUES);
26
39
  const [deleteConfirmOpen, setDeleteConfirmOpen] = React.useState(false);
40
+ const handleChange = React.useCallback((partial) => {
41
+ setValues((prev) => Object.assign({}, prev, partial));
42
+ }, []);
27
43
  const categoryQuery = useQuery({
28
44
  queryKey: ["admin", "sublisting-category", categoryId],
29
45
  queryFn: async () => {
@@ -36,19 +52,21 @@ export function AdminSublistingCategoryEditorView({ categoryId, onSaved, onDelet
36
52
  const cat = categoryQuery.data;
37
53
  if (!cat)
38
54
  return;
39
- setName(cat.name ?? "");
40
- setItemCode(cat.itemCode ?? "");
41
- setDescription(cat.description ?? "");
42
- setCoverImage(cat.coverImage ?? "");
55
+ setValues({
56
+ name: cat.name ?? "",
57
+ itemCode: cat.itemCode ?? "",
58
+ description: cat.description ?? "",
59
+ coverImage: cat.coverImage ?? "",
60
+ });
43
61
  }, [categoryQuery.data]);
44
62
  const saveMutation = useApiMutation({
45
63
  errorMessage: "Failed to save category.",
46
64
  mutationFn: async () => {
47
65
  const payload = {
48
- name,
49
- itemCode: itemCode || undefined,
50
- description: description || undefined,
51
- coverImage: coverImage || undefined,
66
+ name: values.name,
67
+ itemCode: values.itemCode || undefined,
68
+ description: values.description || undefined,
69
+ coverImage: values.coverImage || undefined,
52
70
  };
53
71
  if (isEdit) {
54
72
  return apiClient.put(ADMIN_ENDPOINTS.SUBLISTING_CATEGORY_BY_ID(categoryId), payload);
@@ -73,17 +91,40 @@ export function AdminSublistingCategoryEditorView({ categoryId, onSaved, onDelet
73
91
  });
74
92
  const { upload } = useMediaUpload();
75
93
  const isSubmitting = saveMutation.isPending || categoryQuery.isLoading;
94
+ const sections = React.useMemo(() => [
95
+ {
96
+ id: "basics",
97
+ label: "Details",
98
+ required: true,
99
+ fields: ["name", "itemCode", "description"],
100
+ render: ({ values: v, onChange, errors }) => (_jsxs(Stack, { gap: "md", children: [_jsxs(Div, { layout: "grid", gap: "4", className: "sm:grid-cols-2", children: [_jsx(FieldInput, { name: "name", label: "Category name", value: String(v.name ?? ""), onChange: (val) => onChange({ name: val }), required: true, placeholder: "e.g. Base Set Charizard 108/120", error: errors.name }), _jsx(Input, { label: "Item code", value: String(v.itemCode ?? ""), onChange: (e) => onChange({ itemCode: e.target.value }), placeholder: "e.g. PSA 10, 108/120, STH", helperText: "Grade, card number, or series code. Optional.", error: errors.itemCode })] }), _jsx(Input, { label: "Description", value: String(v.description ?? ""), onChange: (e) => onChange({ description: e.target.value }), placeholder: "Brief description shown on the public category page", error: errors.description })] })),
101
+ },
102
+ {
103
+ id: "media",
104
+ label: "Cover image",
105
+ fields: ["coverImage"],
106
+ // The upload holds uncommitted state while a file is in flight, so the
107
+ // panel must survive being collapsed.
108
+ keepMounted: true,
109
+ render: ({ values: v, onChange }) => (_jsx(ImageUpload, { label: "Cover image", currentImage: String(v.coverImage ?? ""), onUpload: (file) => upload(file, "sublisting-categories", true, {
110
+ type: "category-image",
111
+ name: String(v.name ?? "") || "sublisting",
112
+ }), onChange: (url) => onChange({ coverImage: url }) })),
113
+ },
114
+ ], [upload]);
115
+ const nav = useSectionFormNav(sections, values);
116
+ const { shellCtx } = useFormShellState(sublistingCategoryFormSchema, {
117
+ sections: nav.sectionMeta,
118
+ onGoToSection: nav.goToSection,
119
+ fieldToSectionIndex: nav.fieldToSectionIndex,
120
+ });
76
121
  return (_jsxs(_Fragment, { children: [_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Sub-listing Category" : "New Sub-listing Category", sections: [
77
- _jsx(Form, { schema: sublistingCategoryFormSchema, onSubmit: (e) => e.preventDefault(), spacing: "md", children: ({ setFieldError, clearErrors }) => (_jsxs(_Fragment, { children: [_jsxs(Div, { layout: "grid", gap: "4", className: "sm:grid-cols-2", children: [_jsx(FieldInput, { name: "name", label: "Category name", value: name, onChange: (v) => setName(v), required: true, placeholder: "e.g. Base Set Charizard 108/120" }), _jsx(Input, { label: "Item code", value: itemCode, onChange: (e) => setItemCode(e.target.value), placeholder: "e.g. PSA 10, 108/120, STH", helperText: "Grade, card number, or series code. Optional." })] }), _jsx(Input, { label: "Description", value: description, onChange: (e) => setDescription(e.target.value), placeholder: "Brief description shown on the public category page" }), _jsx(ImageUpload, { label: "Cover image", currentImage: coverImage, onUpload: (file) => upload(file, "sublisting-categories", true, {
78
- type: "category-image",
79
- name: name || "sublisting",
80
- }), onChange: setCoverImage }), _jsx(FormErrorSummary, {}), _jsxs(Row, { gap: "3", padding: "t-xs", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !name || isSubmitting, onClick: () => {
81
- clearErrors();
82
- if (!name.trim()) {
83
- setFieldError("name", "Category name is required");
84
- return;
85
- }
86
- saveMutation.mutate();
87
- }, children: isEdit ? "Save changes" : "Create category" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => setDeleteConfirmOpen(true), children: "Delete" }))] })] })) }, "sc-editor-form"),
122
+ _jsxs(FormShellContext.Provider, { value: shellCtx, children: [_jsx(FormErrorSummary, {}), _jsx(SectionForm, { sections: sections, values: values, onChange: handleChange, onSubmit: () => saveMutation.mutate(), schema: sublistingCategoryFormSchema, openIds: nav.openIds, onOpenChange: nav.setOpenIds, isLoading: isSubmitting, submitLabel: isEdit ? "Save changes" : "Create category", destructiveAction: isEdit
123
+ ? {
124
+ label: "Delete",
125
+ onClick: () => setDeleteConfirmOpen(true),
126
+ disabled: deleteMutation.isPending,
127
+ }
128
+ : undefined })] }, "sc-editor-form"),
88
129
  ] }), deleteConfirmOpen && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Sublisting Category", message: "Delete this category? All linked listings will be unlinked. This cannot be undone.", onConfirm: () => { deleteMutation.mutate(); setDeleteConfirmOpen(false); }, onClose: () => setDeleteConfirmOpen(false), isDeleting: deleteMutation.isPending }))] }));
89
130
  }
@@ -3,25 +3,35 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  import { useApiMutation } from "@mohasinac/appkit/client";
4
4
  import React from "react";
5
5
  import { useQuery } from "@tanstack/react-query";
6
- import { z } from "zod";
7
- import { Button, ConfirmDeleteModal, Div, Form, Input, Row, Stack, StackedViewShell, Text, Toggle, useToast, } from "../../../ui";
8
- import { FieldInput, FieldTextarea, FormErrorSummary } from "../../../ui/forms";
6
+ import { ConfirmDeleteModal, Div, StackedViewShell, useToast } from "../../../ui";
7
+ import { FieldInput, FormErrorSummary } from "../../../ui/forms";
8
+ import { FormShellContext, useFormShellState } from "../../../ui/forms/FormShell";
9
+ import { applyZodIssues } from "../../../ui/forms/apply-zod-issues";
10
+ import { buildSectionsFromSchema, visibleValues } from "../../shell/build-sections";
11
+ import { SectionForm, useSectionFormNav } from "../../shell/SectionForm";
9
12
  import { apiClient } from "../../../http";
10
13
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
11
14
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
12
- const checklistItemFormSchema = z.object({
13
- groupKey: z.string().min(1, "Group key is required").max(100),
14
- groupLabel: z.string().min(1, "Group label is required").max(200),
15
- pageKey: z.string().min(1, "Page key is required").max(100),
16
- pageLabel: z.string().min(1, "Page label is required").max(200),
17
- label: z.string().min(3, "Label must be at least 3 characters").max(500),
18
- }).passthrough();
15
+ import { checklistItemFormSchema } from "../../tester/schemas/checklist-item-form";
19
16
  const __P = {
20
17
  p4: "p-[var(--appkit-space-4)]",
21
18
  };
22
19
  const __O = {
23
20
  yAuto: "overflow-y-auto",
24
21
  };
22
+ const EMPTY_FORM = {
23
+ label: "",
24
+ description: "",
25
+ href: "",
26
+ groupLabel: "",
27
+ groupKey: "",
28
+ pageLabel: "",
29
+ pageKey: "",
30
+ order: 0,
31
+ phase: 1,
32
+ isActive: true,
33
+ adminOnly: false,
34
+ };
25
35
  function slugifyKey(str) {
26
36
  return str
27
37
  .toLowerCase()
@@ -31,24 +41,16 @@ function slugifyKey(str) {
31
41
  }
32
42
  export function AdminTesterChecklistItemEditorView({ itemId, onSaved, onDeleted, embedded, ...rest }) {
33
43
  const isEdit = Boolean(itemId);
34
- const [groupKey, setGroupKey] = React.useState("");
35
- const [groupLabel, setGroupLabel] = React.useState("");
36
- const [pageKey, setPageKey] = React.useState("");
37
- const [pageLabel, setPageLabel] = React.useState("");
38
- const [label, setLabel] = React.useState("");
39
- const [description, setDescription] = React.useState("");
40
- const [href, setHref] = React.useState("");
41
- const [order, setOrder] = React.useState(0);
42
- const [phase, setPhase] = React.useState(1);
43
- const [isActive, setIsActive] = React.useState(true);
44
- const [adminOnly, setAdminOnly] = React.useState(false);
44
+ const [form, setForm] = React.useState(EMPTY_FORM);
45
45
  const [deleteConfirmOpen, setDeleteConfirmOpen] = React.useState(false);
46
+ const patch = (partial) => setForm((prev) => Object.assign({}, prev, partial));
46
47
  const { showToast } = useToast();
47
48
  const itemQuery = useQuery({
48
49
  queryKey: ["admin", "tester-checklist-items", itemId],
49
50
  queryFn: async () => {
50
51
  const res = await apiClient.get(ADMIN_ENDPOINTS.TESTER_CHECKLIST_ITEM_BY_ID(itemId));
51
- return res?.data ?? res;
52
+ return (res?.data ??
53
+ res);
52
54
  },
53
55
  enabled: isEdit,
54
56
  });
@@ -56,43 +58,37 @@ export function AdminTesterChecklistItemEditorView({ itemId, onSaved, onDeleted,
56
58
  const item = itemQuery.data;
57
59
  if (!item)
58
60
  return;
59
- setGroupKey(item.groupKey ?? "");
60
- setGroupLabel(item.groupLabel ?? "");
61
- setPageKey(item.pageKey ?? "");
62
- setPageLabel(item.pageLabel ?? "");
63
- setLabel(item.label ?? "");
64
- setDescription(item.description ?? "");
65
- setHref(item.href ?? "");
66
- setOrder(typeof item.order === "number" ? item.order : 0);
67
- setPhase(typeof item.phase === "number" ? item.phase : 1);
68
- setIsActive(item.isActive ?? true);
69
- setAdminOnly(item.adminOnly ?? false);
61
+ patch({
62
+ label: item.label ?? "",
63
+ description: item.description ?? "",
64
+ href: item.href ?? "",
65
+ groupLabel: item.groupLabel ?? "",
66
+ groupKey: item.groupKey ?? "",
67
+ pageLabel: item.pageLabel ?? "",
68
+ pageKey: item.pageKey ?? "",
69
+ order: typeof item.order === "number" ? item.order : 0,
70
+ phase: typeof item.phase === "number" ? item.phase : 1,
71
+ isActive: item.isActive ?? true,
72
+ adminOnly: item.adminOnly ?? false,
73
+ });
74
+ // eslint-disable-next-line react-hooks/exhaustive-deps
70
75
  }, [itemQuery.data]);
71
- const handleGroupLabelChange = (value) => {
72
- setGroupLabel(value);
73
- if (!isEdit)
74
- setGroupKey(slugifyKey(value));
75
- };
76
- const handlePageLabelChange = (value) => {
77
- setPageLabel(value);
78
- if (!isEdit)
79
- setPageKey(slugifyKey(value));
80
- };
81
76
  const saveMutation = useApiMutation({
82
77
  errorMessage: "Failed to save checklist item.",
83
78
  mutationFn: async () => {
79
+ const draft = visibleValues(checklistItemFormSchema, form);
84
80
  const payload = {
85
- groupKey: groupKey || slugifyKey(groupLabel),
86
- groupLabel,
87
- pageKey: pageKey || slugifyKey(pageLabel),
88
- pageLabel,
89
- label,
90
- description: description || "",
91
- href: href || "",
92
- order,
93
- phase,
94
- isActive,
95
- adminOnly,
81
+ groupKey: draft.groupKey,
82
+ groupLabel: draft.groupLabel,
83
+ pageKey: draft.pageKey,
84
+ pageLabel: draft.pageLabel,
85
+ label: draft.label,
86
+ description: draft.description,
87
+ href: draft.href,
88
+ order: draft.order,
89
+ phase: draft.phase,
90
+ isActive: draft.isActive,
91
+ adminOnly: draft.adminOnly,
96
92
  };
97
93
  if (isEdit) {
98
94
  return apiClient.put(ADMIN_ENDPOINTS.TESTER_CHECKLIST_ITEM_BY_ID(itemId), payload);
@@ -100,7 +96,8 @@ export function AdminTesterChecklistItemEditorView({ itemId, onSaved, onDeleted,
100
96
  return apiClient.post(ADMIN_ENDPOINTS.TESTER_CHECKLIST_ITEMS, payload);
101
97
  },
102
98
  onSuccess: (res) => {
103
- const id = res?.data?.id ?? res?.id ?? itemId;
99
+ const created = res?.data?.id;
100
+ const id = itemId ?? created;
104
101
  showToast(isEdit ? "Checklist item updated." : "Checklist item created.", "success");
105
102
  if (onSaved && id)
106
103
  onSaved(id);
@@ -116,16 +113,49 @@ export function AdminTesterChecklistItemEditorView({ itemId, onSaved, onDeleted,
116
113
  },
117
114
  });
118
115
  const isSubmitting = saveMutation.isPending || itemQuery.isLoading;
119
- const canSave = Boolean(groupLabel.trim()) && Boolean(pageLabel.trim()) && Boolean(label.trim());
120
- const formSection = (_jsxs(_Fragment, { children: [_jsx(Form, { schema: checklistItemFormSchema, onSubmit: (e) => e.preventDefault(), spacing: "md", children: ({ setFieldError, clearErrors }) => (_jsxs(_Fragment, { children: [_jsxs(Div, { layout: "grid", gap: "4", className: "grid-cols-2", children: [_jsx(FieldInput, { name: "groupLabel", label: "Group", value: groupLabel, onChange: handleGroupLabelChange, required: true, placeholder: "e.g. Buying", hint: "Top-level accordion section on the Tester Hub." }), _jsx(Input, { label: "Group key", value: groupKey, onChange: (e) => setGroupKey(e.target.value), placeholder: "buying", helperText: "Auto-generated from the group name." })] }), _jsxs(Div, { layout: "grid", gap: "4", className: "grid-cols-2", children: [_jsx(FieldInput, { name: "pageLabel", label: "Page", value: pageLabel, onChange: handlePageLabelChange, required: true, placeholder: "e.g. Checkout", hint: "Sub-accordion within the group." }), _jsx(Input, { label: "Page key", value: pageKey, onChange: (e) => setPageKey(e.target.value), placeholder: "checkout", helperText: "Auto-generated from the page name." })] }), _jsx(FieldInput, { name: "label", label: "Test case (Yes/No question)", value: label, onChange: setLabel, required: true, placeholder: "e.g. Coupon discount is correctly reflected in the order total" }), _jsx(FieldTextarea, { name: "description", label: "Description (optional)", value: description, onChange: setDescription, placeholder: "Extra context for the tester." }), _jsx(FieldInput, { name: "href", label: "Deep link (optional)", value: href, onChange: setHref, placeholder: "/cart", hint: "Jumps the tester straight to the feature being tested." }), _jsxs(Div, { layout: "grid", gap: "4", className: "grid-cols-2", children: [_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 the page." }), _jsx(Input, { label: "Phase", value: String(phase), onChange: (e) => setPhase(Math.max(1, parseInt(e.target.value, 10) || 1)), type: "number", min: 1, helperText: "Test batch this case belongs to \u2014 testers work through one phase at a time." })] }), _jsxs(Stack, { className: `${__P.p4}`, gap: "3", rounded: "lg", border: "default", children: [_jsx(Text, { size: "sm", weight: "medium", color: "muted", children: "Visibility" }), _jsx(Toggle, { label: "Active (visible to testers)", checked: isActive, onChange: setIsActive }), _jsx(Toggle, { label: "Admin-only (requires canTestAdmin)", checked: adminOnly, onChange: setAdminOnly })] }), _jsx(FormErrorSummary, {}), _jsxs(Row, { gap: "3", padding: "t-xs", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !canSave || isSubmitting, onClick: () => {
121
- clearErrors();
122
- if (!label.trim()) {
123
- setFieldError("label", "Test case label is required");
124
- return;
125
- }
126
- saveMutation.mutate();
127
- }, children: isEdit ? "Save changes" : "Create checklist item" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => setDeleteConfirmOpen(true), children: "Delete" }))] })] })) }, "tester-checklist-item-form"), deleteConfirmOpen && (_jsx(ConfirmDeleteModal, { isOpen: true, title: ACTIONS.ADMIN["delete-checklist-item"].confirmation?.title ?? "Delete checklist item", message: ACTIONS.ADMIN["delete-checklist-item"].confirmation?.body ??
128
- "Delete this checklist item? This cannot be undone.", onConfirm: () => { deleteMutation.mutate(); setDeleteConfirmOpen(false); }, onClose: () => setDeleteConfirmOpen(false), isDeleting: deleteMutation.isPending }))] }));
116
+ const sections = React.useMemo(() => buildSectionsFromSchema(checklistItemFormSchema, {
117
+ renderers: {
118
+ /*
119
+ * The two keys stay editable, and typing a LABEL fills the matching
120
+ * key until the item exists — after that a key is what responses are
121
+ * grouped by, so an edit would orphan them.
122
+ */
123
+ groupLabel: ({ values, onChange, errors }) => (_jsx(FieldInput, { name: "groupLabel", label: "Group", required: true, hint: "Top-level accordion section on the Tester Hub.", value: values.groupLabel, error: errors.groupLabel, onChange: (v) => onChange(isEdit
124
+ ? { groupLabel: v }
125
+ : { groupLabel: v, groupKey: slugifyKey(v) }) })),
126
+ pageLabel: ({ values, onChange, errors }) => (_jsx(FieldInput, { name: "pageLabel", label: "Page", required: true, hint: "Sub-accordion within the group.", value: values.pageLabel, error: errors.pageLabel, onChange: (v) => onChange(isEdit
127
+ ? { pageLabel: v }
128
+ : { pageLabel: v, pageKey: slugifyKey(v) }) })),
129
+ },
130
+ }), [isEdit]);
131
+ const nav = useSectionFormNav(sections, form, {
132
+ scope: "admin:tester-checklist-item-editor",
133
+ });
134
+ const { shellCtx, setFieldError, clearErrors } = useFormShellState(checklistItemFormSchema, {
135
+ sections: nav.sectionMeta,
136
+ onGoToSection: nav.goToSection,
137
+ fieldToSectionIndex: nav.fieldToSectionIndex,
138
+ });
139
+ const onSubmit = () => {
140
+ clearErrors();
141
+ const parsed = checklistItemFormSchema.safeParse(visibleValues(checklistItemFormSchema, form));
142
+ if (!parsed.success) {
143
+ applyZodIssues(parsed.error.issues, setFieldError);
144
+ return;
145
+ }
146
+ saveMutation.mutate();
147
+ };
148
+ const formSection = (_jsxs(_Fragment, { children: [_jsxs(FormShellContext.Provider, { value: shellCtx, children: [_jsx(FormErrorSummary, {}), _jsx(SectionForm, { sections: sections, values: form, onChange: patch, onSubmit: onSubmit, schema: checklistItemFormSchema, openIds: nav.openIds, onOpenChange: nav.setOpenIds, isLoading: isSubmitting, submitLabel: isEdit ? "Save changes" : "Create checklist item", destructiveAction: isEdit
149
+ ? {
150
+ label: "Delete checklist item",
151
+ onClick: () => setDeleteConfirmOpen(true),
152
+ }
153
+ : undefined })] }), deleteConfirmOpen && (_jsx(ConfirmDeleteModal, { isOpen: true, title: ACTIONS.ADMIN["delete-checklist-item"].confirmation?.title ??
154
+ "Delete checklist item", message: ACTIONS.ADMIN["delete-checklist-item"].confirmation?.body ??
155
+ "Delete this checklist item? This cannot be undone.", onConfirm: () => {
156
+ deleteMutation.mutate();
157
+ setDeleteConfirmOpen(false);
158
+ }, onClose: () => setDeleteConfirmOpen(false), isDeleting: deleteMutation.isPending }))] }));
129
159
  if (embedded) {
130
160
  return _jsx(Div, { className: `${__O.yAuto} ${__P.p4}`, children: formSection });
131
161
  }
@@ -1,3 +1,13 @@
1
+ /**
2
+ * The "+ Create Brand" drawer behind every brand `PaginatedSelect`.
3
+ *
4
+ * Fields come from `quickCreateTaxonomySchema`'s annotations — the same schema
5
+ * `CategoryQuickCreateForm` derives from, since both drawers post
6
+ * `{ name, description, isActive }` and differ only in endpoint and slug prefix.
7
+ *
8
+ * `slug` is deliberately not a field: it is derived from the name here and
9
+ * treated as create-only everywhere else in this codebase (Root Cause #39).
10
+ */
1
11
  import React from "react";
2
12
  export interface BrandQuickCreateFormProps {
3
13
  onSaved: (id: string, name: string) => void;
@@ -1,43 +1,66 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { Row } from "@mohasinac/appkit/ui";
4
- import { useApiMutation } from "@mohasinac/appkit/client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * The "+ Create Brand" drawer behind every brand `PaginatedSelect`.
5
+ *
6
+ * Fields come from `quickCreateTaxonomySchema`'s annotations — the same schema
7
+ * `CategoryQuickCreateForm` derives from, since both drawers post
8
+ * `{ name, description, isActive }` and differ only in endpoint and slug prefix.
9
+ *
10
+ * `slug` is deliberately not a field: it is derived from the name here and
11
+ * treated as create-only everywhere else in this codebase (Root Cause #39).
12
+ */
5
13
  import React from "react";
6
- import { Button, Form, Input, Toggle, useToast } from "../../../ui";
7
- import { apiClient } from "../../../http";
14
+ import { useApiMutation } from "@mohasinac/appkit/client";
8
15
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
9
- import { quickCreateTaxonomySchema } from "../schemas/small-forms";
10
- import { FormErrorSummary } from "../../../ui/forms/FormErrorSummary";
16
+ import { apiClient } from "../../../http";
11
17
  import { applyZodIssues } from "../../../ui/forms/apply-zod-issues";
18
+ import { FormErrorSummary } from "../../../ui/forms/FormErrorSummary";
19
+ import { FormShellContext, useFormShellState } from "../../../ui/forms/FormShell";
20
+ import { buildSectionsFromSchema } from "../../shell/build-sections";
21
+ import { SectionForm, useSectionFormNav } from "../../shell/SectionForm";
22
+ import { quickCreateTaxonomySchema } from "../schemas/small-forms";
23
+ const EMPTY = { name: "", description: "", isActive: true };
12
24
  function toBrandSlug(str) {
13
- const base = str.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
25
+ const base = str
26
+ .toLowerCase()
27
+ .trim()
28
+ .replace(/[^a-z0-9]+/g, "-")
29
+ .replace(/^-+|-+$/g, "");
14
30
  return base.startsWith("brand-") ? base : `brand-${base}`;
15
31
  }
16
32
  export function BrandQuickCreateForm({ onSaved, onCancel }) {
17
- const [name, setName] = React.useState("");
18
- const [description, setDescription] = React.useState("");
19
- const [isActive, setIsActive] = React.useState(true);
20
- const { showToast } = useToast();
33
+ const [form, setForm] = React.useState(EMPTY);
34
+ const sections = React.useMemo(() => buildSectionsFromSchema(quickCreateTaxonomySchema), []);
35
+ const nav = useSectionFormNav(sections, form, { scope: "admin:brand-quick-create" });
36
+ const { shellCtx, setFieldError, clearErrors } = useFormShellState(quickCreateTaxonomySchema, {
37
+ sections: nav.sectionMeta,
38
+ onGoToSection: nav.goToSection,
39
+ fieldToSectionIndex: nav.fieldToSectionIndex,
40
+ });
21
41
  const mutation = useApiMutation({
42
+ // Authored copy goes here, never a toast in `onError` — the mutation
43
+ // already owns exactly one failure surface (audit-usemutation-onerror).
22
44
  errorMessage: "Failed to create brand.",
23
45
  mutationFn: async () => apiClient.post(ADMIN_ENDPOINTS.BRANDS, {
24
- name,
25
- slug: toBrandSlug(name),
26
- description: description || undefined,
27
- isActive,
46
+ name: form.name,
47
+ slug: toBrandSlug(form.name),
48
+ description: form.description || undefined,
49
+ isActive: form.isActive,
28
50
  }),
29
51
  onSuccess: (res) => {
30
52
  const id = res?.data?.id ?? res?.id ?? "";
31
- onSaved(id, name);
53
+ onSaved(id, form.name);
32
54
  },
33
55
  });
34
- return (_jsx(Form, { schema: quickCreateTaxonomySchema, onSubmit: (e) => e.preventDefault(), spacing: "md", children: ({ setFieldError, clearErrors }) => (_jsxs(_Fragment, { children: [_jsx(FormErrorSummary, {}), _jsx(Input, { label: "Brand name", value: name, onChange: (e) => setName(e.target.value), required: true, placeholder: "e.g. Hot Wheels", autoFocus: true }), _jsx(Input, { label: "Description", value: description, onChange: (e) => setDescription(e.target.value), placeholder: "Optional brief description" }), _jsx(Toggle, { label: "Active", checked: isActive, onChange: setIsActive }), _jsxs(Row, { gap: "3", padding: "t-xs", children: [_jsx(Button, { type: "submit", isLoading: mutation.isPending, disabled: mutation.isPending, onClick: () => {
35
- clearErrors();
36
- const parsed = quickCreateTaxonomySchema.safeParse({ name, description, isActive });
37
- if (!parsed.success) {
38
- applyZodIssues(parsed.error.issues, setFieldError);
39
- return;
40
- }
41
- mutation.mutate();
42
- }, children: "Create brand" }), _jsx(Button, { type: "button", variant: "ghost", onClick: onCancel, children: "Cancel" })] })] })) }));
56
+ const onSubmit = () => {
57
+ clearErrors();
58
+ const parsed = quickCreateTaxonomySchema.safeParse(form);
59
+ if (!parsed.success) {
60
+ applyZodIssues(parsed.error.issues, setFieldError);
61
+ return;
62
+ }
63
+ mutation.mutate();
64
+ };
65
+ return (_jsxs(FormShellContext.Provider, { value: shellCtx, children: [_jsx(FormErrorSummary, {}), _jsx(SectionForm, { sections: sections, values: form, onChange: (partial) => setForm((prev) => Object.assign({}, prev, partial)), onSubmit: onSubmit, schema: quickCreateTaxonomySchema, openIds: nav.openIds, onOpenChange: nav.setOpenIds, isLoading: mutation.isPending, submitLabel: "Create brand", onCancel: onCancel, cancelLabel: "Cancel" })] }));
43
66
  }
@@ -1,3 +1,14 @@
1
+ /**
2
+ * The "+ Create Category" drawer behind every category `PaginatedSelect`.
3
+ *
4
+ * Twin of `BrandQuickCreateForm` and deliberately kept as two files: they share
5
+ * a schema but differ in endpoint, slug prefix and copy, which is exactly two
6
+ * copies with different domain semantics — the Duplication Decision Framework
7
+ * says extract on the third, not the second.
8
+ *
9
+ * `slug` is not a field: derived from the name here, create-only everywhere
10
+ * else in this codebase (Root Cause #39).
11
+ */
1
12
  import React from "react";
2
13
  export interface CategoryQuickCreateFormProps {
3
14
  onSaved: (id: string, name: string) => void;
@@ -1,42 +1,64 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { Row } from "@mohasinac/appkit/ui";
4
- import { useApiMutation } from "@mohasinac/appkit/client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * The "+ Create Category" drawer behind every category `PaginatedSelect`.
5
+ *
6
+ * Twin of `BrandQuickCreateForm` and deliberately kept as two files: they share
7
+ * a schema but differ in endpoint, slug prefix and copy, which is exactly two
8
+ * copies with different domain semantics — the Duplication Decision Framework
9
+ * says extract on the third, not the second.
10
+ *
11
+ * `slug` is not a field: derived from the name here, create-only everywhere
12
+ * else in this codebase (Root Cause #39).
13
+ */
5
14
  import React from "react";
6
- import { Button, Form, Input, Toggle, useToast } from "../../../ui";
7
- import { apiClient } from "../../../http";
15
+ import { useApiMutation } from "@mohasinac/appkit/client";
8
16
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
9
- import { quickCreateTaxonomySchema } from "../schemas/small-forms";
10
- import { FormErrorSummary } from "../../../ui/forms/FormErrorSummary";
17
+ import { apiClient } from "../../../http";
11
18
  import { applyZodIssues } from "../../../ui/forms/apply-zod-issues";
19
+ import { FormErrorSummary } from "../../../ui/forms/FormErrorSummary";
20
+ import { FormShellContext, useFormShellState } from "../../../ui/forms/FormShell";
21
+ import { buildSectionsFromSchema } from "../../shell/build-sections";
22
+ import { SectionForm, useSectionFormNav } from "../../shell/SectionForm";
23
+ import { quickCreateTaxonomySchema } from "../schemas/small-forms";
24
+ const EMPTY = { name: "", description: "", isActive: true };
12
25
  function toCategorySlug(str) {
13
- return str.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
26
+ return str
27
+ .toLowerCase()
28
+ .trim()
29
+ .replace(/[^a-z0-9]+/g, "-")
30
+ .replace(/^-+|-+$/g, "");
14
31
  }
15
32
  export function CategoryQuickCreateForm({ onSaved, onCancel }) {
16
- const [name, setName] = React.useState("");
17
- const [description, setDescription] = React.useState("");
18
- const [isActive, setIsActive] = React.useState(true);
19
- const { showToast } = useToast();
33
+ const [form, setForm] = React.useState(EMPTY);
34
+ const sections = React.useMemo(() => buildSectionsFromSchema(quickCreateTaxonomySchema), []);
35
+ const nav = useSectionFormNav(sections, form, { scope: "admin:category-quick-create" });
36
+ const { shellCtx, setFieldError, clearErrors } = useFormShellState(quickCreateTaxonomySchema, {
37
+ sections: nav.sectionMeta,
38
+ onGoToSection: nav.goToSection,
39
+ fieldToSectionIndex: nav.fieldToSectionIndex,
40
+ });
20
41
  const mutation = useApiMutation({
21
42
  errorMessage: "Failed to create category.",
22
43
  mutationFn: async () => apiClient.post(ADMIN_ENDPOINTS.CATEGORIES, {
23
- name,
24
- slug: toCategorySlug(name),
25
- description: description || undefined,
26
- isActive,
44
+ name: form.name,
45
+ slug: toCategorySlug(form.name),
46
+ description: form.description || undefined,
47
+ isActive: form.isActive,
27
48
  }),
28
49
  onSuccess: (res) => {
29
50
  const id = res?.data?.id ?? res?.id ?? "";
30
- onSaved(id, name);
51
+ onSaved(id, form.name);
31
52
  },
32
53
  });
33
- return (_jsx(Form, { schema: quickCreateTaxonomySchema, onSubmit: (e) => e.preventDefault(), spacing: "md", children: ({ setFieldError, clearErrors }) => (_jsxs(_Fragment, { children: [_jsx(FormErrorSummary, {}), _jsx(Input, { label: "Category name", value: name, onChange: (e) => setName(e.target.value), required: true, placeholder: "e.g. Trading Cards", autoFocus: true }), _jsx(Input, { label: "Description", value: description, onChange: (e) => setDescription(e.target.value), placeholder: "Optional brief description" }), _jsx(Toggle, { label: "Active", checked: isActive, onChange: setIsActive }), _jsxs(Row, { gap: "3", padding: "t-xs", children: [_jsx(Button, { type: "submit", isLoading: mutation.isPending, disabled: mutation.isPending, onClick: () => {
34
- clearErrors();
35
- const parsed = quickCreateTaxonomySchema.safeParse({ name, description, isActive });
36
- if (!parsed.success) {
37
- applyZodIssues(parsed.error.issues, setFieldError);
38
- return;
39
- }
40
- mutation.mutate();
41
- }, children: "Create category" }), _jsx(Button, { type: "button", variant: "ghost", onClick: onCancel, children: "Cancel" })] })] })) }));
54
+ const onSubmit = () => {
55
+ clearErrors();
56
+ const parsed = quickCreateTaxonomySchema.safeParse(form);
57
+ if (!parsed.success) {
58
+ applyZodIssues(parsed.error.issues, setFieldError);
59
+ return;
60
+ }
61
+ mutation.mutate();
62
+ };
63
+ return (_jsxs(FormShellContext.Provider, { value: shellCtx, children: [_jsx(FormErrorSummary, {}), _jsx(SectionForm, { sections: sections, values: form, onChange: (partial) => setForm((prev) => Object.assign({}, prev, partial)), onSubmit: onSubmit, schema: quickCreateTaxonomySchema, openIds: nav.openIds, onOpenChange: nav.setOpenIds, isLoading: mutation.isPending, submitLabel: "Create category", onCancel: onCancel, cancelLabel: "Cancel" })] }));
42
64
  }
@@ -115,6 +115,8 @@ export { AdminSessionsManager } from "./AdminSessionsManager";
115
115
  export type { AdminSessionsManagerProps } from "./AdminSessionsManager";
116
116
  export { AdminNavigationView } from "./AdminNavigationView";
117
117
  export type { AdminNavigationViewProps } from "./AdminNavigationView";
118
+ export { AdminActionIndexView } from "./AdminActionIndexView";
119
+ export type { AdminActionIndexViewProps } from "./AdminActionIndexView";
118
120
  export { AdminAdsView } from "./AdminAdsView";
119
121
  export type { AdminAdsViewProps, AdminAdItem, AdminAdProvider, AdminAdStatus } from "./AdminAdsView";
120
122
  export { AdminAdEditorView } from "./AdminAdEditorView";
@@ -144,8 +146,6 @@ export type { AdminRevenueChartProps, AdminOrdersChartProps, } from "./analytics
144
146
  export { AdminTopProductsTable } from "./analytics/AdminTopProductsTable";
145
147
  export type { AdminTopProductsTableProps, AdminTopProductsTableLabels, } from "./analytics/AdminTopProductsTable";
146
148
  export { AdminPageViewsReportView } from "./analytics/AdminPageViewsReportView";
147
- export { AdminFeatureFlagsView } from "./AdminFeatureFlagsView";
148
- export type { AdminFeatureFlagsViewProps } from "./AdminFeatureFlagsView";
149
149
  export { AdminNewsletterView } from "./AdminNewsletterView";
150
150
  export type { AdminNewsletterViewProps } from "./AdminNewsletterView";
151
151
  export { AdminContactView } from "./AdminContactView";
@@ -62,6 +62,7 @@ export { AdminReviewsView } from "./AdminReviewsView";
62
62
  export { AdminSectionsView } from "./AdminSectionsView";
63
63
  export { AdminSessionsManager } from "./AdminSessionsManager";
64
64
  export { AdminNavigationView } from "./AdminNavigationView";
65
+ export { AdminActionIndexView } from "./AdminActionIndexView";
65
66
  export { AdminAdsView } from "./AdminAdsView";
66
67
  export { AdminAdEditorView } from "./AdminAdEditorView";
67
68
  export { AdminCarouselView } from "./AdminCarouselView";
@@ -77,7 +78,6 @@ export { DrawerFormFooter } from "./DrawerFormFooter";
77
78
  export { AdminRevenueChart, AdminOrdersChart, } from "./analytics/AdminAnalyticsCharts";
78
79
  export { AdminTopProductsTable } from "./analytics/AdminTopProductsTable";
79
80
  export { AdminPageViewsReportView } from "./analytics/AdminPageViewsReportView";
80
- export { AdminFeatureFlagsView } from "./AdminFeatureFlagsView";
81
81
  export { AdminNewsletterView } from "./AdminNewsletterView";
82
82
  export { AdminContactView } from "./AdminContactView";
83
83
  export { AdminContactEditorView } from "./AdminContactEditorView";