@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
@@ -12,7 +12,11 @@ export interface UserProfile {
12
12
  googleLinked?: boolean;
13
13
  googleLinkedEmail?: string | null;
14
14
  uiPreferences?: {
15
+ /** @deprecated Superseded by `sectionState`. Still written during the
16
+ * migration window so an existing user's layout carries over. */
15
17
  collapsedSections?: string[];
18
+ /** scope -> ids that are OPEN. See useSectionState. */
19
+ sectionState?: Record<string, string[]>;
16
20
  dataViewMode?: "table" | "grid" | "list";
17
21
  handMode?: "left" | "right";
18
22
  };
@@ -32,7 +36,11 @@ export interface UpdateCurrentProfileInput {
32
36
  bio?: string;
33
37
  profileIsPublic?: boolean;
34
38
  uiPreferences?: {
39
+ /** @deprecated Superseded by `sectionState`. Still written during the
40
+ * migration window so an existing user's layout carries over. */
35
41
  collapsedSections?: string[];
42
+ /** scope -> ids that are OPEN. See useSectionState. */
43
+ sectionState?: Record<string, string[]>;
36
44
  dataViewMode?: "table" | "grid" | "list";
37
45
  handMode?: "left" | "right";
38
46
  };
@@ -3,14 +3,11 @@ export * from "./schemas";
3
3
  export * from "./columns";
4
4
  export * from "./hooks/useAccount";
5
5
  export * from "./hooks/useAddresses";
6
- export * from "./hooks/useAddressForm";
7
6
  export * from "./hooks/useAddressSelector";
8
7
  export * from "./hooks/useNotifications";
9
8
  export * from "./hooks/useProfileStats";
10
9
  export * from "./hooks/useCollapsedSections";
11
10
  export { useCurrentProfile as useProfile, useUpdateCurrentProfile as useUpdateProfile, } from "./hooks/useProfile";
12
11
  export * from "./hooks/usePublicProfile";
13
- export * from "./constants/addresses";
14
- export * from "./address-validation";
15
12
  export * from "./components";
16
13
  export { manifest } from "./manifest";
@@ -3,14 +3,11 @@ export * from "./schemas";
3
3
  export * from "./columns";
4
4
  export * from "./hooks/useAccount";
5
5
  export * from "./hooks/useAddresses";
6
- export * from "./hooks/useAddressForm";
7
6
  export * from "./hooks/useAddressSelector";
8
7
  export * from "./hooks/useNotifications";
9
8
  export * from "./hooks/useProfileStats";
10
9
  export * from "./hooks/useCollapsedSections";
11
10
  export { useCurrentProfile as useProfile, useUpdateCurrentProfile as useUpdateProfile, } from "./hooks/useProfile";
12
11
  export * from "./hooks/usePublicProfile";
13
- export * from "./constants/addresses";
14
- export * from "./address-validation";
15
12
  export * from "./components";
16
13
  export { manifest } from "./manifest";
@@ -1,39 +1,5 @@
1
1
  export * from "./firestore";
2
2
  import { z } from "zod";
3
- export declare const userAddressSchema: z.ZodObject<{
4
- id: z.ZodString;
5
- label: z.ZodOptional<z.ZodString>;
6
- line1: z.ZodString;
7
- line2: z.ZodOptional<z.ZodString>;
8
- city: z.ZodString;
9
- state: z.ZodString;
10
- postalCode: z.ZodString;
11
- country: z.ZodString;
12
- isDefault: z.ZodOptional<z.ZodBoolean>;
13
- phone: z.ZodOptional<z.ZodString>;
14
- }, "strip", z.ZodTypeAny, {
15
- country: string;
16
- id: string;
17
- city: string;
18
- state: string;
19
- postalCode: string;
20
- line1: string;
21
- label?: string | undefined;
22
- isDefault?: boolean | undefined;
23
- phone?: string | undefined;
24
- line2?: string | undefined;
25
- }, {
26
- country: string;
27
- id: string;
28
- city: string;
29
- state: string;
30
- postalCode: string;
31
- line1: string;
32
- label?: string | undefined;
33
- isDefault?: boolean | undefined;
34
- phone?: string | undefined;
35
- line2?: string | undefined;
36
- }>;
37
3
  export declare const notificationPreferencesSchema: z.ZodObject<{
38
4
  orderUpdates: z.ZodOptional<z.ZodBoolean>;
39
5
  promotions: z.ZodOptional<z.ZodBoolean>;
@@ -71,40 +37,6 @@ export declare const userProfileSchema: z.ZodObject<{
71
37
  phone: z.ZodOptional<z.ZodString>;
72
38
  photoURL: z.ZodOptional<z.ZodString>;
73
39
  bio: z.ZodOptional<z.ZodString>;
74
- addresses: z.ZodOptional<z.ZodArray<z.ZodObject<{
75
- id: z.ZodString;
76
- label: z.ZodOptional<z.ZodString>;
77
- line1: z.ZodString;
78
- line2: z.ZodOptional<z.ZodString>;
79
- city: z.ZodString;
80
- state: z.ZodString;
81
- postalCode: z.ZodString;
82
- country: z.ZodString;
83
- isDefault: z.ZodOptional<z.ZodBoolean>;
84
- phone: z.ZodOptional<z.ZodString>;
85
- }, "strip", z.ZodTypeAny, {
86
- country: string;
87
- id: string;
88
- city: string;
89
- state: string;
90
- postalCode: string;
91
- line1: string;
92
- label?: string | undefined;
93
- isDefault?: boolean | undefined;
94
- phone?: string | undefined;
95
- line2?: string | undefined;
96
- }, {
97
- country: string;
98
- id: string;
99
- city: string;
100
- state: string;
101
- postalCode: string;
102
- line1: string;
103
- label?: string | undefined;
104
- isDefault?: boolean | undefined;
105
- phone?: string | undefined;
106
- line2?: string | undefined;
107
- }>, "many">>;
108
40
  notificationPreferences: z.ZodOptional<z.ZodObject<{
109
41
  orderUpdates: z.ZodOptional<z.ZodBoolean>;
110
42
  promotions: z.ZodOptional<z.ZodBoolean>;
@@ -132,18 +64,6 @@ export declare const userProfileSchema: z.ZodObject<{
132
64
  displayName?: string | undefined;
133
65
  createdAt?: string | undefined;
134
66
  updatedAt?: string | undefined;
135
- addresses?: {
136
- country: string;
137
- id: string;
138
- city: string;
139
- state: string;
140
- postalCode: string;
141
- line1: string;
142
- label?: string | undefined;
143
- isDefault?: boolean | undefined;
144
- phone?: string | undefined;
145
- line2?: string | undefined;
146
- }[] | undefined;
147
67
  photoURL?: string | undefined;
148
68
  bio?: string | undefined;
149
69
  phone?: string | undefined;
@@ -160,18 +80,6 @@ export declare const userProfileSchema: z.ZodObject<{
160
80
  displayName?: string | undefined;
161
81
  createdAt?: string | undefined;
162
82
  updatedAt?: string | undefined;
163
- addresses?: {
164
- country: string;
165
- id: string;
166
- city: string;
167
- state: string;
168
- postalCode: string;
169
- line1: string;
170
- label?: string | undefined;
171
- isDefault?: boolean | undefined;
172
- phone?: string | undefined;
173
- line2?: string | undefined;
174
- }[] | undefined;
175
83
  photoURL?: string | undefined;
176
84
  bio?: string | undefined;
177
85
  phone?: string | undefined;
@@ -1,18 +1,16 @@
1
1
  export * from "./firestore";
2
2
  import { z } from "zod";
3
+ import { annotate } from "../../shell/field-ui-meta";
3
4
  // --- Sub-schemas --------------------------------------------------------------
4
- export const userAddressSchema = z.object({
5
- id: z.string(),
6
- label: z.string().optional(),
7
- line1: z.string(),
8
- line2: z.string().optional(),
9
- city: z.string(),
10
- state: z.string(),
11
- postalCode: z.string(),
12
- country: z.string(),
13
- isDefault: z.boolean().optional(),
14
- phone: z.string().optional(),
15
- });
5
+ /*
6
+ * `userAddressSchema` is DELETED (W5 / D19).
7
+ *
8
+ * It carried the `line1`/`line2` naming — one of the eleven address shapes,
9
+ * and the only one that disagreed with `AddressDocument` on field NAMES rather
10
+ * than just on rules. Zero consumers outside the barrel that re-exported it.
11
+ * The one shape is `addressFormSchema` in
12
+ * `features/addresses/schemas/address-form.ts`.
13
+ */
16
14
  export const notificationPreferencesSchema = z.object({
17
15
  orderUpdates: z.boolean().optional(),
18
16
  promotions: z.boolean().optional(),
@@ -39,7 +37,6 @@ export const userProfileSchema = z.object({
39
37
  phone: z.string().optional(),
40
38
  photoURL: z.string().optional(),
41
39
  bio: z.string().optional(),
42
- addresses: z.array(userAddressSchema).optional(),
43
40
  notificationPreferences: notificationPreferencesSchema.optional(),
44
41
  createdAt: z.string().optional(),
45
42
  updatedAt: z.string().optional(),
@@ -51,10 +48,23 @@ export const userProfileSchema = z.object({
51
48
  * validation too.
52
49
  */
53
50
  export const updateProfileSchema = z.object({
54
- displayName: z.string().min(1, "Enter your name").optional(),
55
- phoneNumber: z.string().optional(),
56
- bio: z.string().max(500, "Bio must be 500 characters or fewer").optional(),
57
- profileIsPublic: z.boolean().optional(),
51
+ displayName: annotate(z.string().min(1, "Enter your name").optional(), {
52
+ section: "profile", sectionLabel: "Your details", sectionRequired: true,
53
+ quick: true, order: 1, row: "pair", label: "Display name",
54
+ }),
55
+ phoneNumber: annotate(z.string().optional(), {
56
+ section: "profile", quick: true, order: 2, row: "pair",
57
+ label: "Phone number", inputType: "tel",
58
+ }),
59
+ bio: annotate(z.string().max(500, "Bio must be 500 characters or fewer").optional(), {
60
+ section: "profile", order: 3, row: "full", kind: "textarea",
61
+ label: "Bio", help: "Up to 500 characters. Buyers see this on your public profile.",
62
+ }),
63
+ profileIsPublic: annotate(z.boolean().optional(), {
64
+ section: "visibility", sectionLabel: "Visibility", order: 1, row: "full",
65
+ label: "Public profile",
66
+ help: "When on, your profile is visible to other LetItRip users.",
67
+ }),
58
68
  });
59
69
  /**
60
70
  * Changing the account email.
@@ -69,11 +79,23 @@ export const updateProfileSchema = z.object({
69
79
  * credential, not chosen here.
70
80
  */
71
81
  export const changeEmailSchema = z.object({
72
- newEmail: z
82
+ newEmail: annotate(z
73
83
  .string()
74
84
  .trim()
75
85
  .toLowerCase()
76
86
  .min(1, "Enter the new email address.")
77
- .email("That doesn't look like an email address."),
78
- emailPassword: z.string().min(1, "Enter your current password to confirm."),
87
+ .email("That doesn't look like an email address."), {
88
+ section: "basics", sectionLabel: "Change email", sectionRequired: true,
89
+ order: 1, row: "full", label: "New email address", inputType: "email",
90
+ }),
91
+ /*
92
+ * 🛑 `inputType: "password"` is not cosmetic. Without it the generated
93
+ * control is a bare `<FieldInput>` with no `type`, which renders a password
94
+ * IN PLAINTEXT — the defect found the first time this generator met a
95
+ * credential field.
96
+ */
97
+ emailPassword: annotate(z.string().min(1, "Enter your current password to confirm."), {
98
+ section: "basics", order: 2, row: "full", label: "Current password",
99
+ inputType: "password",
100
+ }),
79
101
  });
@@ -0,0 +1,13 @@
1
+ import * as React from "react";
2
+ import type { JsonValue } from "@mohasinac/appkit/client";
3
+ export interface AddressLocationFieldsProps {
4
+ country: string;
5
+ state: string;
6
+ postalCode: string;
7
+ errors: Record<string, string>;
8
+ isLooking?: boolean;
9
+ onChange: (partial: Record<string, JsonValue>) => void;
10
+ /** Called with (postalCode, country) whenever either settles. */
11
+ onPostalSettled: (postalCode: string, country: string) => void;
12
+ }
13
+ export declare function AddressLocationFields({ country, state, postalCode, errors, isLooking, onChange, onPostalSettled, }: AddressLocationFieldsProps): React.JSX.Element;
@@ -0,0 +1,41 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { PaginatedSelect, Stack, Text } from "../../../ui";
4
+ import { FieldInput } from "../../../ui/forms/FieldInput";
5
+ import { FormGroup } from "../../../ui/components/Form";
6
+ import { countryFor, postalLabelFor, COUNTRIES } from "../../../constants/geo/countries";
7
+ import { subdivisionsFor } from "../../../constants/geo/subdivisions";
8
+ const COUNTRY_OPTIONS = Object.values(COUNTRIES).map((c) => ({
9
+ value: c.code,
10
+ label: c.name,
11
+ }));
12
+ export function AddressLocationFields({ country, state, postalCode, errors, isLooking = false, onChange, onPostalSettled, }) {
13
+ const def = countryFor(country);
14
+ const states = subdivisionsFor(def?.code);
15
+ const postalLabel = postalLabelFor(country);
16
+ return (_jsxs(Stack, { gap: "sm", children: [_jsxs(FormGroup, { columns: 2, children: [_jsx(PaginatedSelectField, { label: "Country", value: def?.code ?? "", error: errors.country, onChange: (next) => {
17
+ /*
18
+ * Changing country invalidates the state: "Karnataka" is not a
19
+ * Canadian province. Cleared rather than carried, because a state
20
+ * that no longer belongs to its country is a row nothing can
21
+ * group or ship.
22
+ */
23
+ onChange({ country: next, state: "" });
24
+ onPostalSettled(postalCode, next);
25
+ } }), states.length > 0 ? (_jsx(PaginatedSelectField, { label: "State / region", value: state, error: errors.state, options: states.map((s) => ({ value: s, label: s })), onChange: (next) => onChange({ state: next }) })) : (_jsx(FieldInput, { name: "state", label: "State / region", required: true, value: state, error: errors.state, onChange: (v) => onChange({ state: v }) }))] }), _jsx(FieldInput, { name: "postalCode", label: postalLabel, required: true, value: postalCode, error: errors.postalCode, hint: isLooking
26
+ ? "Looking up your city…"
27
+ : "We fill in the city and state when we recognise it.", onChange: (v) => {
28
+ onChange({ postalCode: v });
29
+ onPostalSettled(v, country);
30
+ }, onBlur: () => onPostalSettled(postalCode, country) }), !def && country.trim() && (_jsx(Text, { size: "xs", color: "muted", children: "We do not know the postal format for that country, so anything plausible is accepted." }))] }));
31
+ }
32
+ /**
33
+ * A labelled `PaginatedSelect`.
34
+ *
35
+ * The primitive takes no `label` or `error` of its own — the generator wraps
36
+ * it the same way at `build-sections.tsx:392`. This is that wrapper, named,
37
+ * so the two country pickers in this file do not each rebuild it.
38
+ */
39
+ function PaginatedSelectField({ label, value, error, options = COUNTRY_OPTIONS, onChange, }) {
40
+ return (_jsxs(Stack, { gap: "xs", children: [_jsxs(Text, { size: "sm", weight: "medium", color: "muted", children: [label, " *"] }), _jsx(PaginatedSelect, { value: value, options: options, onChange: (next) => onChange(next ?? ""), ariaLabel: label, placeholder: `Select ${label.toLowerCase()}…` }), error && (_jsx(Text, { size: "xs", color: "error", role: "alert", children: error }))] }));
41
+ }
@@ -0,0 +1,17 @@
1
+ export interface PostalLookupResult {
2
+ city: string;
3
+ state: string;
4
+ }
5
+ export interface UsePostalLookupOptions {
6
+ /** Called with the resolved place. Only ever fires on a hit. */
7
+ onResolved: (result: PostalLookupResult) => void;
8
+ /** Skip the lookup entirely — e.g. while the form is submitting. */
9
+ enabled?: boolean;
10
+ }
11
+ export interface UsePostalLookupResult {
12
+ /** Feed it the current postal code and country on every change or blur. */
13
+ lookup: (postalCode: string, country: string) => void;
14
+ /** True while a request is in flight. Purely for a spinner; never gates. */
15
+ isLooking: boolean;
16
+ }
17
+ export declare function usePostalLookup({ onResolved, enabled, }: UsePostalLookupOptions): UsePostalLookupResult;
@@ -0,0 +1,133 @@
1
+ "use client";
2
+ /*
3
+ * WHY: "Typing a zipcode should fill in the city" — and there was **no lookup
4
+ * anywhere in the codebase**. Two dead modules carried the shape of one
5
+ * that had been removed (`useAddressForm`, `address-validation`, both
6
+ * with an unused `validatePostalCode` extension point and zero
7
+ * consumers), which is what made it look built.
8
+ * WHAT: `usePostalLookup` — resolve a postal code to its place and region.
9
+ *
10
+ * ## Zippopotam, and one code path for every country
11
+ *
12
+ * `https://api.zippopotam.us/{country}/{postal}` is free, needs no key and
13
+ * covers ~60 countries. It returns place + state, not district — which is fine:
14
+ * the user writes the locality, this fills the two fields they would otherwise
15
+ * copy off an envelope.
16
+ *
17
+ * India Post's own API would be more complete for India, but it is one country
18
+ * behind a different contract; a second provider is a second failure mode and a
19
+ * second set of field names for a form that just spent this wave collapsing
20
+ * eleven shapes into one.
21
+ *
22
+ * ## 🛑 Three rules, and each one is the difference between help and damage
23
+ *
24
+ * 1. **Never overwrite what the user typed.** Autofill lands only in an EMPTY
25
+ * city or state. A lookup that corrects a deliberately unusual address is a
26
+ * bug the user cannot even report — they watch their own typing vanish.
27
+ * 2. **Fail silently and OPEN.** A network error, a 404, an unsupported
28
+ * country: all leave the fields exactly as they were and never block the
29
+ * submit. Zippopotam's India coverage is thinner than India Post's, so a
30
+ * miss is the common case and must be a non-event.
31
+ * 3. **Abort in flight.** A user typing "560001" fires on every keystroke past
32
+ * the debounce; without an `AbortController` the answer for "56000" can
33
+ * land after the answer for "560001" and fill the wrong city.
34
+ *
35
+ * EXPORTS: usePostalLookup, type PostalLookupResult
36
+ *
37
+ * @tag domain:addresses
38
+ * @tag layer:hook
39
+ * @tag pattern:none
40
+ * @tag access:client
41
+ * @tag consumers:AddressForm,AdminAddressEditorView
42
+ * @tag sideEffects:network
43
+ */
44
+ import * as React from "react";
45
+ import { normalizeError } from "../../../errors/normalize";
46
+ import { countryFor, isValidPostalCode } from "../../../constants/geo/countries";
47
+ const ENDPOINT = "https://api.zippopotam.us";
48
+ const DEBOUNCE_MS = 400;
49
+ /**
50
+ * Per-session cache, keyed `{country}:{postal}`.
51
+ *
52
+ * Module scope rather than component state: the same postal code is looked up
53
+ * again every time the user opens the address form, and a miss is cached too —
54
+ * re-asking for a code Zippopotam does not have is a round trip that can only
55
+ * fail again.
56
+ */
57
+ const CACHE = new Map();
58
+ export function usePostalLookup({ onResolved, enabled = true, }) {
59
+ const [isLooking, setIsLooking] = React.useState(false);
60
+ const timerRef = React.useRef(null);
61
+ const abortRef = React.useRef(null);
62
+ /*
63
+ * The callback in a ref so `lookup` is stable across renders. Without it
64
+ * every keystroke re-creates the debounced function and the timer never
65
+ * survives long enough to fire.
66
+ */
67
+ const onResolvedRef = React.useRef(onResolved);
68
+ onResolvedRef.current = onResolved;
69
+ React.useEffect(() => () => {
70
+ if (timerRef.current)
71
+ clearTimeout(timerRef.current);
72
+ abortRef.current?.abort();
73
+ }, []);
74
+ const lookup = React.useCallback((postalCode, country) => {
75
+ if (!enabled)
76
+ return;
77
+ if (timerRef.current)
78
+ clearTimeout(timerRef.current);
79
+ abortRef.current?.abort();
80
+ const code = postalCode.trim();
81
+ const def = countryFor(country);
82
+ // Only ask once the code is plausibly complete for this country, so a
83
+ // half-typed PIN does not spend a round trip proving itself wrong.
84
+ if (!def || !isValidPostalCode(country, code))
85
+ return;
86
+ const key = `${def.code}:${code}`;
87
+ const cached = CACHE.get(key);
88
+ if (cached !== undefined) {
89
+ if (cached)
90
+ onResolvedRef.current(cached);
91
+ return;
92
+ }
93
+ timerRef.current = setTimeout(() => {
94
+ const controller = new AbortController();
95
+ abortRef.current = controller;
96
+ setIsLooking(true);
97
+ void fetch(`${ENDPOINT}/${def.code.toLowerCase()}/${encodeURIComponent(code)}`, {
98
+ signal: controller.signal,
99
+ })
100
+ .then((res) => (res.ok ? res.json() : null))
101
+ .then((json) => {
102
+ const place = json?.places?.[0];
103
+ const result = place
104
+ ? {
105
+ city: place["place name"] ?? "",
106
+ state: place.state ?? place["state abbreviation"] ?? "",
107
+ }
108
+ : null;
109
+ CACHE.set(key, result);
110
+ if (result)
111
+ onResolvedRef.current(result);
112
+ })
113
+ .catch((err) => {
114
+ const normalized = normalizeError(err);
115
+ /*
116
+ * Deliberately silent. An abort is the expected path when the user
117
+ * keeps typing, and a real failure must leave the fields editable
118
+ * rather than tell the buyer their postcode is wrong when it is
119
+ * our upstream that is down. Not cached, so a transient failure
120
+ * does not poison the code for the session.
121
+ */
122
+ void normalized;
123
+ })
124
+ .finally(() => {
125
+ if (abortRef.current === controller) {
126
+ abortRef.current = null;
127
+ setIsLooking(false);
128
+ }
129
+ });
130
+ }, DEBOUNCE_MS);
131
+ }, [enabled]);
132
+ return { lookup, isLooking };
133
+ }