@mohasinac/appkit 4.30.19 → 4.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_internal/client/features/layout/useSidebarSearch.d.ts +21 -5
- package/dist/_internal/client/features/layout/useSidebarSearch.js +27 -6
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.d.ts +23 -3
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +106 -87
- package/dist/_internal/client/features/lottery/LotteryPullForm.d.ts +16 -5
- package/dist/_internal/client/features/lottery/LotteryPullForm.js +65 -40
- package/dist/_internal/server/features/auth/permissions.d.ts +2 -0
- package/dist/_internal/server/features/auth/permissions.js +3 -2
- package/dist/_internal/server/features/categories/data.js +15 -4
- package/dist/_internal/server/features/classified/index.d.ts +0 -1
- package/dist/_internal/server/features/classified/index.js +0 -1
- package/dist/_internal/server/features/digital-code/index.d.ts +0 -1
- package/dist/_internal/server/features/digital-code/index.js +0 -1
- package/dist/_internal/server/features/live/index.d.ts +0 -1
- package/dist/_internal/server/features/live/index.js +0 -1
- package/dist/_internal/server/features/products/data.js +15 -5
- package/dist/_internal/server/features/products/list-public.d.ts +9 -0
- package/dist/_internal/server/features/products/list-public.js +95 -7
- package/dist/_internal/server/features/site-settings/adapters.d.ts +2 -2
- package/dist/_internal/server/features/site-settings/adapters.js +8 -5
- package/dist/_internal/server/features/tester/visibility.d.ts +2 -1
- package/dist/_internal/server/features/tester/visibility.js +2 -2
- package/dist/_internal/server/functions/scheduled.d.ts +3 -1
- package/dist/_internal/server/functions/scheduled.js +27 -1
- package/dist/_internal/server/jobs/core/hardBanCascade.js +4 -0
- package/dist/_internal/server/jobs/core/index.d.ts +2 -0
- package/dist/_internal/server/jobs/core/index.js +2 -0
- package/dist/_internal/server/jobs/core/pageViewPrune.d.ts +10 -0
- package/dist/_internal/server/jobs/core/pageViewPrune.js +44 -0
- package/dist/_internal/server/jobs/core/pageViewRollup.d.ts +2 -0
- package/dist/_internal/server/jobs/core/pageViewRollup.js +87 -0
- package/dist/_internal/server/jobs/handlers/index.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/index.js +2 -0
- package/dist/_internal/server/jobs/handlers/pageViewPrune.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/pageViewPrune.js +2 -0
- package/dist/_internal/server/jobs/handlers/pageViewRollup.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/pageViewRollup.js +2 -0
- package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
- package/dist/_internal/shared/actions/action-registry.js +69 -22
- package/dist/_internal/shared/checkout/rules/classified.rule.d.ts +9 -4
- package/dist/_internal/shared/checkout/rules/classified.rule.js +7 -2
- package/dist/_internal/shared/features/layout/matchesNavQuery.d.ts +14 -0
- package/dist/_internal/shared/features/layout/matchesNavQuery.js +72 -0
- package/dist/_internal/shared/features/layout/types.d.ts +37 -1
- package/dist/_internal/shared/features/layout/types.js +19 -1
- package/dist/_internal/shared/features/notifications/action-url.d.ts +9 -1
- package/dist/_internal/shared/features/notifications/action-url.js +47 -0
- package/dist/_internal/shared/features/offers/config.d.ts +65 -0
- package/dist/_internal/shared/features/offers/config.js +73 -2
- package/dist/_internal/shared/features/orders/schema.d.ts +19 -1
- package/dist/_internal/shared/features/orders/schema.js +22 -2
- package/dist/_internal/shared/features/site-settings/types.d.ts +12 -3
- package/dist/_internal/shared/listing-types/capabilities.d.ts +8 -2
- package/dist/_internal/shared/listing-types/capabilities.js +6 -1
- package/dist/_internal/shared/listing-types/classified/ctas.js +6 -1
- package/dist/_internal/shared/listing-types/feature-flags.d.ts +10 -5
- package/dist/_internal/shared/listing-types/feature-flags.js +11 -6
- package/dist/client.d.ts +37 -20
- package/dist/client.js +36 -14
- package/dist/configs/next.js +10 -2
- package/dist/constants/api-endpoints.d.ts +18 -54
- package/dist/constants/api-endpoints.js +6 -26
- package/dist/constants/field-names.d.ts +6 -24
- package/dist/constants/field-names.js +10 -27
- package/dist/constants/geo/countries.d.ts +50 -0
- package/dist/constants/geo/countries.js +129 -0
- package/dist/constants/geo/subdivisions.d.ts +13 -0
- package/dist/constants/geo/subdivisions.js +104 -0
- package/dist/constants/index.d.ts +2 -2
- package/dist/constants/index.js +2 -2
- package/dist/constants/table-keys.d.ts +24 -0
- package/dist/constants/table-keys.js +28 -0
- package/dist/contracts/extend.d.ts +0 -9
- package/dist/contracts/index.d.ts +1 -1
- package/dist/contracts/realtime-session.js +7 -0
- package/dist/core/browser.d.ts +1 -1
- package/dist/core/browser.js +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/site-config.d.ts +0 -3
- package/dist/core/site-config.js +0 -3
- package/dist/errors/messages.d.ts +0 -8
- package/dist/errors/messages.js +0 -9
- package/dist/features/about/schemas/index.d.ts +8 -8
- package/dist/features/account/components/AddressFilters.js +32 -11
- package/dist/features/account/components/AddressForm.d.ts +26 -25
- package/dist/features/account/components/AddressForm.js +81 -103
- package/dist/features/account/components/AddressesIndexListing.js +8 -4
- package/dist/features/account/components/UserSidebar.d.ts +3 -4
- package/dist/features/account/components/UserSupportView.js +89 -58
- package/dist/features/account/components/index.d.ts +1 -7
- package/dist/features/account/components/index.js +0 -3
- package/dist/features/account/hooks/useAddresses.d.ts +4 -3
- package/dist/features/account/hooks/useAddresses.js +4 -6
- package/dist/features/account/hooks/useCollapsedSections.d.ts +51 -10
- package/dist/features/account/hooks/useCollapsedSections.js +211 -38
- package/dist/features/account/hooks/useProfile.d.ts +8 -0
- package/dist/features/account/index.d.ts +0 -3
- package/dist/features/account/index.js +0 -3
- package/dist/features/account/schemas/index.d.ts +0 -92
- package/dist/features/account/schemas/index.js +42 -20
- package/dist/features/addresses/components/AddressLocationFields.d.ts +13 -0
- package/dist/features/addresses/components/AddressLocationFields.js +41 -0
- package/dist/features/addresses/hooks/usePostalLookup.d.ts +17 -0
- package/dist/features/addresses/hooks/usePostalLookup.js +133 -0
- package/dist/features/addresses/schemas/address-form.d.ts +423 -0
- package/dist/features/addresses/schemas/address-form.js +212 -0
- package/dist/features/addresses/schemas/index.d.ts +1 -0
- package/dist/features/addresses/schemas/index.js +8 -0
- package/dist/features/admin/actions/admin-read-actions.d.ts +1 -1
- package/dist/features/admin/actions/index.d.ts +0 -1
- package/dist/features/admin/actions/index.js +0 -1
- package/dist/features/admin/actions/notification-actions.js +1 -41
- package/dist/features/admin/components/AdminActionIndexView.d.ts +32 -0
- package/dist/features/admin/components/AdminActionIndexView.js +128 -0
- package/dist/features/admin/components/AdminAdEditorView.js +159 -163
- package/dist/features/admin/components/AdminAddressEditorView.js +97 -55
- package/dist/features/admin/components/AdminBrandEditorView.d.ts +15 -0
- package/dist/features/admin/components/AdminBrandEditorView.js +113 -77
- package/dist/features/admin/components/AdminBundleEditorView.d.ts +19 -9
- package/dist/features/admin/components/AdminBundleEditorView.js +136 -168
- package/dist/features/admin/components/AdminCategoryEditorView.js +120 -43
- package/dist/features/admin/components/AdminCouponEditorView.js +145 -109
- package/dist/features/admin/components/AdminEmployeeEditorView.js +125 -56
- package/dist/features/admin/components/AdminFaqEditorView.js +112 -58
- package/dist/features/admin/components/AdminFeatureEditorView.js +108 -68
- package/dist/features/admin/components/AdminNavEditorView.js +69 -44
- package/dist/features/admin/components/AdminOrderEditorView.js +47 -10
- package/dist/features/admin/components/AdminPrizeDrawsView.js +16 -2
- package/dist/features/admin/components/AdminSidebar.d.ts +11 -7
- package/dist/features/admin/components/AdminSiteSettingsView.js +37 -37
- package/dist/features/admin/components/AdminStoreEditorView.js +75 -52
- package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +71 -30
- package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +95 -65
- package/dist/features/admin/components/BrandQuickCreateForm.d.ts +10 -0
- package/dist/features/admin/components/BrandQuickCreateForm.js +49 -26
- package/dist/features/admin/components/CategoryQuickCreateForm.d.ts +11 -0
- package/dist/features/admin/components/CategoryQuickCreateForm.js +48 -26
- package/dist/features/admin/components/index.d.ts +2 -2
- package/dist/features/admin/components/index.js +1 -1
- package/dist/features/admin/constants/site-settings-tabs.d.ts +120 -0
- package/dist/features/admin/constants/site-settings-tabs.js +152 -0
- package/dist/features/admin/index.d.ts +0 -3
- package/dist/features/admin/index.js +0 -2
- package/dist/features/admin/repository/analytics-rollup.repository.d.ts +35 -0
- package/dist/features/admin/repository/analytics-rollup.repository.js +30 -0
- package/dist/features/admin/schemas/admin-editor-forms.d.ts +56 -57
- package/dist/features/admin/schemas/admin-editor-forms.js +97 -54
- package/dist/features/admin/schemas/admin-ops-forms.d.ts +57 -5
- package/dist/features/admin/schemas/admin-ops-forms.js +104 -20
- package/dist/features/admin/schemas/admin-user-form.js +7 -0
- package/dist/features/admin/schemas/firestore.d.ts +48 -95
- package/dist/features/admin/schemas/firestore.js +15 -151
- package/dist/features/admin/schemas/nav-item-form.js +9 -2
- package/dist/features/admin/server.d.ts +0 -4
- package/dist/features/admin/server.js +0 -2
- package/dist/features/admin/types/index.d.ts +0 -7
- package/dist/features/analytics/repository/page-views.repository.d.ts +14 -0
- package/dist/features/analytics/repository/page-views.repository.js +24 -0
- package/dist/features/auth/actions/index.d.ts +0 -1
- package/dist/features/auth/actions/index.js +0 -1
- package/dist/features/auth/actions/realtime-token-actions.js +1 -12
- package/dist/features/auth/auth-helpers.js +5 -7
- package/dist/features/auth/components/Guards.js +2 -1
- package/dist/features/auth/components/LoginForm.d.ts +0 -2
- package/dist/features/auth/components/LoginForm.js +1 -3
- package/dist/features/auth/components/RegisterForm.js +62 -19
- package/dist/features/auth/permissions/constants.d.ts +27 -1
- package/dist/features/auth/role-predicates.d.ts +75 -7
- package/dist/features/auth/role-predicates.js +28 -2
- package/dist/features/auth/schemas/firestore.d.ts +22 -0
- package/dist/features/auth/schemas/index.d.ts +1 -1
- package/dist/features/auth/schemas/index.js +44 -8
- package/dist/features/auth/types/index.d.ts +14 -1
- package/dist/features/blog/api/route.js +10 -2
- package/dist/features/blog/components/BlogIndexListing.js +1 -1
- package/dist/features/blog/hooks/useBlog.js +2 -2
- package/dist/features/blog/schemas/index.d.ts +4 -0
- package/dist/features/blog/schemas/index.js +2 -0
- package/dist/features/blog/types/index.d.ts +1 -1
- package/dist/features/catalogue/components/CatalogueItemEditorView.d.ts +22 -0
- package/dist/features/catalogue/components/CatalogueItemEditorView.js +112 -52
- package/dist/features/catalogue/schemas/validation.d.ts +4 -4
- package/dist/features/catalogue/schemas/validation.js +47 -10
- package/dist/features/categories/schemas/bundle-form.d.ts +142 -0
- package/dist/features/categories/schemas/bundle-form.js +149 -0
- package/dist/features/classified/components/ClassifiedDetailPageView.d.ts +5 -4
- package/dist/features/classified/components/ClassifiedDetailPageView.js +37 -16
- package/dist/features/consultation/components/ConsultationForm.js +1 -1
- package/dist/features/consultation/schemas/index.js +34 -10
- package/dist/features/corporate/schemas/index.js +36 -15
- package/dist/features/filters/FilterPanel.js +3 -3
- package/dist/features/filters/RangeFilter.d.ts +10 -0
- package/dist/features/filters/RangeFilter.js +41 -4
- package/dist/features/homepage/components/MarketplaceHomepageView.js +24 -5
- package/dist/features/homepage/hooks/useBlogArticles.js +1 -1
- package/dist/features/layout/BottomActions.js +84 -11
- package/dist/features/layout/BottomActionsContext.d.ts +1 -6
- package/dist/features/layout/BottomActionsContext.js +1 -1
- package/dist/features/layout/hooks/useBottomActions.js +2 -2
- package/dist/features/layout/hooks/useFormBottomActions.d.ts +12 -1
- package/dist/features/layout/hooks/useFormBottomActions.js +12 -6
- package/dist/features/lottery/schemas/config-write.d.ts +9 -5
- package/dist/features/lottery/schemas/config-write.js +69 -9
- package/dist/features/orders/schemas/buyer-forms.d.ts +6 -3
- package/dist/features/orders/schemas/buyer-forms.js +31 -3
- package/dist/features/orders/schemas/index.d.ts +2 -2
- package/dist/features/products/components/GroupSettingsPanel.js +3 -1
- package/dist/features/products/components/MakeOfferButton.d.ts +13 -2
- package/dist/features/products/components/MakeOfferButton.js +33 -11
- package/dist/features/products/components/ProductDetailActions.js +0 -1
- package/dist/features/products/components/ProductDetailPageView.d.ts +7 -3
- package/dist/features/products/components/ProductDetailPageView.js +8 -5
- package/dist/features/products/constants/action-defs.d.ts +1 -2
- package/dist/features/products/constants/action-defs.js +40 -43
- package/dist/features/products/repository/products.repository.d.ts +5 -1
- package/dist/features/products/repository/products.repository.js +23 -1
- package/dist/features/products/schemas/firestore.d.ts +7 -3
- package/dist/features/products/schemas/product-features.validators.js +3 -0
- package/dist/features/promotions/components/CouponCard.js +8 -7
- package/dist/features/scams/schemas/firestore.d.ts +15 -1
- package/dist/features/scams/schemas/report-form.d.ts +5 -5
- package/dist/features/scams/schemas/report-form.js +18 -3
- package/dist/features/search/action-index/derive.d.ts +49 -0
- package/dist/features/search/action-index/derive.js +121 -0
- package/dist/features/search/action-index/repository.d.ts +42 -0
- package/dist/features/search/action-index/repository.js +100 -0
- package/dist/features/search/action-index/settings-entries.d.ts +41 -0
- package/dist/features/search/action-index/settings-entries.js +268 -0
- package/dist/features/search/action-index/types.d.ts +81 -0
- package/dist/features/search/action-index/types.js +102 -0
- package/dist/features/search/action-index/validate-entry.d.ts +34 -0
- package/dist/features/search/action-index/validate-entry.js +114 -0
- package/dist/features/search/hooks/useNavSuggestions.d.ts +5 -1
- package/dist/features/search/hooks/useNavSuggestions.js +23 -3
- package/dist/features/search/repository/search.repository.js +3 -1
- package/dist/features/seller/actions/offer-actions.js +43 -24
- package/dist/features/seller/actions/seller-actions.js +29 -5
- package/dist/features/seller/components/CategoryChipPicker.d.ts +9 -0
- package/dist/features/seller/components/CategoryChipPicker.js +12 -0
- package/dist/features/seller/components/SellerAddressesView.js +5 -1
- package/dist/features/seller/components/SellerAnalyticsAlertsView.js +83 -43
- package/dist/features/seller/components/SellerArtView.d.ts +14 -7
- package/dist/features/seller/components/SellerArtView.js +4 -119
- package/dist/features/seller/components/SellerClassifiedView.d.ts +14 -7
- package/dist/features/seller/components/SellerClassifiedView.js +4 -124
- package/dist/features/seller/components/SellerCouponEditorView.d.ts +22 -1
- package/dist/features/seller/components/SellerCouponEditorView.js +91 -45
- package/dist/features/seller/components/SellerDigitalCodesView.d.ts +14 -7
- package/dist/features/seller/components/SellerDigitalCodesView.js +4 -126
- package/dist/features/seller/components/SellerListingTypeView.d.ts +66 -0
- package/dist/features/seller/components/SellerListingTypeView.js +277 -0
- package/dist/features/seller/components/SellerLiveView.d.ts +14 -7
- package/dist/features/seller/components/SellerLiveView.js +4 -126
- package/dist/features/seller/components/SellerSidebar.d.ts +3 -6
- package/dist/features/seller/components/SellerStickersView.d.ts +14 -7
- package/dist/features/seller/components/SellerStickersView.js +4 -119
- package/dist/features/seller/components/SellerSupportView.d.ts +31 -0
- package/dist/features/seller/components/SellerSupportView.js +100 -0
- package/dist/features/seller/components/index.d.ts +4 -8
- package/dist/features/seller/components/index.js +2 -4
- package/dist/features/seller/index.d.ts +0 -1
- package/dist/features/seller/index.js +0 -1
- package/dist/features/seller/schemas/coupon-form.d.ts +214 -0
- package/dist/features/seller/schemas/coupon-form.js +155 -23
- package/dist/features/seller/schemas/offer-forms.d.ts +16 -7
- package/dist/features/seller/schemas/offer-forms.js +28 -12
- package/dist/features/shell/FormShell.js +2 -2
- package/dist/features/shell/QuickFormDrawer.js +2 -2
- package/dist/features/shell/SectionForm.d.ts +19 -1
- package/dist/features/shell/SectionForm.js +104 -17
- package/dist/features/shell/build-sections.d.ts +23 -0
- package/dist/features/shell/build-sections.js +106 -8
- package/dist/features/shell/field-ui-meta.d.ts +44 -0
- package/dist/features/shell/field-ui-meta.js +14 -7
- package/dist/features/shell/form-sections.d.ts +46 -0
- package/dist/features/shell/form-sections.js +114 -0
- package/dist/features/shipments/components/AdminShipmentEditorView.js +87 -64
- package/dist/features/shipments/schemas/validation.d.ts +2 -2
- package/dist/features/shipments/schemas/validation.js +44 -13
- package/dist/features/store-extensions/schemas/custom-role-form.js +6 -2
- package/dist/features/store-extensions/schemas/listing-template-form.d.ts +7 -7
- package/dist/features/store-extensions/schemas/payout-method-form.js +14 -0
- package/dist/features/stores/actions/store-query-actions.js +3 -2
- package/dist/features/stores/api/[storeSlug]/auctions/route.js +3 -1
- package/dist/features/stores/api/[storeSlug]/products/route.js +3 -1
- package/dist/features/support/repository/support.repository.d.ts +21 -0
- package/dist/features/support/repository/support.repository.js +63 -0
- package/dist/features/support/schemas/firestore.d.ts +27 -2
- package/dist/features/support/schemas/firestore.js +2 -0
- package/dist/features/support/schemas/ticket-create-form.js +7 -0
- package/dist/features/tester/schemas/checklist-item-form.d.ts +43 -0
- package/dist/features/tester/schemas/checklist-item-form.js +109 -0
- package/dist/features/tester/seed-data/blog-tester-seed-data.js +2 -2
- package/dist/features/tester/seed-data/categories-tester-seed-data.js +2 -2
- package/dist/features/tester/seed-data/events-tester-seed-data.js +5 -5
- package/dist/features/tester/seed-data/orders-tester-seed-data.js +2 -2
- package/dist/features/tester/seed-data/products-tester-seed-data.js +48 -49
- package/dist/features/tester/seed-data/stores-tester-seed-data.js +3 -3
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +275 -29
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +48 -12
- package/dist/http/api-handler.js +2 -1
- package/dist/index.d.ts +24 -103
- package/dist/index.js +33 -141
- package/dist/jobs.d.ts +1 -1
- package/dist/jobs.js +1 -1
- package/dist/monitoring/browser.d.ts +0 -2
- package/dist/monitoring/browser.js +12 -1
- package/dist/monitoring/index.d.ts +0 -2
- package/dist/monitoring/index.js +0 -1
- package/dist/next/api/routeHandler.js +6 -3
- package/dist/next/index.d.ts +7 -2
- package/dist/next/index.js +36 -1
- package/dist/next/middleware/index.d.ts +0 -2
- package/dist/next/middleware/index.js +0 -1
- package/dist/next/routing/route-map.d.ts +8 -7
- package/dist/next/routing/route-map.js +10 -3
- package/dist/providers/db-firebase/admin.js +15 -1
- package/dist/providers/db-firebase/sieve.d.ts +22 -0
- package/dist/react/hooks/useListingTypeFlags.d.ts +1 -1
- package/dist/react/hooks/useListingTypeFlags.js +1 -1
- package/dist/react/hooks/usePendingFilters.js +5 -3
- package/dist/react/hooks/usePendingTable.js +15 -3
- package/dist/repositories/index.d.ts +0 -1
- package/dist/repositories/index.js +0 -1
- package/dist/schemas/registry.d.ts +197 -232
- package/dist/schemas/registry.js +5 -6
- package/dist/schemas/webhooks/razorpay.d.ts +50 -50
- package/dist/security/authorization.d.ts +9 -0
- package/dist/security/authorization.js +16 -2
- package/dist/security/browser.d.ts +1 -3
- package/dist/security/browser.js +5 -2
- package/dist/security/index.d.ts +1 -3
- package/dist/security/index.js +19 -2
- package/dist/security/pii-encrypt.js +16 -0
- package/dist/security/pii-schemas.d.ts +0 -14
- package/dist/security/pii-schemas.js +7 -15
- package/dist/seed/_helpers/category-forest.js +2 -2
- package/dist/seed/_helpers/media.d.ts +19 -0
- package/dist/seed/_helpers/media.js +75 -0
- package/dist/seed/blog-posts-seed-data.js +17 -17
- package/dist/seed/carousel-slides-seed-data.js +7 -7
- package/dist/seed/cart-seed-data.js +13 -13
- package/dist/seed/categories-seed-data.js +10 -10
- package/dist/seed/events-seed-data.js +24 -24
- package/dist/seed/factories/product.factory.js +4 -4
- package/dist/seed/factories/store.factory.js +3 -3
- package/dist/seed/factories/user.factory.js +2 -2
- package/dist/seed/grouped-listings-seed-data.js +11 -11
- package/dist/seed/homepage-sections-seed-data.js +2 -2
- package/dist/seed/index.d.ts +0 -1
- package/dist/seed/index.js +0 -1
- package/dist/seed/manifest.d.ts +1 -1
- package/dist/seed/manifest.js +0 -5
- package/dist/seed/notifications-seed-data.js +20 -1
- package/dist/seed/orders-seed-data.js +2 -2
- package/dist/seed/products-art-seed-data.js +16 -16
- package/dist/seed/products-auctions-seed-data.js +34 -34
- package/dist/seed/products-classifieds-seed-data.js +35 -37
- package/dist/seed/products-digital-codes-seed-data.js +20 -20
- package/dist/seed/products-live-items-seed-data.js +11 -11
- package/dist/seed/products-preorders-seed-data.js +13 -13
- package/dist/seed/products-prize-draws-seed-data.js +43 -43
- package/dist/seed/products-standard-seed-data.js +54 -54
- package/dist/seed/products-stickers-seed-data.js +15 -15
- package/dist/seed/reviews-seed-data.js +4 -4
- package/dist/seed/scammers-seed-data.js +3 -3
- package/dist/seed/site-settings-seed-data.js +11 -24
- package/dist/seed/store-extensions-seed-data.js +10 -10
- package/dist/seed/stores-seed-data.js +11 -11
- package/dist/seed/support-tickets-seed-data.d.ts +14 -0
- package/dist/seed/support-tickets-seed-data.js +20 -1
- package/dist/seed/users-seed-data.js +20 -20
- package/dist/server-entry.d.ts +0 -1
- package/dist/server-entry.js +0 -1
- package/dist/server.d.ts +9 -6
- package/dist/server.js +7 -13
- package/dist/styles.css +248 -68
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/themes/default-dark.js +2 -2
- package/dist/tokens/themes/default-light.js +2 -2
- package/dist/tokens/tokens.css +24 -4
- package/dist/ui/components/ActionRow.d.ts +50 -0
- package/dist/ui/components/ActionRow.js +53 -0
- package/dist/ui/components/ActionRow.style.css +145 -0
- package/dist/ui/components/Drawer.d.ts +10 -0
- package/dist/ui/components/Drawer.js +2 -1
- package/dist/ui/components/FilterDrawer.js +4 -1
- package/dist/ui/components/FilterDrawer.style.css +6 -12
- package/dist/ui/components/FormActionBar.js +14 -1
- package/dist/ui/components/FormActionBar.style.css +12 -11
- package/dist/ui/components/ListingLayout.js +8 -1
- package/dist/ui/components/ListingLayout.style.css +6 -13
- package/dist/ui/components/Modal.d.ts +15 -1
- package/dist/ui/components/Modal.js +17 -3
- package/dist/ui/components/QuickCreateModal.js +2 -2
- package/dist/ui/components/QuickCreateModal.style.css +78 -84
- package/dist/ui/components/RecordDetailModal.js +2 -2
- package/dist/ui/components/SideDrawer.d.ts +8 -0
- package/dist/ui/components/SideDrawer.js +2 -1
- package/dist/ui/components/SideDrawer.style.css +6 -3
- package/dist/ui/components/SideModal.d.ts +11 -1
- package/dist/ui/components/SideModal.js +3 -2
- package/dist/ui/components/SideModal.style.css +14 -0
- package/dist/ui/components/Typography.style.css +33 -24
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/forms/FormShell.style.css +260 -311
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +1 -0
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.js +0 -1
- package/dist/validation/index.d.ts +1 -1
- package/dist/validation/index.js +1 -1
- package/dist/validation/schemas.d.ts +0 -19
- package/dist/validation/schemas.js +8 -19
- package/package.json +1 -1
- 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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
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
|
+
}
|