@mohasinac/appkit 4.30.19 → 4.31.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 (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 +1 -2
  313. package/dist/next/index.js +0 -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,21 +1,47 @@
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";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * AdminAddressEditorView — on the shared address shape, 2026-08-30 (W5 / D19).
5
+ *
6
+ * ## What it was
7
+ *
8
+ * `adminAddressFormSchema`, a twelfth restatement of the same eleven fields,
9
+ * with `postalCode: /^\d{6}$/` — India-only, on a form whose `country` was a
10
+ * free-text box. It was the ONLY one of the three address surfaces that used
11
+ * `INDIAN_STATES`; the other two shipped free text into the same
12
+ * `AddressDocument.state`, so the field held "Karnataka", "karnataka" and "KA"
13
+ * depending on which surface created the row.
14
+ *
15
+ * ## `canSave` is gone, and its last clause is why
16
+ *
17
+ * `form.postalCode.length === 6` — a LENGTH check, so `"abcdef"` satisfied it,
18
+ * and any non-Indian address could never be saved from this screen at all.
19
+ * The schema now decides, per country, and reports on the field.
20
+ */
4
21
  import { useApiMutation } from "@mohasinac/appkit/client";
5
22
  import React from "react";
6
23
  import { useQuery } from "@tanstack/react-query";
7
- import { Button, Card, CardBody, Checkbox, ConfirmDeleteModal, Div, Form, Input, Select, Span, Stack, StackedViewShell, Text, Toggle, useToast, Show, StickyToolbar } from "../../../ui";
24
+ import { ConfirmDeleteModal, Stack, StackedViewShell, useToast, } from "../../../ui";
25
+ import { FieldInput, FormErrorSummary } from "../../../ui/forms";
26
+ import { FormShellContext, useFormShellState } from "../../../ui/forms/FormShell";
27
+ import { applyZodIssues } from "../../../ui/forms/apply-zod-issues";
28
+ import { buildSectionsFromSchema, visibleValues } from "../../shell/build-sections";
29
+ import { SectionForm, useSectionFormNav } from "../../shell/SectionForm";
8
30
  import { apiClient } from "../../../http";
9
31
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
10
32
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
11
- import { INDIAN_STATES } from "../../account/constants/addresses";
12
- import { adminAddressFormSchema } from "../schemas/admin-editor-forms";
13
- import { FormErrorSummary } from "../../../ui/forms/FormErrorSummary";
14
- const STATE_OPTIONS = INDIAN_STATES.map((s) => ({ value: s, label: s }));
15
- // ── Section heading helper ─────────────────────────────────────────────────────
16
- function SectionHeading({ children }) {
17
- return (_jsx(Text, { className: "tracking-widest mb-4", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: children }));
18
- }
33
+ import { adminAddressCreateSchema } from "../../addresses/schemas/address-form";
34
+ import { AddressLocationFields } from "../../addresses/components/AddressLocationFields";
35
+ import { usePostalLookup } from "../../addresses/hooks/usePostalLookup";
36
+ import { COUNTRIES, DEFAULT_COUNTRY } from "../../../constants/geo/countries";
37
+ const COUNTRY_OPTIONS = Object.values(COUNTRIES).map((c) => ({
38
+ value: c.code,
39
+ label: c.name,
40
+ }));
41
+ const OWNER_TYPE_OPTIONS = [
42
+ { value: "user", label: "User" },
43
+ { value: "store", label: "Store" },
44
+ ];
19
45
  const EMPTY = {
20
46
  ownerType: "user",
21
47
  ownerId: "",
@@ -28,7 +54,7 @@ const EMPTY = {
28
54
  city: "",
29
55
  state: "",
30
56
  postalCode: "",
31
- country: "India",
57
+ country: DEFAULT_COUNTRY,
32
58
  isDefault: false,
33
59
  };
34
60
  export function AdminAddressEditorView({ addressId, onSaved, onDeleted, ...rest }) {
@@ -36,40 +62,36 @@ export function AdminAddressEditorView({ addressId, onSaved, onDeleted, ...rest
36
62
  const [deleteOpen, setDeleteOpen] = React.useState(false);
37
63
  const { showToast } = useToast();
38
64
  const [form, setForm] = React.useState(EMPTY);
39
- const set = (key, value) => setForm((prev) => ({ ...prev, [key]: value }));
65
+ const patch = (partial) => setForm((prev) => Object.assign({}, prev, partial));
40
66
  const { isLoading } = useQuery({
41
67
  queryKey: ["admin", "address", addressId],
42
68
  queryFn: async () => {
43
69
  const res = await apiClient.get(ADMIN_ENDPOINTS.ADDRESS_BY_ID(addressId));
44
- return (res?.data ?? res);
70
+ return (res?.data ??
71
+ res);
45
72
  },
46
73
  enabled: isEdit,
47
74
  select: (data) => {
48
- setForm({
49
- ownerType: data.ownerType ?? "user",
50
- ownerId: data.ownerId ?? "",
51
- label: data.label ?? "",
52
- fullName: data.fullName ?? "",
53
- phone: data.phone ?? "",
54
- addressLine1: data.addressLine1 ?? "",
55
- addressLine2: data.addressLine2 ?? "",
56
- landmark: data.landmark ?? "",
57
- city: data.city ?? "",
58
- state: data.state ?? "",
59
- postalCode: data.postalCode ?? "",
60
- country: data.country ?? "India",
61
- isDefault: data.isDefault ?? false,
62
- });
75
+ patch({ ...EMPTY, ...data, country: data.country || DEFAULT_COUNTRY });
63
76
  return data;
64
77
  },
65
78
  });
79
+ const { lookup, isLooking } = usePostalLookup({
80
+ // Empty fields only — never correct what the admin typed.
81
+ onResolved: ({ city, state }) => setForm((prev) => ({
82
+ ...prev,
83
+ city: prev.city.trim() ? prev.city : city,
84
+ state: prev.state.trim() ? prev.state : state,
85
+ })),
86
+ });
66
87
  const saveMutation = useApiMutation({
67
88
  errorMessage: "Failed to save address.",
68
89
  mutationFn: async () => {
90
+ const draft = visibleValues(adminAddressCreateSchema, form);
69
91
  const payload = {
70
- ...form,
71
- addressLine2: form.addressLine2 || undefined,
72
- landmark: form.landmark || undefined,
92
+ ...draft,
93
+ addressLine2: draft.addressLine2 || undefined,
94
+ landmark: draft.landmark || undefined,
73
95
  };
74
96
  if (isEdit) {
75
97
  return apiClient.patch(ADMIN_ENDPOINTS.ADDRESS_BY_ID(addressId), payload);
@@ -77,7 +99,8 @@ export function AdminAddressEditorView({ addressId, onSaved, onDeleted, ...rest
77
99
  return apiClient.post(ADMIN_ENDPOINTS.ADDRESSES, payload);
78
100
  },
79
101
  onSuccess: (res) => {
80
- const id = res?.data?.id ?? res?.id ?? addressId;
102
+ const created = res?.data?.id;
103
+ const id = addressId ?? created;
81
104
  showToast(isEdit ? "Address updated." : "Address created.", "success");
82
105
  if (onSaved && id)
83
106
  onSaved(String(id));
@@ -94,26 +117,45 @@ export function AdminAddressEditorView({ addressId, onSaved, onDeleted, ...rest
94
117
  },
95
118
  });
96
119
  const isSubmitting = saveMutation.isPending || isLoading;
97
- const canSave = form.ownerId &&
98
- form.label &&
99
- form.fullName &&
100
- form.phone &&
101
- form.addressLine1 &&
102
- form.city &&
103
- form.state &&
104
- form.postalCode.length === 6;
105
- // ── Action sidebar (desktop) ───────────────────────────────────────────────
106
- const actionSidebar = (_jsxs(Card, { variant: "outlined", padding: "md", spacing: "sm", children: [_jsx(Button, { type: "submit", form: "address-editor-form", className: "w-full", isLoading: isSubmitting, disabled: !canSave || isSubmitting, children: isEdit ? ACTIONS.ADMIN["save-changes"].label : "Create address" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", className: "w-full", isLoading: deleteMutation.isPending, onClick: () => setDeleteOpen(true), children: "Delete address" }))] }));
107
- // ── Form sections ──────────────────────────────────────────────────────────
108
- const formContent = (_jsxs(Form, { schema: adminAddressFormSchema, id: "address-editor-form", onSubmit: (e) => {
109
- e.preventDefault();
110
- saveMutation.mutate();
111
- }, spacing: "lg", children: [_jsx(FormErrorSummary, {}), _jsxs(Card, { variant: "outlined", padding: "lg", children: [_jsx(SectionHeading, { children: "Ownership" }), _jsxs(Stack, { gap: "md", children: [_jsx(Row, { gap: "lg", children: ["user", "store"].map((type) => (_jsxs("label", { className: "flex cursor-pointer items-center gap-[var(--appkit-space-2)]", children: [_jsx(Checkbox, { bare: true, type: "radio", name: "ownerType", value: type, checked: form.ownerType === type, onChange: () => {
112
- set("ownerType", type);
113
- set("ownerId", "");
114
- }, className: "accent-[var(--appkit-color-primary)]" }), _jsx(Span, { size: "sm", className: "text-[var(--appkit-color-text)]", transform: "capitalize", children: type })] }, type))) }), _jsx(Input, { label: form.ownerType === "user" ? "User ID" : "Store ID (slug)", value: form.ownerId, onChange: (e) => set("ownerId", e.target.value), required: true, placeholder: form.ownerType === "user" ? "user-mohsin-c" : "store-pokemon-palace", helperText: form.ownerType === "user"
115
- ? "Firebase Auth UID or user slug"
116
- : "Store slug (e.g. store-pokemon-palace)" })] })] }), _jsxs(Card, { variant: "outlined", padding: "lg", children: [_jsx(SectionHeading, { children: "Contact & Location" }), _jsxs(Stack, { gap: "md", children: [_jsxs(Div, { layout: "grid", gap: "4", className: "sm:grid-cols-2", children: [_jsx(Input, { label: "Label", value: form.label, onChange: (e) => set("label", e.target.value), required: true, placeholder: "Home / Office / Pickup" }), _jsx(Input, { label: "Full Name", value: form.fullName, onChange: (e) => set("fullName", e.target.value), required: true, placeholder: "Recipient name (PII)" })] }), _jsx(Input, { label: "Phone", value: form.phone, onChange: (e) => set("phone", e.target.value), required: true, type: "tel", placeholder: "+91 9876543210 (PII)" }), _jsx(Input, { label: "Address Line 1", value: form.addressLine1, onChange: (e) => set("addressLine1", e.target.value), required: true, placeholder: "House/flat no., street (PII)" }), _jsxs(Div, { layout: "grid", gap: "4", className: "sm:grid-cols-2", children: [_jsx(Input, { label: "Address Line 2", value: form.addressLine2 ?? "", onChange: (e) => set("addressLine2", e.target.value), placeholder: "Area, locality (optional)" }), _jsx(Input, { label: "Landmark", value: form.landmark ?? "", onChange: (e) => set("landmark", e.target.value), placeholder: "Near hospital, etc. (optional)" })] }), _jsxs(Div, { layout: "grid", gap: "4", className: "sm:grid-cols-3", children: [_jsx(Input, { label: "City", value: form.city, onChange: (e) => set("city", e.target.value), required: true, placeholder: "Mumbai" }), _jsx(Select, { label: "State", value: form.state, onValueChange: (val) => set("state", val), options: STATE_OPTIONS, placeholder: "Select state", required: true }), _jsx(Input, { label: "Postal Code", value: form.postalCode, onChange: (e) => set("postalCode", e.target.value), required: true, placeholder: "400001", maxLength: 6 })] }), _jsx(Input, { label: "Country", value: form.country, onChange: (e) => set("country", e.target.value), placeholder: "India" })] })] }), _jsxs(Card, { variant: "outlined", padding: "lg", children: [_jsx(SectionHeading, { children: "Flags" }), _jsx(Toggle, { label: "Set as default address", checked: form.isDefault, onChange: (v) => set("isDefault", v) })] }), _jsxs(Row, { gap: "3", className: "lg:hidden", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !canSave || isSubmitting, children: isEdit ? ACTIONS.ADMIN["save-changes"].label : "Create address" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => setDeleteOpen(true), children: "Delete address" }))] })] }, "address-form"));
117
- const twoPanel = (_jsxs(Div, { layout: "grid", gap: "6", lgAlign: "start", className: "lg:grid-cols-[1fr_280px]", children: [_jsx(CardBody, { className: "min-w-0 space-y-6 p-[var(--appkit-space-0)]", children: formContent }), _jsx(Show, { above: "lg", children: _jsx(StickyToolbar, { offset: "header", tone: "default", border: false, padding: "none", children: actionSidebar }) })] }));
118
- return (_jsxs(_Fragment, { children: [_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Address" : "New Address", sections: [twoPanel] }), _jsx(ConfirmDeleteModal, { isOpen: deleteOpen, onClose: () => setDeleteOpen(false), onConfirm: () => deleteMutation.mutate(), isDeleting: deleteMutation.isPending, title: "Delete this address?", message: "This address will be permanently removed. This action cannot be undone.", confirmText: "Delete address", variant: "danger" })] }));
120
+ const sections = React.useMemo(() => buildSectionsFromSchema(adminAddressCreateSchema, {
121
+ options: { ownerType: OWNER_TYPE_OPTIONS, country: COUNTRY_OPTIONS },
122
+ renderers: {
123
+ /*
124
+ * The id's LABEL depends on the owner type, which a generated field
125
+ * cannot know — and switching type clears it, because a user slug is
126
+ * not a store slug and carrying it over produces an address attached
127
+ * to nothing.
128
+ */
129
+ ownerId: ({ values, onChange, errors }) => (_jsx(FieldInput, { name: "ownerId", required: true, label: values.ownerType === "user" ? "User ID" : "Store ID (slug)", hint: values.ownerType === "user"
130
+ ? "Firebase Auth UID or user slug"
131
+ : "Store slug, e.g. store-beyblade-arena", placeholder: values.ownerType === "user" ? "user-mohsin-c" : "store-beyblade-arena", value: values.ownerId, error: errors.ownerId, onChange: (v) => onChange({ ownerId: v }) })),
132
+ state: ({ values, onChange, errors }) => (_jsx(AddressLocationFields, { country: values.country, state: values.state, postalCode: values.postalCode, errors: errors, isLooking: isLooking, onChange: onChange, onPostalSettled: lookup })),
133
+ postalCode: () => null,
134
+ country: () => null,
135
+ },
136
+ }), [isLooking, lookup]);
137
+ const nav = useSectionFormNav(sections, form, { scope: "admin:address-editor" });
138
+ const { shellCtx, setFieldError, clearErrors } = useFormShellState(adminAddressCreateSchema, {
139
+ sections: nav.sectionMeta,
140
+ onGoToSection: nav.goToSection,
141
+ fieldToSectionIndex: nav.fieldToSectionIndex,
142
+ });
143
+ const handleSubmit = () => {
144
+ clearErrors();
145
+ const parsed = adminAddressCreateSchema.safeParse(visibleValues(adminAddressCreateSchema, form));
146
+ if (!parsed.success) {
147
+ applyZodIssues(parsed.error.issues, setFieldError);
148
+ return;
149
+ }
150
+ saveMutation.mutate();
151
+ };
152
+ return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit address" : "New address", sections: [
153
+ _jsxs(Stack, { gap: "md", children: [_jsxs(FormShellContext.Provider, { value: shellCtx, children: [_jsx(FormErrorSummary, {}), _jsx(SectionForm, { sections: sections, values: form, onChange: patch, onSubmit: handleSubmit, schema: adminAddressCreateSchema, openIds: nav.openIds, onOpenChange: nav.setOpenIds, isLoading: isSubmitting, submitLabel: isEdit ? ACTIONS.ADMIN["save-changes"].label : "Create address", destructiveAction: isEdit
154
+ ? {
155
+ label: "Delete address",
156
+ onClick: () => setDeleteOpen(true),
157
+ disabled: deleteMutation.isPending,
158
+ }
159
+ : undefined })] }), deleteOpen && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete this address?", message: "This removes the address permanently. Orders already shipped to it keep their own copy.", onConfirm: () => deleteMutation.mutate(), onClose: () => setDeleteOpen(false), isDeleting: deleteMutation.isPending }))] }, "address-form"),
160
+ ] }));
119
161
  }
@@ -1,3 +1,18 @@
1
+ /**
2
+ * Create or edit a brand.
3
+ *
4
+ * Fields come from `brandFormSchema`, which used to be declared locally in this
5
+ * file, unannotated, and — the part that mattered — never executed: the submit
6
+ * handler checked `name.trim()` and called the mutation. So `website`'s URL rule
7
+ * had never rejected anything, and the raw `<Input>`s it would have reported on
8
+ * carry no `name`, which means `applyZodIssues` had nowhere to put an error even
9
+ * if the parse had run. Both halves are fixed by deriving the form from the
10
+ * schema: every field is a `Field*` with a name, and the parse gates the save.
11
+ *
12
+ * The submit button is no longer `disabled={!name}`. A disabled control with no
13
+ * explanation cannot tell the admin which field it is waiting on; the schema now
14
+ * says so, on the field.
15
+ */
1
16
  import React from "react";
2
17
  import type { StackedViewShellProps } from "../../../ui";
3
18
  export interface AdminBrandEditorViewProps extends Omit<StackedViewShellProps, "sections"> {
@@ -1,57 +1,70 @@
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
- import { useApiMutation } from "@mohasinac/appkit/client";
3
+ /**
4
+ * Create or edit a brand.
5
+ *
6
+ * Fields come from `brandFormSchema`, which used to be declared locally in this
7
+ * file, unannotated, and — the part that mattered — never executed: the submit
8
+ * handler checked `name.trim()` and called the mutation. So `website`'s URL rule
9
+ * had never rejected anything, and the raw `<Input>`s it would have reported on
10
+ * carry no `name`, which means `applyZodIssues` had nowhere to put an error even
11
+ * if the parse had run. Both halves are fixed by deriving the form from the
12
+ * schema: every field is a `Field*` with a name, and the parse gates the save.
13
+ *
14
+ * The submit button is no longer `disabled={!name}`. A disabled control with no
15
+ * explanation cannot tell the admin which field it is waiting on; the schema now
16
+ * says so, on the field.
17
+ */
5
18
  import React from "react";
6
19
  import { useQuery } from "@tanstack/react-query";
7
- import { z } from "zod";
8
- import { mediaUrlSchema } from "../../../validation/schemas";
9
- import { Button, ConfirmDeleteModal, Div, Form, Input, StackedViewShell, Toggle, useToast, } from "../../../ui";
10
- import { FieldInput, FormErrorSummary } from "../../../ui/forms";
11
- import { ImageUpload } from "../../media/upload/ImageUpload";
12
- import { useMediaUpload } from "../../media";
13
- import { apiClient } from "../../../http";
20
+ import { useApiMutation } from "@mohasinac/appkit/client";
14
21
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
15
- const brandFormSchema = z.object({
16
- name: z.string().min(1, "Brand name is required").max(120),
17
- slug: z.string().regex(/^[a-z0-9-]+$/i).optional().or(z.literal("")),
18
- description: z.string().max(2000).optional().or(z.literal("")),
19
- logoURL: mediaUrlSchema.optional().or(z.literal("")),
20
- website: z.string().url().optional().or(z.literal("")),
21
- country: z.string().max(80).optional().or(z.literal("")),
22
- founded: z.number().int().min(1800).max(new Date().getFullYear()).optional(),
23
- isActive: z.boolean(),
24
- displayOrder: z.number().int().min(0).optional(),
25
- });
26
- const __P = {
27
- p4: "p-[var(--appkit-space-4)]",
28
- };
29
- const __O = {
30
- yAuto: "overflow-y-auto",
22
+ import { apiClient } from "../../../http";
23
+ import { ConfirmDeleteModal, Div, StackedViewShell, useToast } from "../../../ui";
24
+ import { applyZodIssues } from "../../../ui/forms/apply-zod-issues";
25
+ import { FormErrorSummary } from "../../../ui/forms/FormErrorSummary";
26
+ import { FormShellContext, useFormShellState } from "../../../ui/forms/FormShell";
27
+ import { buildSectionsFromSchema } from "../../shell/build-sections";
28
+ import { SectionForm, useSectionFormNav } from "../../shell/SectionForm";
29
+ import { useMediaUpload } from "../../media";
30
+ import { ImageUpload } from "../../media/upload/ImageUpload";
31
+ import { brandFormSchema } from "../schemas/admin-editor-forms";
32
+ const __P = { p4: "p-[var(--appkit-space-4)]" };
33
+ const __O = { yAuto: "overflow-y-auto" };
34
+ const EMPTY = {
35
+ name: "",
36
+ slug: "",
37
+ description: "",
38
+ logoURL: "",
39
+ website: "",
40
+ country: "",
41
+ founded: "",
42
+ isActive: true,
43
+ displayOrder: "",
31
44
  };
32
45
  function toBrandSlug(str) {
33
- const base = str.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
46
+ const base = str
47
+ .toLowerCase()
48
+ .trim()
49
+ .replace(/[^a-z0-9]+/g, "-")
50
+ .replace(/^-+|-+$/g, "");
34
51
  return base.startsWith("brand-") ? base : `brand-${base}`;
35
52
  }
53
+ /** `""` means "not set" — `Number("")` is 0, which is a real display order. */
54
+ function optionalNumber(raw) {
55
+ return raw.trim() === "" ? undefined : Number(raw);
56
+ }
36
57
  export function AdminBrandEditorView({ brandId, onSaved, onDeleted, embedded, ...rest }) {
37
58
  const isEdit = Boolean(brandId);
38
- const [name, setName] = React.useState("");
39
- const [slug, setSlug] = React.useState("");
40
- const [slugManual, setSlugManual] = React.useState(false);
41
- const [description, setDescription] = React.useState("");
42
- const [logoURL, setLogoURL] = React.useState("");
43
- const [website, setWebsite] = React.useState("");
44
- const [country, setCountry] = React.useState("");
45
- const [founded, setFounded] = React.useState("");
46
- const [isActive, setIsActive] = React.useState(true);
47
- const [displayOrder, setDisplayOrder] = React.useState("");
59
+ const [form, setForm] = React.useState(EMPTY);
48
60
  const [deleteConfirmOpen, setDeleteConfirmOpen] = React.useState(false);
49
61
  const { showToast } = useToast();
62
+ const { upload } = useMediaUpload();
50
63
  const brandQuery = useQuery({
51
64
  queryKey: ["admin", "brand", brandId],
52
65
  queryFn: async () => {
53
- const res = await apiClient.get(ADMIN_ENDPOINTS.BRAND_BY_ID(brandId));
54
- return res?.data ?? res;
66
+ const res = (await apiClient.get(ADMIN_ENDPOINTS.BRAND_BY_ID(brandId)));
67
+ return (res?.data ?? res);
55
68
  },
56
69
  enabled: isEdit,
57
70
  });
@@ -59,39 +72,49 @@ export function AdminBrandEditorView({ brandId, onSaved, onDeleted, embedded, ..
59
72
  const brand = brandQuery.data;
60
73
  if (!brand)
61
74
  return;
62
- setName(brand.name ?? "");
63
- setSlug(brand.slug ?? "");
64
- setSlugManual(true);
65
- setDescription(brand.description ?? "");
66
- setLogoURL(brand.logoURL ?? "");
67
- setWebsite(brand.website ?? "");
68
- setCountry(brand.country ?? "");
69
- setFounded(brand.founded !== undefined ? String(brand.founded) : "");
70
- setIsActive(brand.isActive ?? true);
71
- setDisplayOrder(brand.displayOrder !== undefined ? String(brand.displayOrder) : "");
75
+ setForm({
76
+ name: brand.name ?? "",
77
+ slug: brand.slug ?? "",
78
+ description: brand.description ?? "",
79
+ logoURL: brand.logoURL ?? "",
80
+ website: brand.website ?? "",
81
+ country: brand.country ?? "",
82
+ founded: brand.founded !== undefined ? String(brand.founded) : "",
83
+ isActive: brand.isActive ?? true,
84
+ displayOrder: brand.displayOrder !== undefined ? String(brand.displayOrder) : "",
85
+ });
72
86
  }, [brandQuery.data]);
73
- const handleNameChange = (value) => {
74
- setName(value);
75
- if (!slugManual)
76
- setSlug(toBrandSlug(value));
77
- };
87
+ const sections = React.useMemo(() => buildSectionsFromSchema(brandFormSchema, {
88
+ renderers: {
89
+ logoURL: ({ values, onChange }) => (_jsx(ImageUpload, { label: "Cover image", currentImage: values.logoURL, onUpload: (file) => upload(file, "brands", true, {
90
+ type: "brand-logo",
91
+ brand: values.name || values.slug,
92
+ }), onChange: (url) => onChange({ logoURL: url }) })),
93
+ },
94
+ }), [upload]);
95
+ const nav = useSectionFormNav(sections, form, { scope: "admin:brand-editor" });
96
+ const { shellCtx, setFieldError, clearErrors } = useFormShellState(brandFormSchema, {
97
+ sections: nav.sectionMeta,
98
+ onGoToSection: nav.goToSection,
99
+ fieldToSectionIndex: nav.fieldToSectionIndex,
100
+ });
78
101
  const saveMutation = useApiMutation({
79
102
  errorMessage: "Failed to save brand.",
80
103
  mutationFn: async () => {
81
104
  const payload = {
82
- name,
83
- slug: slug || toBrandSlug(name),
84
- description: description || undefined,
85
- logoURL: logoURL || undefined,
86
- website: website || undefined,
87
- country: country || undefined,
88
- founded: founded !== "" ? Number(founded) : undefined,
89
- isActive,
90
- displayOrder: displayOrder !== "" ? Number(displayOrder) : undefined,
105
+ name: form.name,
106
+ // Create-only: an existing brand keeps the slug its links resolve on.
107
+ slug: isEdit ? form.slug : toBrandSlug(form.name),
108
+ description: form.description || undefined,
109
+ logoURL: form.logoURL || undefined,
110
+ website: form.website || undefined,
111
+ country: form.country || undefined,
112
+ founded: optionalNumber(form.founded),
113
+ isActive: form.isActive,
114
+ displayOrder: optionalNumber(form.displayOrder),
91
115
  };
92
- if (isEdit) {
116
+ if (isEdit)
93
117
  return apiClient.put(ADMIN_ENDPOINTS.BRAND_BY_ID(brandId), payload);
94
- }
95
118
  return apiClient.post(ADMIN_ENDPOINTS.BRANDS, payload);
96
119
  },
97
120
  onSuccess: (res) => {
@@ -110,19 +133,32 @@ export function AdminBrandEditorView({ brandId, onSaved, onDeleted, embedded, ..
110
133
  onDeleted();
111
134
  },
112
135
  });
113
- const { upload } = useMediaUpload();
114
- const isSubmitting = saveMutation.isPending || brandQuery.isLoading;
115
- const formSection = (_jsxs(_Fragment, { children: [_jsx(Form, { schema: brandFormSchema, 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: "Brand name", value: name, onChange: (v) => handleNameChange(v), required: true, placeholder: "e.g. Hot Wheels" }), _jsx(Input, { label: "Slug", value: slug, onChange: (e) => {
116
- setSlug(e.target.value);
117
- setSlugManual(true);
118
- }, 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" }), _jsx(ImageUpload, { label: "Cover Image", currentImage: logoURL, onUpload: (file) => upload(file, "brands", true, { type: "brand-logo", brand: name || slug }), onChange: setLogoURL }), _jsxs(Div, { layout: "grid", gap: "4", className: "sm:grid-cols-2", 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" })] }), _jsxs(Div, { layout: "grid", gap: "4", className: "sm:grid-cols-2", children: [_jsx(Input, { label: "Country of origin", value: country, onChange: (e) => setCountry(e.target.value), placeholder: "e.g. Japan" }), _jsx(Input, { label: "Founded year", value: founded, onChange: (e) => setFounded(e.target.value), type: "number", min: 1800, max: new Date().getFullYear(), placeholder: "e.g. 1999" })] }), _jsx(Toggle, { label: "Active", checked: isActive, onChange: setIsActive }), _jsx(FormErrorSummary, {}), _jsxs(Row, { gap: "3", padding: "t-xs", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !name || isSubmitting, onClick: () => {
119
- clearErrors();
120
- if (!name.trim()) {
121
- setFieldError("name", "Brand name is required");
122
- return;
123
- }
124
- saveMutation.mutate();
125
- }, children: isEdit ? "Save changes" : "Create brand" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", onClick: () => setDeleteConfirmOpen(true), children: "Delete brand" }))] })] })) }, "brand-form"), deleteConfirmOpen && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Brand", message: "Delete this brand? This cannot be undone.", onConfirm: () => { deleteMutation.mutate(); setDeleteConfirmOpen(false); }, onClose: () => setDeleteConfirmOpen(false), isDeleting: deleteMutation.isPending }))] }));
136
+ const onSubmit = () => {
137
+ clearErrors();
138
+ const parsed = brandFormSchema.safeParse({
139
+ ...form,
140
+ slug: isEdit ? form.slug : toBrandSlug(form.name),
141
+ founded: optionalNumber(form.founded),
142
+ displayOrder: optionalNumber(form.displayOrder),
143
+ });
144
+ if (!parsed.success) {
145
+ applyZodIssues(parsed.error.issues, setFieldError);
146
+ return;
147
+ }
148
+ saveMutation.mutate();
149
+ };
150
+ // The live slug preview tracks the name until the brand exists.
151
+ React.useEffect(() => {
152
+ if (isEdit)
153
+ return;
154
+ setForm((prev) => ({ ...prev, slug: prev.name ? toBrandSlug(prev.name) : "" }));
155
+ }, [form.name, isEdit]);
156
+ const formSection = (_jsxs(_Fragment, { children: [_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: brandFormSchema, openIds: nav.openIds, onOpenChange: nav.setOpenIds, isLoading: saveMutation.isPending || brandQuery.isLoading, submitLabel: isEdit ? "Save changes" : "Create brand", destructiveAction: isEdit
157
+ ? { label: "Delete brand", onClick: () => setDeleteConfirmOpen(true) }
158
+ : undefined })] }), deleteConfirmOpen && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Brand", message: "Delete this brand? This cannot be undone.", onConfirm: () => {
159
+ deleteMutation.mutate();
160
+ setDeleteConfirmOpen(false);
161
+ }, onClose: () => setDeleteConfirmOpen(false), isDeleting: deleteMutation.isPending }))] }));
126
162
  if (embedded) {
127
163
  return _jsx(Div, { className: `${__O.yAuto} ${__P.p4}`, children: formSection });
128
164
  }
@@ -1,17 +1,25 @@
1
1
  /**
2
- * AdminBundleEditorView — S-SBUNI-4 2026-05-13.
2
+ * AdminBundleEditorView — S-SBUNI-4 2026-05-13, sectionised 2026-08-30.
3
3
  *
4
4
  * Unified create + edit view for categoryType:"bundle" rows. When `bundleId`
5
5
  * is set, loads + edits; when omitted, runs as a "new" form. Delegates to
6
- * /api/admin/bundles. Owns: name + description + bundlePrice +
7
- * static-only product picker + isActive. Dynamic-rule editing is out of scope
8
- * for this session (the API accepts dynamic rules but the form only writes
9
- * static rules; admins editing a pre-existing dynamic bundle see its members
10
- * in the picker but the rule itself stays unchanged until they switch to
11
- * static).
6
+ * /api/admin/bundles (or /api/store/bundles under `scope="store"`).
7
+ *
8
+ * ## The schema now runs
9
+ *
10
+ * It used to declare a seven-field `.passthrough()` stub inside this file,
11
+ * hand it to `<Form schema>`, and validate with two `if` statements instead.
12
+ * So the member-count bounds the picker DISPLAYS — `min 3, max 16` — were red
13
+ * hint text under the control that nothing enforced, and a two-member bundle
14
+ * saved cleanly. The real schema lives in `../../categories/schemas/bundle-form`
15
+ * and is parsed on every change.
16
+ *
17
+ * Static vs dynamic rules are both editable: the rule-type select swaps which
18
+ * member source is on screen, and `visibleValues` makes the payload follow it.
12
19
  */
13
20
  import React from "react";
14
- export interface AdminBundleEditorViewProps {
21
+ import type { StackedViewShellProps } from "../../../ui";
22
+ export interface AdminBundleEditorViewProps extends Omit<StackedViewShellProps, "sections"> {
15
23
  /** When set, the form loads an existing bundle; otherwise it runs as "new". */
16
24
  bundleId?: string;
17
25
  /** Called after a successful create with the new bundle id. */
@@ -25,5 +33,7 @@ export interface AdminBundleEditorViewProps {
25
33
  * products.
26
34
  */
27
35
  scope?: "admin" | "store";
36
+ /** Render bare, for a drawer that supplies its own chrome. */
37
+ embedded?: boolean;
28
38
  }
29
- export declare function AdminBundleEditorView({ bundleId, onSaved, onDeleted, scope, }: AdminBundleEditorViewProps): React.JSX.Element;
39
+ export declare function AdminBundleEditorView({ bundleId, onSaved, onDeleted, scope, embedded, ...rest }: AdminBundleEditorViewProps): React.JSX.Element;