@whop/elements-react-native 0.1.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.
- package/README.md +179 -0
- package/android/build.gradle +64 -0
- package/android/consumer-rules.pro +3 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/java/com/whop/elements/WhopAddressSuggestionsModule.kt +102 -0
- package/android/src/main/java/com/whop/elements/WhopAuthSessionModule.kt +126 -0
- package/android/src/main/java/com/whop/elements/WhopElementsPackage.kt +39 -0
- package/android/src/main/java/com/whop/elements/WhopPayButtonManager.kt +74 -0
- package/android/src/main/java/com/whop/elements/WhopPayButtonPressEvent.kt +17 -0
- package/android/src/main/java/com/whop/elements/WhopPayButtonView.kt +178 -0
- package/android/src/main/java/com/whop/elements/WhopPlatformPayModule.kt +212 -0
- package/assets/whop-wordmark-dark.png +0 -0
- package/assets/whop-wordmark-dark@2x.png +0 -0
- package/assets/whop-wordmark-dark@3x.png +0 -0
- package/assets/whop-wordmark-light.png +0 -0
- package/assets/whop-wordmark-light@2x.png +0 -0
- package/assets/whop-wordmark-light@3x.png +0 -0
- package/ios/Package.swift +59 -0
- package/ios/Sources/ElementsReactNative/WhopAddressSuggestionsImpl.swift +189 -0
- package/ios/Sources/ElementsReactNative/WhopAuthSessionImpl.swift +106 -0
- package/ios/Sources/ElementsReactNative/WhopPayButtonImpl.swift +89 -0
- package/ios/Sources/ElementsReactNative/WhopPlatformPayImpl.swift +181 -0
- package/ios/generated/WhopAddressSuggestionsModule.h +11 -0
- package/ios/generated/WhopAddressSuggestionsModule.mm +46 -0
- package/ios/generated/WhopAuthSessionModule.h +11 -0
- package/ios/generated/WhopAuthSessionModule.mm +45 -0
- package/ios/generated/WhopElementsShims.h +35 -0
- package/ios/generated/WhopPayButtonComponentView.h +12 -0
- package/ios/generated/WhopPayButtonComponentView.mm +82 -0
- package/ios/generated/WhopPlatformPayModule.h +11 -0
- package/ios/generated/WhopPlatformPayModule.mm +51 -0
- package/lib/module/api/client.js +139 -0
- package/lib/module/api/client.js.map +1 -0
- package/lib/module/api/client.test.js +137 -0
- package/lib/module/api/client.test.js.map +1 -0
- package/lib/module/api/types.js +2 -0
- package/lib/module/api/types.js.map +1 -0
- package/lib/module/controller/actions.js +148 -0
- package/lib/module/controller/actions.js.map +1 -0
- package/lib/module/controller/actions.test.js +102 -0
- package/lib/module/controller/actions.test.js.map +1 -0
- package/lib/module/controller/store.js +158 -0
- package/lib/module/controller/store.js.map +1 -0
- package/lib/module/core/address/country-data.js +1370 -0
- package/lib/module/core/address/country-data.js.map +1 -0
- package/lib/module/core/address/country-name.js +38 -0
- package/lib/module/core/address/country-name.js.map +1 -0
- package/lib/module/core/address/country-names.generated.js +249 -0
- package/lib/module/core/address/country-names.generated.js.map +1 -0
- package/lib/module/core/address/engine.js +245 -0
- package/lib/module/core/address/engine.js.map +1 -0
- package/lib/module/core/address/engine.test.js +216 -0
- package/lib/module/core/address/engine.test.js.map +1 -0
- package/lib/module/core/address/form-state.js +409 -0
- package/lib/module/core/address/form-state.js.map +1 -0
- package/lib/module/core/address/form-state.test.js +516 -0
- package/lib/module/core/address/form-state.test.js.map +1 -0
- package/lib/module/core/address/places.js +36 -0
- package/lib/module/core/address/places.js.map +1 -0
- package/lib/module/core/address/required-coverage.test.js +57 -0
- package/lib/module/core/address/required-coverage.test.js.map +1 -0
- package/lib/module/core/address/suggest.js +102 -0
- package/lib/module/core/address/suggest.js.map +1 -0
- package/lib/module/core/address/suggest.test.js +156 -0
- package/lib/module/core/address/suggest.test.js.map +1 -0
- package/lib/module/core/address/use-suggestions.js +33 -0
- package/lib/module/core/address/use-suggestions.js.map +1 -0
- package/lib/module/core/payments/address-change.js +91 -0
- package/lib/module/core/payments/address-change.js.map +1 -0
- package/lib/module/core/payments/billing-merge.js +62 -0
- package/lib/module/core/payments/billing-merge.js.map +1 -0
- package/lib/module/core/payments/browser-info.js +42 -0
- package/lib/module/core/payments/browser-info.js.map +1 -0
- package/lib/module/core/payments/bt.js +151 -0
- package/lib/module/core/payments/bt.js.map +1 -0
- package/lib/module/core/payments/bt.test.js +23 -0
- package/lib/module/core/payments/bt.test.js.map +1 -0
- package/lib/module/core/payments/currency.js +37 -0
- package/lib/module/core/payments/currency.js.map +1 -0
- package/lib/module/core/payments/detail.js +159 -0
- package/lib/module/core/payments/detail.js.map +1 -0
- package/lib/module/core/payments/detail.test.js +225 -0
- package/lib/module/core/payments/detail.test.js.map +1 -0
- package/lib/module/core/payments/errors.js +115 -0
- package/lib/module/core/payments/errors.js.map +1 -0
- package/lib/module/core/payments/mint.js +89 -0
- package/lib/module/core/payments/mint.js.map +1 -0
- package/lib/module/core/payments/plan.js +131 -0
- package/lib/module/core/payments/plan.js.map +1 -0
- package/lib/module/core/payments/refusals.js +17 -0
- package/lib/module/core/payments/refusals.js.map +1 -0
- package/lib/module/core/payments/secure-fields.js +87 -0
- package/lib/module/core/payments/secure-fields.js.map +1 -0
- package/lib/module/core/payments/tax-id-catalog.js +616 -0
- package/lib/module/core/payments/tax-id-catalog.js.map +1 -0
- package/lib/module/core/payments/wallet-contact.js +42 -0
- package/lib/module/core/payments/wallet-contact.js.map +1 -0
- package/lib/module/core/payments/wallet-contact.test.js +77 -0
- package/lib/module/core/payments/wallet-contact.test.js.map +1 -0
- package/lib/module/elements/address.js +467 -0
- package/lib/module/elements/address.js.map +1 -0
- package/lib/module/elements/branding.js +114 -0
- package/lib/module/elements/branding.js.map +1 -0
- package/lib/module/elements/card-fields/context.js +254 -0
- package/lib/module/elements/card-fields/context.js.map +1 -0
- package/lib/module/elements/card-fields/fields.js +309 -0
- package/lib/module/elements/card-fields/fields.js.map +1 -0
- package/lib/module/elements/card-fields/index.js +30 -0
- package/lib/module/elements/card-fields/index.js.map +1 -0
- package/lib/module/elements/card.js +107 -0
- package/lib/module/elements/card.js.map +1 -0
- package/lib/module/elements/email.js +84 -0
- package/lib/module/elements/email.js.map +1 -0
- package/lib/module/elements/payment/declared-fields.js +186 -0
- package/lib/module/elements/payment/declared-fields.js.map +1 -0
- package/lib/module/elements/payment/index.js +448 -0
- package/lib/module/elements/payment/index.js.map +1 -0
- package/lib/module/elements/payment/wallet.js +132 -0
- package/lib/module/elements/payment/wallet.js.map +1 -0
- package/lib/module/elements/tax-id.js +100 -0
- package/lib/module/elements/tax-id.js.map +1 -0
- package/lib/module/i18n/catalogs.js +103 -0
- package/lib/module/i18n/catalogs.js.map +1 -0
- package/lib/module/i18n/index.js +45 -0
- package/lib/module/i18n/index.js.map +1 -0
- package/lib/module/index.js +27 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/namespace.js +174 -0
- package/lib/module/namespace.js.map +1 -0
- package/lib/module/native/index.js +128 -0
- package/lib/module/native/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/provider.js +56 -0
- package/lib/module/provider.js.map +1 -0
- package/lib/module/specs/NativeWhopAddressSuggestions.js +6 -0
- package/lib/module/specs/NativeWhopAddressSuggestions.js.map +1 -0
- package/lib/module/specs/NativeWhopAuthSession.js +10 -0
- package/lib/module/specs/NativeWhopAuthSession.js.map +1 -0
- package/lib/module/specs/NativeWhopPlatformPay.js +10 -0
- package/lib/module/specs/NativeWhopPlatformPay.js.map +1 -0
- package/lib/module/specs/WhopPayButtonNativeComponent.ts +22 -0
- package/lib/module/theme/appearance.js +85 -0
- package/lib/module/theme/appearance.js.map +1 -0
- package/lib/module/theme/appearance.test.js +124 -0
- package/lib/module/theme/appearance.test.js.map +1 -0
- package/lib/module/theme/provider.js +25 -0
- package/lib/module/theme/provider.js.map +1 -0
- package/lib/module/theme/resolve.js +69 -0
- package/lib/module/theme/resolve.js.map +1 -0
- package/lib/module/theme/scales.generated.js +419 -0
- package/lib/module/theme/scales.generated.js.map +1 -0
- package/lib/module/ui/element-frame.js +83 -0
- package/lib/module/ui/element-frame.js.map +1 -0
- package/lib/module/ui/payment-method-icon.js +69 -0
- package/lib/module/ui/payment-method-icon.js.map +1 -0
- package/lib/module/ui/primitives.js +266 -0
- package/lib/module/ui/primitives.js.map +1 -0
- package/lib/module/ui/select.js +281 -0
- package/lib/module/ui/select.js.map +1 -0
- package/lib/module/ui/suggestions.js +71 -0
- package/lib/module/ui/suggestions.js.map +1 -0
- package/lib/module/ui/whop-logo.js +42 -0
- package/lib/module/ui/whop-logo.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/api/client.d.ts +87 -0
- package/lib/typescript/src/api/client.d.ts.map +1 -0
- package/lib/typescript/src/api/types.d.ts +175 -0
- package/lib/typescript/src/api/types.d.ts.map +1 -0
- package/lib/typescript/src/controller/actions.d.ts +42 -0
- package/lib/typescript/src/controller/actions.d.ts.map +1 -0
- package/lib/typescript/src/controller/store.d.ts +90 -0
- package/lib/typescript/src/controller/store.d.ts.map +1 -0
- package/lib/typescript/src/core/address/country-data.d.ts +4 -0
- package/lib/typescript/src/core/address/country-data.d.ts.map +1 -0
- package/lib/typescript/src/core/address/country-name.d.ts +2 -0
- package/lib/typescript/src/core/address/country-name.d.ts.map +1 -0
- package/lib/typescript/src/core/address/country-names.generated.d.ts +2 -0
- package/lib/typescript/src/core/address/country-names.generated.d.ts.map +1 -0
- package/lib/typescript/src/core/address/engine.d.ts +97 -0
- package/lib/typescript/src/core/address/engine.d.ts.map +1 -0
- package/lib/typescript/src/core/address/form-state.d.ts +144 -0
- package/lib/typescript/src/core/address/form-state.d.ts.map +1 -0
- package/lib/typescript/src/core/address/places.d.ts +23 -0
- package/lib/typescript/src/core/address/places.d.ts.map +1 -0
- package/lib/typescript/src/core/address/suggest.d.ts +47 -0
- package/lib/typescript/src/core/address/suggest.d.ts.map +1 -0
- package/lib/typescript/src/core/address/use-suggestions.d.ts +3 -0
- package/lib/typescript/src/core/address/use-suggestions.d.ts.map +1 -0
- package/lib/typescript/src/core/payments/address-change.d.ts +52 -0
- package/lib/typescript/src/core/payments/address-change.d.ts.map +1 -0
- package/lib/typescript/src/core/payments/billing-merge.d.ts +39 -0
- package/lib/typescript/src/core/payments/billing-merge.d.ts.map +1 -0
- package/lib/typescript/src/core/payments/browser-info.d.ts +12 -0
- package/lib/typescript/src/core/payments/browser-info.d.ts.map +1 -0
- package/lib/typescript/src/core/payments/bt.d.ts +55 -0
- package/lib/typescript/src/core/payments/bt.d.ts.map +1 -0
- package/lib/typescript/src/core/payments/currency.d.ts +7 -0
- package/lib/typescript/src/core/payments/currency.d.ts.map +1 -0
- package/lib/typescript/src/core/payments/detail.d.ts +53 -0
- package/lib/typescript/src/core/payments/detail.d.ts.map +1 -0
- package/lib/typescript/src/core/payments/errors.d.ts +62 -0
- package/lib/typescript/src/core/payments/errors.d.ts.map +1 -0
- package/lib/typescript/src/core/payments/mint.d.ts +74 -0
- package/lib/typescript/src/core/payments/mint.d.ts.map +1 -0
- package/lib/typescript/src/core/payments/plan.d.ts +69 -0
- package/lib/typescript/src/core/payments/plan.d.ts.map +1 -0
- package/lib/typescript/src/core/payments/refusals.d.ts +12 -0
- package/lib/typescript/src/core/payments/refusals.d.ts.map +1 -0
- package/lib/typescript/src/core/payments/secure-fields.d.ts +33 -0
- package/lib/typescript/src/core/payments/secure-fields.d.ts.map +1 -0
- package/lib/typescript/src/core/payments/tax-id-catalog.d.ts +481 -0
- package/lib/typescript/src/core/payments/tax-id-catalog.d.ts.map +1 -0
- package/lib/typescript/src/core/payments/wallet-contact.d.ts +40 -0
- package/lib/typescript/src/core/payments/wallet-contact.d.ts.map +1 -0
- package/lib/typescript/src/elements/address.d.ts +55 -0
- package/lib/typescript/src/elements/address.d.ts.map +1 -0
- package/lib/typescript/src/elements/branding.d.ts +18 -0
- package/lib/typescript/src/elements/branding.d.ts.map +1 -0
- package/lib/typescript/src/elements/card-fields/context.d.ts +67 -0
- package/lib/typescript/src/elements/card-fields/context.d.ts.map +1 -0
- package/lib/typescript/src/elements/card-fields/fields.d.ts +15 -0
- package/lib/typescript/src/elements/card-fields/fields.d.ts.map +1 -0
- package/lib/typescript/src/elements/card-fields/index.d.ts +21 -0
- package/lib/typescript/src/elements/card-fields/index.d.ts.map +1 -0
- package/lib/typescript/src/elements/card.d.ts +21 -0
- package/lib/typescript/src/elements/card.d.ts.map +1 -0
- package/lib/typescript/src/elements/email.d.ts +31 -0
- package/lib/typescript/src/elements/email.d.ts.map +1 -0
- package/lib/typescript/src/elements/payment/declared-fields.d.ts +43 -0
- package/lib/typescript/src/elements/payment/declared-fields.d.ts.map +1 -0
- package/lib/typescript/src/elements/payment/index.d.ts +37 -0
- package/lib/typescript/src/elements/payment/index.d.ts.map +1 -0
- package/lib/typescript/src/elements/payment/wallet.d.ts +39 -0
- package/lib/typescript/src/elements/payment/wallet.d.ts.map +1 -0
- package/lib/typescript/src/elements/tax-id.d.ts +41 -0
- package/lib/typescript/src/elements/tax-id.d.ts.map +1 -0
- package/lib/typescript/src/i18n/catalogs.d.ts +7 -0
- package/lib/typescript/src/i18n/catalogs.d.ts.map +1 -0
- package/lib/typescript/src/i18n/index.d.ts +17 -0
- package/lib/typescript/src/i18n/index.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +42 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/namespace.d.ts +36 -0
- package/lib/typescript/src/namespace.d.ts.map +1 -0
- package/lib/typescript/src/native/index.d.ts +62 -0
- package/lib/typescript/src/native/index.d.ts.map +1 -0
- package/lib/typescript/src/provider.d.ts +37 -0
- package/lib/typescript/src/provider.d.ts.map +1 -0
- package/lib/typescript/src/specs/NativeWhopAddressSuggestions.d.ts +13 -0
- package/lib/typescript/src/specs/NativeWhopAddressSuggestions.d.ts.map +1 -0
- package/lib/typescript/src/specs/NativeWhopAuthSession.d.ts +20 -0
- package/lib/typescript/src/specs/NativeWhopAuthSession.d.ts.map +1 -0
- package/lib/typescript/src/specs/NativeWhopPlatformPay.d.ts +24 -0
- package/lib/typescript/src/specs/NativeWhopPlatformPay.d.ts.map +1 -0
- package/lib/typescript/src/specs/WhopPayButtonNativeComponent.d.ts +21 -0
- package/lib/typescript/src/specs/WhopPayButtonNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/theme/appearance.d.ts +71 -0
- package/lib/typescript/src/theme/appearance.d.ts.map +1 -0
- package/lib/typescript/src/theme/provider.d.ts +11 -0
- package/lib/typescript/src/theme/provider.d.ts.map +1 -0
- package/lib/typescript/src/theme/resolve.d.ts +19 -0
- package/lib/typescript/src/theme/resolve.d.ts.map +1 -0
- package/lib/typescript/src/theme/scales.generated.d.ts +18 -0
- package/lib/typescript/src/theme/scales.generated.d.ts.map +1 -0
- package/lib/typescript/src/ui/element-frame.d.ts +32 -0
- package/lib/typescript/src/ui/element-frame.d.ts.map +1 -0
- package/lib/typescript/src/ui/payment-method-icon.d.ts +21 -0
- package/lib/typescript/src/ui/payment-method-icon.d.ts.map +1 -0
- package/lib/typescript/src/ui/primitives.d.ts +94 -0
- package/lib/typescript/src/ui/primitives.d.ts.map +1 -0
- package/lib/typescript/src/ui/select.d.ts +25 -0
- package/lib/typescript/src/ui/select.d.ts.map +1 -0
- package/lib/typescript/src/ui/suggestions.d.ts +15 -0
- package/lib/typescript/src/ui/suggestions.d.ts.map +1 -0
- package/lib/typescript/src/ui/whop-logo.d.ts +4 -0
- package/lib/typescript/src/ui/whop-logo.d.ts.map +1 -0
- package/package.json +121 -0
- package/scripts/check-swift.sh +27 -0
- package/scripts/codegen-shims.mjs +409 -0
- package/scripts/gen-country-names.mjs +58 -0
- package/scripts/gen-theme.mjs +124 -0
- package/scripts/gen-wordmark.mjs +68 -0
- package/scripts/mirror.mjs +112 -0
- package/src/api/client.ts +202 -0
- package/src/api/types.ts +166 -0
- package/src/controller/actions.ts +197 -0
- package/src/controller/store.ts +201 -0
- package/src/core/address/country-data.ts +927 -0
- package/src/core/address/country-name.ts +36 -0
- package/src/core/address/country-names.generated.ts +246 -0
- package/src/core/address/engine.ts +349 -0
- package/src/core/address/form-state.ts +479 -0
- package/src/core/address/places.ts +39 -0
- package/src/core/address/suggest.ts +153 -0
- package/src/core/address/use-suggestions.ts +37 -0
- package/src/core/payments/address-change.ts +121 -0
- package/src/core/payments/billing-merge.ts +91 -0
- package/src/core/payments/browser-info.ts +43 -0
- package/src/core/payments/bt.ts +176 -0
- package/src/core/payments/currency.ts +54 -0
- package/src/core/payments/detail.ts +204 -0
- package/src/core/payments/errors.ts +171 -0
- package/src/core/payments/mint.ts +130 -0
- package/src/core/payments/plan.ts +198 -0
- package/src/core/payments/refusals.ts +24 -0
- package/src/core/payments/secure-fields.ts +85 -0
- package/src/core/payments/tax-id-catalog.ts +320 -0
- package/src/core/payments/wallet-contact.ts +56 -0
- package/src/elements/address.tsx +570 -0
- package/src/elements/branding.tsx +87 -0
- package/src/elements/card-fields/context.tsx +310 -0
- package/src/elements/card-fields/fields.tsx +281 -0
- package/src/elements/card-fields/index.tsx +37 -0
- package/src/elements/card.tsx +101 -0
- package/src/elements/email.tsx +100 -0
- package/src/elements/payment/declared-fields.tsx +238 -0
- package/src/elements/payment/index.tsx +497 -0
- package/src/elements/payment/wallet.tsx +155 -0
- package/src/elements/tax-id.tsx +143 -0
- package/src/i18n/catalogs.ts +100 -0
- package/src/i18n/index.tsx +46 -0
- package/src/index.ts +68 -0
- package/src/namespace.tsx +231 -0
- package/src/native/index.ts +173 -0
- package/src/provider.tsx +76 -0
- package/src/specs/NativeWhopAddressSuggestions.ts +14 -0
- package/src/specs/NativeWhopAuthSession.ts +21 -0
- package/src/specs/NativeWhopPlatformPay.ts +25 -0
- package/src/specs/WhopPayButtonNativeComponent.ts +22 -0
- package/src/theme/appearance.ts +150 -0
- package/src/theme/provider.tsx +28 -0
- package/src/theme/resolve.ts +68 -0
- package/src/theme/scales.generated.ts +427 -0
- package/src/ui/element-frame.tsx +94 -0
- package/src/ui/payment-method-icon.tsx +55 -0
- package/src/ui/primitives.tsx +269 -0
- package/src/ui/select.tsx +255 -0
- package/src/ui/suggestions.tsx +69 -0
- package/src/ui/whop-logo.tsx +37 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
|
+
import COUNTRY_CATALOG from "./country-data.js";
|
|
5
|
+
import { parseCountryFormat } from "./engine.js";
|
|
6
|
+
import { planFields } from "./form-state.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Every key `planFields` can mark required, across every country in the catalog and every config
|
|
10
|
+
* permutation the element exposes.
|
|
11
|
+
*
|
|
12
|
+
* The element renders from this vocabulary, and a required key with no field to type it into is a
|
|
13
|
+
* form the buyer can never complete — which is exactly how `line1` and the custom fields shipped
|
|
14
|
+
* broken. Adding a key here without adding its renderer breaks this test on purpose.
|
|
15
|
+
*/
|
|
16
|
+
const RENDERED_KEYS = ['country', 'name', 'first_name', 'last_name', 'organization', 'line1', 'city', 'state', 'postal_code', 'custom:tax_id'];
|
|
17
|
+
const CUSTOM = [{
|
|
18
|
+
key: 'tax_id',
|
|
19
|
+
label: 'Tax ID',
|
|
20
|
+
type: 'text',
|
|
21
|
+
position: 'after_address',
|
|
22
|
+
required: true
|
|
23
|
+
}];
|
|
24
|
+
function configs() {
|
|
25
|
+
const out = [];
|
|
26
|
+
for (const scope of ['full', 'minimal']) {
|
|
27
|
+
for (const name of ['combined', 'split', 'none']) {
|
|
28
|
+
for (const organization of ['name', 'name_with_type', 'none']) {
|
|
29
|
+
out.push({
|
|
30
|
+
mode: 'billing',
|
|
31
|
+
layout: 'compact',
|
|
32
|
+
scope,
|
|
33
|
+
name,
|
|
34
|
+
organization,
|
|
35
|
+
line2: 'toggle',
|
|
36
|
+
autocomplete: false,
|
|
37
|
+
customFields: CUSTOM,
|
|
38
|
+
requiredFloor: ['name', 'organization', 'line1', 'city', 'state', 'postal_code']
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
describe('required-field coverage', () => {
|
|
46
|
+
it('never requires a key the element has no field for', () => {
|
|
47
|
+
const seen = new Set();
|
|
48
|
+
for (const country of Object.keys(COUNTRY_CATALOG)) {
|
|
49
|
+
const format = parseCountryFormat(country, COUNTRY_CATALOG[country]);
|
|
50
|
+
for (const config of configs()) {
|
|
51
|
+
for (const key of planFields(config, format).required) seen.add(key);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
expect([...seen].sort()).toEqual([...RENDERED_KEYS].sort());
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
//# sourceMappingURL=required-coverage.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["describe","expect","it","COUNTRY_CATALOG","parseCountryFormat","planFields","RENDERED_KEYS","CUSTOM","key","label","type","position","required","configs","out","scope","name","organization","push","mode","layout","line2","autocomplete","customFields","requiredFloor","seen","Set","country","Object","keys","format","config","add","sort","toEqual"],"sourceRoot":"../../../../src","sources":["core/address/required-coverage.test.ts"],"mappings":";;AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,QAAQ;AAE7C,OAAOC,eAAe,MAAM,mBAAgB;AAC5C,SAASC,kBAAkB,QAAQ,aAAU;AAC7C,SAAuDC,UAAU,QAAQ,iBAAc;;AAEvF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,aAAa,GAAG,CACrB,SAAS,EACT,MAAM,EACN,YAAY,EACZ,WAAW,EACX,cAAc,EACd,OAAO,EACP,MAAM,EACN,OAAO,EACP,aAAa,EACb,eAAe,CACN;AAEV,MAAMC,MAAyB,GAAG,CACjC;EAAEC,GAAG,EAAE,QAAQ;EAAEC,KAAK,EAAE,QAAQ;EAAEC,IAAI,EAAE,MAAM;EAAEC,QAAQ,EAAE,eAAe;EAAEC,QAAQ,EAAE;AAAK,CAAC,CAC3F;AAED,SAASC,OAAOA,CAAA,EAAwB;EACvC,MAAMC,GAAwB,GAAG,EAAE;EACnC,KAAK,MAAMC,KAAK,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,EAAW;IACjD,KAAK,MAAMC,IAAI,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,EAAW;MAC1D,KAAK,MAAMC,YAAY,IAAI,CAAC,MAAM,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAW;QACvEH,GAAG,CAACI,IAAI,CAAC;UACRC,IAAI,EAAE,SAAS;UACfC,MAAM,EAAE,SAAS;UACjBL,KAAK;UACLC,IAAI;UACJC,YAAY;UACZI,KAAK,EAAE,QAAQ;UACfC,YAAY,EAAE,KAAK;UACnBC,YAAY,EAAEhB,MAAM;UACpBiB,aAAa,EAAE,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa;QAChF,CAAC,CAAC;MACH;IACD;EACD;EACA,OAAOV,GAAG;AACX;AAEAd,QAAQ,CAAC,yBAAyB,EAAE,MAAM;EACzCE,EAAE,CAAC,mDAAmD,EAAE,MAAM;IAC7D,MAAMuB,IAAI,GAAG,IAAIC,GAAG,CAAS,CAAC;IAC9B,KAAK,MAAMC,OAAO,IAAIC,MAAM,CAACC,IAAI,CAAC1B,eAAe,CAAC,EAAE;MACnD,MAAM2B,MAAM,GAAG1B,kBAAkB,CAACuB,OAAO,EAAExB,eAAe,CAACwB,OAAO,CAAC,CAAC;MACpE,KAAK,MAAMI,MAAM,IAAIlB,OAAO,CAAC,CAAC,EAAE;QAC/B,KAAK,MAAML,GAAG,IAAIH,UAAU,CAAC0B,MAAM,EAAED,MAAM,CAAC,CAAClB,QAAQ,EAAEa,IAAI,CAACO,GAAG,CAACxB,GAAG,CAAC;MACrE;IACD;IACAP,MAAM,CAAC,CAAC,GAAGwB,IAAI,CAAC,CAACQ,IAAI,CAAC,CAAC,CAAC,CAACC,OAAO,CAAC,CAAC,GAAG5B,aAAa,CAAC,CAAC2B,IAAI,CAAC,CAAC,CAAC;EAC5D,CAAC,CAAC;AACH,CAAC,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/** One row in the suggestion list. Display only — components arrive from `resolve`. */
|
|
4
|
+
|
|
5
|
+
/** The raw components a resolved pick carries, before per-country composition. */
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Where the house number leads the street name. Everywhere else it trails, and emitting
|
|
9
|
+
* "77 Unter den Linden" for a Berlin address is both wrong and an AVS mismatch.
|
|
10
|
+
*
|
|
11
|
+
* Both platform geocoders hand back the number and the street as separate components without an
|
|
12
|
+
* opinion on order, so this table is the only thing that decides it — which is why it lives here
|
|
13
|
+
* once rather than in Swift and Kotlin twice.
|
|
14
|
+
*/
|
|
15
|
+
const NUMBER_FIRST = new Set(['US', 'CA', 'GB', 'IE', 'AU', 'NZ', 'IN', 'PH', 'MY', 'SG', 'ZA', 'JP', 'CN', 'KR', 'TW', 'HK', 'TH', 'VN', 'ID']);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Empty string is NOT absence, and the reducer cannot tell the difference: `apply-place` does
|
|
19
|
+
* `line1: parsed.line1 ?? state.values.line1`, so an empty line1 would REPLACE the street the
|
|
20
|
+
* buyer already typed, and `country: parsed.country ?? state.country` would blank the country.
|
|
21
|
+
* Both geocoders return "" for missing components, so this normalization is load-bearing.
|
|
22
|
+
*/
|
|
23
|
+
function present(value) {
|
|
24
|
+
const trimmed = value?.trim();
|
|
25
|
+
return trimmed ? trimmed : undefined;
|
|
26
|
+
}
|
|
27
|
+
export function composeLine1(streetNumber, street, country) {
|
|
28
|
+
const number = present(streetNumber);
|
|
29
|
+
const name = present(street);
|
|
30
|
+
if (!name) return number;
|
|
31
|
+
if (!number) return name;
|
|
32
|
+
return NUMBER_FIRST.has((country ?? '').toUpperCase()) ? `${number} ${name}` : `${name} ${number}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** The suggestion rows a `suggest` call returned. */
|
|
36
|
+
export function parseSuggestions(json) {
|
|
37
|
+
let rows;
|
|
38
|
+
try {
|
|
39
|
+
rows = JSON.parse(json);
|
|
40
|
+
} catch {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
if (!Array.isArray(rows)) return [];
|
|
44
|
+
return rows.filter(row => typeof row === 'object' && row !== null && typeof row.id === 'string' && typeof row.label === 'string').filter(row => row.id.length > 0 && row.label.length > 0);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* A resolved pick, in the wire keys the address form emits.
|
|
49
|
+
*
|
|
50
|
+
* `formCountry` backfills a resolve that names no country, which both geocoders do occasionally.
|
|
51
|
+
* Without it `composeLine1` orders the street as if it were number-last, and `placeAllowed` rejects
|
|
52
|
+
* a country-less parse whenever an allow list is active — so the pick silently no-ops.
|
|
53
|
+
*/
|
|
54
|
+
export function parseComponents(json, formCountry) {
|
|
55
|
+
let raw;
|
|
56
|
+
try {
|
|
57
|
+
raw = JSON.parse(json);
|
|
58
|
+
} catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
if (typeof raw !== 'object' || raw === null) return null;
|
|
62
|
+
const row = raw;
|
|
63
|
+
const country = present(row.country)?.toUpperCase() ?? present(formCountry)?.toUpperCase();
|
|
64
|
+
const line1 = composeLine1(row.streetNumber, row.street, country) ?? present(row.line1);
|
|
65
|
+
// Without a street the whole-replace in `apply-place` would clear the grid in exchange for
|
|
66
|
+
// nothing, so a componentless resolve declines instead.
|
|
67
|
+
if (!line1) return null;
|
|
68
|
+
return {
|
|
69
|
+
line1,
|
|
70
|
+
city: present(row.city),
|
|
71
|
+
state: present(row.state),
|
|
72
|
+
postal_code: present(row.postalCode),
|
|
73
|
+
country
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* A geocoder's subdivision, as the catalog key the address engine validates against.
|
|
79
|
+
*
|
|
80
|
+
* The engine keys subdivisions by `sub_key` and builds each option's display name by joining the
|
|
81
|
+
* native and latin names — `[names[i] || key, latinNames[i]].join(' — ')` at
|
|
82
|
+
* core/address/engine.ts:141, so Tokyo's option is key `東京都` and name `東京都 — Tokyo`. A geocoder
|
|
83
|
+
* answers with ONE of those halves and never the joined form, so matching the whole `name` string
|
|
84
|
+
* misses every country whose catalog carries both scripts.
|
|
85
|
+
*
|
|
86
|
+
* An unmatched value resolves to undefined rather than to itself: it would render the state Select
|
|
87
|
+
* on its placeholder while still being emitted, so `apply-place` writing '' and surfacing the
|
|
88
|
+
* required-state error is the honest outcome.
|
|
89
|
+
*/
|
|
90
|
+
export function resolveSubdivision(value, options) {
|
|
91
|
+
const wanted = present(value)?.toLowerCase();
|
|
92
|
+
if (!wanted) return undefined;
|
|
93
|
+
if (options.length === 0) return present(value);
|
|
94
|
+
return options.find(option => subdivisionAliases(option).includes(wanted))?.key;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Kept identical to the separator engine.ts:141 joins with. */
|
|
98
|
+
const NAME_SEPARATOR = ' — ';
|
|
99
|
+
function subdivisionAliases(option) {
|
|
100
|
+
return [option.key, option.iso, option.name, ...option.name.split(NAME_SEPARATOR)].map(part => present(part)?.toLowerCase()).filter(part => part !== undefined);
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=suggest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["NUMBER_FIRST","Set","present","value","trimmed","trim","undefined","composeLine1","streetNumber","street","country","number","name","has","toUpperCase","parseSuggestions","json","rows","JSON","parse","Array","isArray","filter","row","id","label","length","parseComponents","formCountry","raw","line1","city","state","postal_code","postalCode","resolveSubdivision","options","wanted","toLowerCase","find","option","subdivisionAliases","includes","key","NAME_SEPARATOR","iso","split","map","part"],"sourceRoot":"../../../../src","sources":["core/address/suggest.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
|
+
import { composeLine1, parseComponents, parseSuggestions, resolveSubdivision } from "./suggest.js";
|
|
5
|
+
describe('composeLine1', () => {
|
|
6
|
+
it('puts the number first in number-first countries', () => {
|
|
7
|
+
expect(composeLine1('1600', 'Amphitheatre Parkway', 'US')).toBe('1600 Amphitheatre Parkway');
|
|
8
|
+
expect(composeLine1('10', 'Downing Street', 'GB')).toBe('10 Downing Street');
|
|
9
|
+
});
|
|
10
|
+
it('puts the number last everywhere else', () => {
|
|
11
|
+
expect(composeLine1('77', 'Unter den Linden', 'DE')).toBe('Unter den Linden 77');
|
|
12
|
+
expect(composeLine1('12', 'Rue de Rivoli', 'FR')).toBe('Rue de Rivoli 12');
|
|
13
|
+
});
|
|
14
|
+
it('falls back to whichever half exists', () => {
|
|
15
|
+
expect(composeLine1(undefined, 'Broadway', 'US')).toBe('Broadway');
|
|
16
|
+
expect(composeLine1('42', undefined, 'US')).toBe('42');
|
|
17
|
+
expect(composeLine1(undefined, undefined, 'US')).toBeUndefined();
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
describe('parseSuggestions', () => {
|
|
21
|
+
it('keeps rows that carry both an id and a label', () => {
|
|
22
|
+
const rows = parseSuggestions(JSON.stringify([{
|
|
23
|
+
id: 'a\nAustin, TX',
|
|
24
|
+
label: '1 A St, Austin, TX'
|
|
25
|
+
}, {
|
|
26
|
+
id: '',
|
|
27
|
+
label: 'no id'
|
|
28
|
+
}, {
|
|
29
|
+
id: 'b',
|
|
30
|
+
label: ''
|
|
31
|
+
}, {
|
|
32
|
+
id: 'c'
|
|
33
|
+
}, null]));
|
|
34
|
+
expect(rows).toEqual([{
|
|
35
|
+
id: 'a\nAustin, TX',
|
|
36
|
+
label: '1 A St, Austin, TX'
|
|
37
|
+
}]);
|
|
38
|
+
});
|
|
39
|
+
it('survives anything the bridge hands back', () => {
|
|
40
|
+
expect(parseSuggestions('not json')).toEqual([]);
|
|
41
|
+
expect(parseSuggestions('{}')).toEqual([]);
|
|
42
|
+
expect(parseSuggestions('[]')).toEqual([]);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe('parseComponents', () => {
|
|
46
|
+
it('composes line1 by the resolved country', () => {
|
|
47
|
+
const us = parseComponents(JSON.stringify({
|
|
48
|
+
streetNumber: '1600',
|
|
49
|
+
street: 'Amphitheatre Pkwy',
|
|
50
|
+
country: 'US'
|
|
51
|
+
}));
|
|
52
|
+
expect(us?.line1).toBe('1600 Amphitheatre Pkwy');
|
|
53
|
+
const de = parseComponents(JSON.stringify({
|
|
54
|
+
streetNumber: '77',
|
|
55
|
+
street: 'Unter den Linden',
|
|
56
|
+
country: 'DE'
|
|
57
|
+
}));
|
|
58
|
+
expect(de?.line1).toBe('Unter den Linden 77');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// A country-less resolve is otherwise doubly broken: ordered number-last whatever the form says,
|
|
62
|
+
// and rejected by placeAllowed whenever an allow list is active, so the pick silently no-ops.
|
|
63
|
+
it('falls back to the form country when the platform names none', () => {
|
|
64
|
+
const row = parseComponents(JSON.stringify({
|
|
65
|
+
streetNumber: '1600',
|
|
66
|
+
street: 'Amphitheatre Pkwy'
|
|
67
|
+
}), 'US');
|
|
68
|
+
expect(row?.line1).toBe('1600 Amphitheatre Pkwy');
|
|
69
|
+
expect(row?.country).toBe('US');
|
|
70
|
+
});
|
|
71
|
+
it('never overrides a country the platform did report', () => {
|
|
72
|
+
expect(parseComponents(JSON.stringify({
|
|
73
|
+
street: 'A St',
|
|
74
|
+
country: 'ca'
|
|
75
|
+
}), 'US')?.country).toBe('CA');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// The reducer does `line1: parsed.line1 ?? state.values.line1` and `city: parsed.city ?? ''`,
|
|
79
|
+
// so an empty string here would wipe a typed street rather than leave it alone.
|
|
80
|
+
it('turns empty strings into absence', () => {
|
|
81
|
+
const row = parseComponents(JSON.stringify({
|
|
82
|
+
streetNumber: '1',
|
|
83
|
+
street: 'A St',
|
|
84
|
+
city: ' ',
|
|
85
|
+
state: '',
|
|
86
|
+
postalCode: '',
|
|
87
|
+
country: ''
|
|
88
|
+
}));
|
|
89
|
+
expect(row?.city).toBeUndefined();
|
|
90
|
+
expect(row?.state).toBeUndefined();
|
|
91
|
+
expect(row?.postal_code).toBeUndefined();
|
|
92
|
+
});
|
|
93
|
+
it('uses the platform-named place when there are no street components', () => {
|
|
94
|
+
expect(parseComponents(JSON.stringify({
|
|
95
|
+
line1: 'Apple Park',
|
|
96
|
+
city: 'Cupertino',
|
|
97
|
+
country: 'US'
|
|
98
|
+
}))?.line1).toBe('Apple Park');
|
|
99
|
+
});
|
|
100
|
+
it('declines a resolve with no street at all, which would blank the grid for nothing', () => {
|
|
101
|
+
expect(parseComponents(JSON.stringify({
|
|
102
|
+
city: 'Austin',
|
|
103
|
+
country: 'US'
|
|
104
|
+
}))).toBeNull();
|
|
105
|
+
expect(parseComponents('not json')).toBeNull();
|
|
106
|
+
expect(parseComponents('[]')).toBeNull();
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
describe('resolveSubdivision', () => {
|
|
110
|
+
// Both fixtures mirror what engine.ts:141 actually builds from the real catalog.
|
|
111
|
+
// US carries sub_names and no sub_lnames, so its option name is a single script.
|
|
112
|
+
const usa = [{
|
|
113
|
+
key: 'CA',
|
|
114
|
+
name: 'California',
|
|
115
|
+
iso: 'CA'
|
|
116
|
+
}, {
|
|
117
|
+
key: 'NY',
|
|
118
|
+
name: 'New York',
|
|
119
|
+
iso: 'NY'
|
|
120
|
+
}];
|
|
121
|
+
// JP carries sub_lnames and no sub_names, so `names[i] || key` is the native key and the name
|
|
122
|
+
// comes out JOINED — which is the shape a geocoder never returns.
|
|
123
|
+
const japan = [{
|
|
124
|
+
key: '東京都',
|
|
125
|
+
name: '東京都 — Tokyo',
|
|
126
|
+
iso: '13'
|
|
127
|
+
}, {
|
|
128
|
+
key: '北海道',
|
|
129
|
+
name: '北海道 — Hokkaido',
|
|
130
|
+
iso: '01'
|
|
131
|
+
}];
|
|
132
|
+
it('accepts the catalog key or the display name', () => {
|
|
133
|
+
expect(resolveSubdivision('CA', usa)).toBe('CA');
|
|
134
|
+
expect(resolveSubdivision('California', usa)).toBe('CA');
|
|
135
|
+
expect(resolveSubdivision('new york', usa)).toBe('NY');
|
|
136
|
+
});
|
|
137
|
+
it('matches either half of a joined native-and-latin name', () => {
|
|
138
|
+
expect(resolveSubdivision('Tokyo', japan)).toBe('東京都');
|
|
139
|
+
expect(resolveSubdivision('東京都', japan)).toBe('東京都');
|
|
140
|
+
expect(resolveSubdivision('hokkaido', japan)).toBe('北海道');
|
|
141
|
+
});
|
|
142
|
+
it('still matches the joined name itself', () => {
|
|
143
|
+
expect(resolveSubdivision('東京都 — Tokyo', japan)).toBe('東京都');
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Emitting an unmatched value would show the Select on its placeholder while still sending the
|
|
147
|
+
// bad string onward; clearing it surfaces the required-state error instead.
|
|
148
|
+
it('resolves an unknown subdivision to absence, not to itself', () => {
|
|
149
|
+
expect(resolveSubdivision('Bayern', usa)).toBeUndefined();
|
|
150
|
+
});
|
|
151
|
+
it('passes the value through for countries with no subdivision list', () => {
|
|
152
|
+
expect(resolveSubdivision('Greater London', [])).toBe('Greater London');
|
|
153
|
+
expect(resolveSubdivision(' ', [])).toBeUndefined();
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
//# sourceMappingURL=suggest.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["describe","expect","it","composeLine1","parseComponents","parseSuggestions","resolveSubdivision","toBe","undefined","toBeUndefined","rows","JSON","stringify","id","label","toEqual","us","streetNumber","street","country","line1","de","row","city","state","postalCode","postal_code","toBeNull","usa","key","name","iso","japan"],"sourceRoot":"../../../../src","sources":["core/address/suggest.test.ts"],"mappings":";;AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,QAAQ;AAE7C,SAASC,YAAY,EAAEC,eAAe,EAAEC,gBAAgB,EAAEC,kBAAkB,QAAQ,cAAW;AAE/FN,QAAQ,CAAC,cAAc,EAAE,MAAM;EAC9BE,EAAE,CAAC,iDAAiD,EAAE,MAAM;IAC3DD,MAAM,CAACE,YAAY,CAAC,MAAM,EAAE,sBAAsB,EAAE,IAAI,CAAC,CAAC,CAACI,IAAI,CAAC,2BAA2B,CAAC;IAC5FN,MAAM,CAACE,YAAY,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC,CAACI,IAAI,CAAC,mBAAmB,CAAC;EAC7E,CAAC,CAAC;EAEFL,EAAE,CAAC,sCAAsC,EAAE,MAAM;IAChDD,MAAM,CAACE,YAAY,CAAC,IAAI,EAAE,kBAAkB,EAAE,IAAI,CAAC,CAAC,CAACI,IAAI,CAAC,qBAAqB,CAAC;IAChFN,MAAM,CAACE,YAAY,CAAC,IAAI,EAAE,eAAe,EAAE,IAAI,CAAC,CAAC,CAACI,IAAI,CAAC,kBAAkB,CAAC;EAC3E,CAAC,CAAC;EAEFL,EAAE,CAAC,qCAAqC,EAAE,MAAM;IAC/CD,MAAM,CAACE,YAAY,CAACK,SAAS,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC,CAACD,IAAI,CAAC,UAAU,CAAC;IAClEN,MAAM,CAACE,YAAY,CAAC,IAAI,EAAEK,SAAS,EAAE,IAAI,CAAC,CAAC,CAACD,IAAI,CAAC,IAAI,CAAC;IACtDN,MAAM,CAACE,YAAY,CAACK,SAAS,EAAEA,SAAS,EAAE,IAAI,CAAC,CAAC,CAACC,aAAa,CAAC,CAAC;EACjE,CAAC,CAAC;AACH,CAAC,CAAC;AAEFT,QAAQ,CAAC,kBAAkB,EAAE,MAAM;EAClCE,EAAE,CAAC,8CAA8C,EAAE,MAAM;IACxD,MAAMQ,IAAI,GAAGL,gBAAgB,CAC5BM,IAAI,CAACC,SAAS,CAAC,CACd;MAAEC,EAAE,EAAE,eAAe;MAAEC,KAAK,EAAE;IAAqB,CAAC,EACpD;MAAED,EAAE,EAAE,EAAE;MAAEC,KAAK,EAAE;IAAQ,CAAC,EAC1B;MAAED,EAAE,EAAE,GAAG;MAAEC,KAAK,EAAE;IAAG,CAAC,EACtB;MAAED,EAAE,EAAE;IAAI,CAAC,EACX,IAAI,CACJ,CACF,CAAC;IACDZ,MAAM,CAACS,IAAI,CAAC,CAACK,OAAO,CAAC,CAAC;MAAEF,EAAE,EAAE,eAAe;MAAEC,KAAK,EAAE;IAAqB,CAAC,CAAC,CAAC;EAC7E,CAAC,CAAC;EAEFZ,EAAE,CAAC,yCAAyC,EAAE,MAAM;IACnDD,MAAM,CAACI,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAACU,OAAO,CAAC,EAAE,CAAC;IAChDd,MAAM,CAACI,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAACU,OAAO,CAAC,EAAE,CAAC;IAC1Cd,MAAM,CAACI,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAACU,OAAO,CAAC,EAAE,CAAC;EAC3C,CAAC,CAAC;AACH,CAAC,CAAC;AAEFf,QAAQ,CAAC,iBAAiB,EAAE,MAAM;EACjCE,EAAE,CAAC,wCAAwC,EAAE,MAAM;IAClD,MAAMc,EAAE,GAAGZ,eAAe,CAACO,IAAI,CAACC,SAAS,CAAC;MAAEK,YAAY,EAAE,MAAM;MAAEC,MAAM,EAAE,mBAAmB;MAAEC,OAAO,EAAE;IAAK,CAAC,CAAC,CAAC;IAChHlB,MAAM,CAACe,EAAE,EAAEI,KAAK,CAAC,CAACb,IAAI,CAAC,wBAAwB,CAAC;IAChD,MAAMc,EAAE,GAAGjB,eAAe,CAACO,IAAI,CAACC,SAAS,CAAC;MAAEK,YAAY,EAAE,IAAI;MAAEC,MAAM,EAAE,kBAAkB;MAAEC,OAAO,EAAE;IAAK,CAAC,CAAC,CAAC;IAC7GlB,MAAM,CAACoB,EAAE,EAAED,KAAK,CAAC,CAACb,IAAI,CAAC,qBAAqB,CAAC;EAC9C,CAAC,CAAC;;EAEF;EACA;EACAL,EAAE,CAAC,6DAA6D,EAAE,MAAM;IACvE,MAAMoB,GAAG,GAAGlB,eAAe,CAACO,IAAI,CAACC,SAAS,CAAC;MAAEK,YAAY,EAAE,MAAM;MAAEC,MAAM,EAAE;IAAoB,CAAC,CAAC,EAAE,IAAI,CAAC;IACxGjB,MAAM,CAACqB,GAAG,EAAEF,KAAK,CAAC,CAACb,IAAI,CAAC,wBAAwB,CAAC;IACjDN,MAAM,CAACqB,GAAG,EAAEH,OAAO,CAAC,CAACZ,IAAI,CAAC,IAAI,CAAC;EAChC,CAAC,CAAC;EAEFL,EAAE,CAAC,mDAAmD,EAAE,MAAM;IAC7DD,MAAM,CAACG,eAAe,CAACO,IAAI,CAACC,SAAS,CAAC;MAAEM,MAAM,EAAE,MAAM;MAAEC,OAAO,EAAE;IAAK,CAAC,CAAC,EAAE,IAAI,CAAC,EAAEA,OAAO,CAAC,CAACZ,IAAI,CAAC,IAAI,CAAC;EACrG,CAAC,CAAC;;EAEF;EACA;EACAL,EAAE,CAAC,kCAAkC,EAAE,MAAM;IAC5C,MAAMoB,GAAG,GAAGlB,eAAe,CAC1BO,IAAI,CAACC,SAAS,CAAC;MAAEK,YAAY,EAAE,GAAG;MAAEC,MAAM,EAAE,MAAM;MAAEK,IAAI,EAAE,IAAI;MAAEC,KAAK,EAAE,EAAE;MAAEC,UAAU,EAAE,EAAE;MAAEN,OAAO,EAAE;IAAG,CAAC,CACzG,CAAC;IACDlB,MAAM,CAACqB,GAAG,EAAEC,IAAI,CAAC,CAACd,aAAa,CAAC,CAAC;IACjCR,MAAM,CAACqB,GAAG,EAAEE,KAAK,CAAC,CAACf,aAAa,CAAC,CAAC;IAClCR,MAAM,CAACqB,GAAG,EAAEI,WAAW,CAAC,CAACjB,aAAa,CAAC,CAAC;EACzC,CAAC,CAAC;EAEFP,EAAE,CAAC,mEAAmE,EAAE,MAAM;IAC7ED,MAAM,CAACG,eAAe,CAACO,IAAI,CAACC,SAAS,CAAC;MAAEQ,KAAK,EAAE,YAAY;MAAEG,IAAI,EAAE,WAAW;MAAEJ,OAAO,EAAE;IAAK,CAAC,CAAC,CAAC,EAAEC,KAAK,CAAC,CAACb,IAAI,CAC7G,YACD,CAAC;EACF,CAAC,CAAC;EAEFL,EAAE,CAAC,kFAAkF,EAAE,MAAM;IAC5FD,MAAM,CAACG,eAAe,CAACO,IAAI,CAACC,SAAS,CAAC;MAAEW,IAAI,EAAE,QAAQ;MAAEJ,OAAO,EAAE;IAAK,CAAC,CAAC,CAAC,CAAC,CAACQ,QAAQ,CAAC,CAAC;IACrF1B,MAAM,CAACG,eAAe,CAAC,UAAU,CAAC,CAAC,CAACuB,QAAQ,CAAC,CAAC;IAC9C1B,MAAM,CAACG,eAAe,CAAC,IAAI,CAAC,CAAC,CAACuB,QAAQ,CAAC,CAAC;EACzC,CAAC,CAAC;AACH,CAAC,CAAC;AAEF3B,QAAQ,CAAC,oBAAoB,EAAE,MAAM;EACpC;EACA;EACA,MAAM4B,GAAG,GAAG,CACX;IAAEC,GAAG,EAAE,IAAI;IAAEC,IAAI,EAAE,YAAY;IAAEC,GAAG,EAAE;EAAK,CAAC,EAC5C;IAAEF,GAAG,EAAE,IAAI;IAAEC,IAAI,EAAE,UAAU;IAAEC,GAAG,EAAE;EAAK,CAAC,CAC1C;EACD;EACA;EACA,MAAMC,KAAK,GAAG,CACb;IAAEH,GAAG,EAAE,KAAK;IAAEC,IAAI,EAAE,aAAa;IAAEC,GAAG,EAAE;EAAK,CAAC,EAC9C;IAAEF,GAAG,EAAE,KAAK;IAAEC,IAAI,EAAE,gBAAgB;IAAEC,GAAG,EAAE;EAAK,CAAC,CACjD;EAED7B,EAAE,CAAC,6CAA6C,EAAE,MAAM;IACvDD,MAAM,CAACK,kBAAkB,CAAC,IAAI,EAAEsB,GAAG,CAAC,CAAC,CAACrB,IAAI,CAAC,IAAI,CAAC;IAChDN,MAAM,CAACK,kBAAkB,CAAC,YAAY,EAAEsB,GAAG,CAAC,CAAC,CAACrB,IAAI,CAAC,IAAI,CAAC;IACxDN,MAAM,CAACK,kBAAkB,CAAC,UAAU,EAAEsB,GAAG,CAAC,CAAC,CAACrB,IAAI,CAAC,IAAI,CAAC;EACvD,CAAC,CAAC;EAEFL,EAAE,CAAC,uDAAuD,EAAE,MAAM;IACjED,MAAM,CAACK,kBAAkB,CAAC,OAAO,EAAE0B,KAAK,CAAC,CAAC,CAACzB,IAAI,CAAC,KAAK,CAAC;IACtDN,MAAM,CAACK,kBAAkB,CAAC,KAAK,EAAE0B,KAAK,CAAC,CAAC,CAACzB,IAAI,CAAC,KAAK,CAAC;IACpDN,MAAM,CAACK,kBAAkB,CAAC,UAAU,EAAE0B,KAAK,CAAC,CAAC,CAACzB,IAAI,CAAC,KAAK,CAAC;EAC1D,CAAC,CAAC;EAEFL,EAAE,CAAC,sCAAsC,EAAE,MAAM;IAChDD,MAAM,CAACK,kBAAkB,CAAC,aAAa,EAAE0B,KAAK,CAAC,CAAC,CAACzB,IAAI,CAAC,KAAK,CAAC;EAC7D,CAAC,CAAC;;EAEF;EACA;EACAL,EAAE,CAAC,2DAA2D,EAAE,MAAM;IACrED,MAAM,CAACK,kBAAkB,CAAC,QAAQ,EAAEsB,GAAG,CAAC,CAAC,CAACnB,aAAa,CAAC,CAAC;EAC1D,CAAC,CAAC;EAEFP,EAAE,CAAC,iEAAiE,EAAE,MAAM;IAC3ED,MAAM,CAACK,kBAAkB,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC,CAACC,IAAI,CAAC,gBAAgB,CAAC;IACvEN,MAAM,CAACK,kBAAkB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAACG,aAAa,CAAC,CAAC;EACrD,CAAC,CAAC;AACH,CAAC,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef, useState } from 'react';
|
|
4
|
+
import { WhopAddressSuggestions } from "../../native/index.js";
|
|
5
|
+
/** Long enough that a geocoder has something to work with, short enough to feel live. */
|
|
6
|
+
const MIN_QUERY_LENGTH = 3;
|
|
7
|
+
const DEBOUNCE_MS = 250;
|
|
8
|
+
export function useAddressSuggestions(enabled, query) {
|
|
9
|
+
const [rows, setRows] = useState([]);
|
|
10
|
+
const generation = useRef(0);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
// Advance BEFORE the early return: clearing the list does not cancel a lookup already in
|
|
13
|
+
// flight, so a generation that only moved when a new lookup was scheduled left the old one
|
|
14
|
+
// still matching, and deleting back to two characters repopulated the field.
|
|
15
|
+
const current = generation.current + 1;
|
|
16
|
+
generation.current = current;
|
|
17
|
+
const trimmed = query.trim();
|
|
18
|
+
if (!enabled || trimmed.length < MIN_QUERY_LENGTH) {
|
|
19
|
+
setRows([]);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const timer = setTimeout(() => {
|
|
23
|
+
void WhopAddressSuggestions.suggest(trimmed).then(found => {
|
|
24
|
+
// Geocoder latency is not ordered. Without this a slow lookup for "12 Ma" can land after
|
|
25
|
+
// "12 Main St" and put stale rows under a newer query.
|
|
26
|
+
if (generation.current === current) setRows(found);
|
|
27
|
+
});
|
|
28
|
+
}, DEBOUNCE_MS);
|
|
29
|
+
return () => clearTimeout(timer);
|
|
30
|
+
}, [enabled, query]);
|
|
31
|
+
return rows;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=use-suggestions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useEffect","useRef","useState","WhopAddressSuggestions","MIN_QUERY_LENGTH","DEBOUNCE_MS","useAddressSuggestions","enabled","query","rows","setRows","generation","current","trimmed","trim","length","timer","setTimeout","suggest","then","found","clearTimeout"],"sourceRoot":"../../../../src","sources":["core/address/use-suggestions.ts"],"mappings":";;AAAA,SAASA,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,OAAO;AAEnD,SAASC,sBAAsB,QAAQ,uBAAc;AAGrD;AACA,MAAMC,gBAAgB,GAAG,CAAC;AAC1B,MAAMC,WAAW,GAAG,GAAG;AAEvB,OAAO,SAASC,qBAAqBA,CAACC,OAAgB,EAAEC,KAAa,EAAuB;EAC3F,MAAM,CAACC,IAAI,EAAEC,OAAO,CAAC,GAAGR,QAAQ,CAAsB,EAAE,CAAC;EACzD,MAAMS,UAAU,GAAGV,MAAM,CAAC,CAAC,CAAC;EAE5BD,SAAS,CAAC,MAAM;IACf;IACA;IACA;IACA,MAAMY,OAAO,GAAGD,UAAU,CAACC,OAAO,GAAG,CAAC;IACtCD,UAAU,CAACC,OAAO,GAAGA,OAAO;IAE5B,MAAMC,OAAO,GAAGL,KAAK,CAACM,IAAI,CAAC,CAAC;IAC5B,IAAI,CAACP,OAAO,IAAIM,OAAO,CAACE,MAAM,GAAGX,gBAAgB,EAAE;MAClDM,OAAO,CAAC,EAAE,CAAC;MACX;IACD;IACA,MAAMM,KAAK,GAAGC,UAAU,CAAC,MAAM;MAC9B,KAAKd,sBAAsB,CAACe,OAAO,CAACL,OAAO,CAAC,CAACM,IAAI,CAAEC,KAAK,IAAK;QAC5D;QACA;QACA,IAAIT,UAAU,CAACC,OAAO,KAAKA,OAAO,EAAEF,OAAO,CAACU,KAAK,CAAC;MACnD,CAAC,CAAC;IACH,CAAC,EAAEf,WAAW,CAAC;IACf,OAAO,MAAMgB,YAAY,CAACL,KAAK,CAAC;EACjC,CAAC,EAAE,CAACT,OAAO,EAAEC,KAAK,CAAC,CAAC;EAEpB,OAAOC,IAAI;AACZ","ignoreList":[]}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// ported verbatim from frontend/apps/web/src/elements/payments/lib/address-change.ts — keep in sync when the web element changes
|
|
4
|
+
|
|
5
|
+
import { createContext, useContext, useEffect, useMemo, useRef } from 'react';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The postal address the payment element's `addressChange` event carries: every place-identifying
|
|
9
|
+
* field the billing block collects, with the optionality the form itself has. Only `country` is
|
|
10
|
+
* guaranteed — each country's format collects its own field set (no state in the Netherlands, no
|
|
11
|
+
* postal code in Ireland, no line2 unless the buyer fills one), so a key is absent whenever the
|
|
12
|
+
* form did not collect a value for it. Name, organization, and email are not part of an address
|
|
13
|
+
* and stay off this event.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A buyer typing a postal code produces one form snapshot per keystroke, and the consumer turns
|
|
18
|
+
* every emit into a tax quote or a shipping-rate lookup — one network call per character is the
|
|
19
|
+
* failure mode this guards. 300ms is the settle window: longer than the gap between keystrokes at
|
|
20
|
+
* any real typing speed (so a whole postal code collapses into ONE emit), short enough that the
|
|
21
|
+
* quote is back before the buyer reaches the pay button. TRAILING edge only — a leading emit would
|
|
22
|
+
* fire on the first character, which is the one value guaranteed to be useless.
|
|
23
|
+
*/
|
|
24
|
+
export const ADDRESS_CHANGE_DEBOUNCE_MS = 300;
|
|
25
|
+
const OPTIONAL_ADDRESS_KEYS = ['line1', 'line2', 'city', 'state', 'postal_code'];
|
|
26
|
+
export function postalAddressOf(address) {
|
|
27
|
+
const out = {
|
|
28
|
+
country: address.country
|
|
29
|
+
};
|
|
30
|
+
for (const key of OPTIONAL_ADDRESS_KEYS) {
|
|
31
|
+
const value = address[key];
|
|
32
|
+
if (value) out[key] = value;
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
function sameAddressChange(a, b) {
|
|
37
|
+
return a.complete === b.complete && a.address.country === b.address.country && OPTIONAL_ADDRESS_KEYS.every(key => a.address[key] === b.address[key]);
|
|
38
|
+
}
|
|
39
|
+
const AddressChangePublishContext = /*#__PURE__*/createContext({
|
|
40
|
+
publish: () => {},
|
|
41
|
+
abandon: () => {}
|
|
42
|
+
});
|
|
43
|
+
export const AddressChangePublishProvider = AddressChangePublishContext.Provider;
|
|
44
|
+
export function usePublishAddressChange() {
|
|
45
|
+
return useContext(AddressChangePublishContext);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* ELEMENT-SCOPED on purpose: every method tile mounts its own billing block, so the debounce
|
|
50
|
+
* timer and the last-emitted memory have to be shared across them — a per-block memory would
|
|
51
|
+
* suppress the republish that a tile switch back to an earlier address depends on.
|
|
52
|
+
*/
|
|
53
|
+
export function useAddressChangePublisher(emit) {
|
|
54
|
+
const emitRef = useRef(emit);
|
|
55
|
+
const pendingRef = useRef(undefined);
|
|
56
|
+
const emittedRef = useRef(undefined);
|
|
57
|
+
const timerRef = useRef(undefined);
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
emitRef.current = emit;
|
|
60
|
+
});
|
|
61
|
+
useEffect(() => () => clearTimeout(timerRef.current), []);
|
|
62
|
+
return useMemo(() => ({
|
|
63
|
+
publish: (owner, change) => {
|
|
64
|
+
pendingRef.current = {
|
|
65
|
+
owner,
|
|
66
|
+
change
|
|
67
|
+
};
|
|
68
|
+
clearTimeout(timerRef.current);
|
|
69
|
+
timerRef.current = setTimeout(() => {
|
|
70
|
+
const next = pendingRef.current?.change;
|
|
71
|
+
if (!next) return;
|
|
72
|
+
if (emittedRef.current && sameAddressChange(emittedRef.current, next)) return;
|
|
73
|
+
emittedRef.current = next;
|
|
74
|
+
// a fresh payload per delivery: the retained dedupe value must not alias an object a
|
|
75
|
+
// direct-mode consumer holds and could mutate
|
|
76
|
+
emitRef.current({
|
|
77
|
+
complete: next.complete,
|
|
78
|
+
address: {
|
|
79
|
+
...next.address
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}, ADDRESS_CHANGE_DEBOUNCE_MS);
|
|
83
|
+
},
|
|
84
|
+
abandon: owner => {
|
|
85
|
+
if (pendingRef.current?.owner !== owner) return;
|
|
86
|
+
pendingRef.current = undefined;
|
|
87
|
+
clearTimeout(timerRef.current);
|
|
88
|
+
}
|
|
89
|
+
}), []);
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=address-change.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["createContext","useContext","useEffect","useMemo","useRef","ADDRESS_CHANGE_DEBOUNCE_MS","OPTIONAL_ADDRESS_KEYS","postalAddressOf","address","out","country","key","value","sameAddressChange","a","b","complete","every","AddressChangePublishContext","publish","abandon","AddressChangePublishProvider","Provider","usePublishAddressChange","useAddressChangePublisher","emit","emitRef","pendingRef","undefined","emittedRef","timerRef","current","clearTimeout","owner","change","setTimeout","next"],"sourceRoot":"../../../../src","sources":["core/payments/address-change.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// ported verbatim from frontend/apps/web/src/elements/payments/lib/billing-merge.ts — keep in sync when the web element changes
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The billing-details precedence merge for the confirm rail: explicit
|
|
7
|
+
* `createConfirmationToken({ billingDetails })` input > standalone address element values >
|
|
8
|
+
* the payment element's internal billing block. Applied twice along the cascade (controller
|
|
9
|
+
* merges the address element under the input; the payment element merges its block under the
|
|
10
|
+
* result) — scalars merge field-level, the address object is ATOMIC per source (a mixed-source
|
|
11
|
+
* address would be incoherent), which keeps the two applications associative.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
function billingNameOf(address) {
|
|
15
|
+
if (address.name) return address.name;
|
|
16
|
+
const joined = [address.first_name, address.last_name].filter(Boolean).join(' ');
|
|
17
|
+
return joined || undefined;
|
|
18
|
+
}
|
|
19
|
+
function billingAddressOf(address) {
|
|
20
|
+
const bag = {};
|
|
21
|
+
if (address.country) bag.country = address.country;
|
|
22
|
+
if (address.line1) bag.line1 = address.line1;
|
|
23
|
+
if (address.line2) bag.line2 = address.line2;
|
|
24
|
+
if (address.city) bag.city = address.city;
|
|
25
|
+
if (address.state) bag.state = address.state;
|
|
26
|
+
if (address.postal_code) bag.postal_code = address.postal_code;
|
|
27
|
+
return Object.keys(bag).length > 0 ? bag : undefined;
|
|
28
|
+
}
|
|
29
|
+
function hasAddressValues(address) {
|
|
30
|
+
return Boolean(address && Object.values(address).some(value => typeof value === 'string' && value.trim().length > 0));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Merge a collected form snapshot UNDER an explicit billing-details bag. When the collected
|
|
35
|
+
* form is the address source actually being used and it is incomplete, the merge throws — a
|
|
36
|
+
* confirm over a half-filled form must fail loud, exactly like the surfaces' own validation
|
|
37
|
+
* (an explicit complete input keeps winning silently).
|
|
38
|
+
*/
|
|
39
|
+
export function mergeBillingWithCollected(explicit, collected) {
|
|
40
|
+
if (!collected) return explicit;
|
|
41
|
+
const explicitAddress = hasAddressValues(explicit?.address) ? explicit?.address : undefined;
|
|
42
|
+
const explicitCompletesPhone = Boolean(explicit?.phone && collected.completeWithoutPhone);
|
|
43
|
+
const requiredPhoneMissing = collected.phoneRequired && !explicit?.phone && !collected.phone;
|
|
44
|
+
if (requiredPhoneMissing) {
|
|
45
|
+
throw new Error('The address form is incomplete — finish it or pass billingDetails to createConfirmationToken');
|
|
46
|
+
}
|
|
47
|
+
if (!explicitAddress && !explicitCompletesPhone && !collected.complete) {
|
|
48
|
+
throw new Error('The address form is incomplete — finish it or pass billingDetails to createConfirmationToken');
|
|
49
|
+
}
|
|
50
|
+
const merged = {
|
|
51
|
+
...explicit
|
|
52
|
+
};
|
|
53
|
+
if (!merged.phone && collected.phone) merged.phone = collected.phone;
|
|
54
|
+
if (!merged.name) {
|
|
55
|
+
const name = billingNameOf(collected.address);
|
|
56
|
+
if (name) merged.name = name;else delete merged.name;
|
|
57
|
+
}
|
|
58
|
+
const address = explicitAddress ?? billingAddressOf(collected.address);
|
|
59
|
+
if (address) merged.address = address;else delete merged.address;
|
|
60
|
+
return Object.keys(merged).length > 0 ? merged : explicit;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=billing-merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["billingNameOf","address","name","joined","first_name","last_name","filter","Boolean","join","undefined","billingAddressOf","bag","country","line1","line2","city","state","postal_code","Object","keys","length","hasAddressValues","values","some","value","trim","mergeBillingWithCollected","explicit","collected","explicitAddress","explicitCompletesPhone","phone","completeWithoutPhone","requiredPhoneMissing","phoneRequired","Error","complete","merged"],"sourceRoot":"../../../../src","sources":["core/payments/billing-merge.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { Dimensions, NativeModules, PixelRatio, Platform } from 'react-native';
|
|
4
|
+
/**
|
|
5
|
+
* The React Native counterpart of the web element's `browser_info` capture.
|
|
6
|
+
*
|
|
7
|
+
* The field names are the wire's, because the backend feeds them to 3DS, which was specified for
|
|
8
|
+
* browsers. An app has no `navigator`, so each value is the nearest honest platform fact rather
|
|
9
|
+
* than a fabricated browser one — omitted where there is no honest answer.
|
|
10
|
+
*/
|
|
11
|
+
export function capturedBrowserInfo() {
|
|
12
|
+
const {
|
|
13
|
+
width,
|
|
14
|
+
height
|
|
15
|
+
} = Dimensions.get('screen');
|
|
16
|
+
const scale = PixelRatio.get();
|
|
17
|
+
return {
|
|
18
|
+
platform: Platform.OS === 'ios' ? 'iPhone' : 'Linux armv8l',
|
|
19
|
+
color_depth: 24,
|
|
20
|
+
screen_width: Math.round(width * scale),
|
|
21
|
+
screen_height: Math.round(height * scale),
|
|
22
|
+
language: resolveLanguage(),
|
|
23
|
+
java_enabled: false,
|
|
24
|
+
browser_time_difference: new Date().getTimezoneOffset(),
|
|
25
|
+
user_agent: `WhopElementsReactNative/${Platform.OS} ${String(Platform.Version)}`
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function resolveLanguage() {
|
|
29
|
+
const tag = deviceLocale();
|
|
30
|
+
return tag ? tag.replace(/_/g, '-') : 'en-US';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The one platform read; kept separate so the locale default can reuse it. */
|
|
34
|
+
export function deviceLocale() {
|
|
35
|
+
if (Platform.OS === 'ios') {
|
|
36
|
+
const settings = NativeModules.SettingsManager?.settings;
|
|
37
|
+
return settings?.AppleLocale ?? settings?.AppleLanguages?.[0];
|
|
38
|
+
}
|
|
39
|
+
const i18n = NativeModules.I18nManager;
|
|
40
|
+
return i18n?.localeIdentifier;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=browser-info.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["Dimensions","NativeModules","PixelRatio","Platform","capturedBrowserInfo","width","height","get","scale","platform","OS","color_depth","screen_width","Math","round","screen_height","language","resolveLanguage","java_enabled","browser_time_difference","Date","getTimezoneOffset","user_agent","String","Version","tag","deviceLocale","replace","settings","SettingsManager","AppleLocale","AppleLanguages","i18n","I18nManager","localeIdentifier"],"sourceRoot":"../../../../src","sources":["core/payments/browser-info.ts"],"mappings":";;AAAA,SAASA,UAAU,EAAEC,aAAa,EAAEC,UAAU,EAAEC,QAAQ,QAAQ,cAAc;AAI9E;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,mBAAmBA,CAAA,EAAgB;EAClD,MAAM;IAAEC,KAAK;IAAEC;EAAO,CAAC,GAAGN,UAAU,CAACO,GAAG,CAAC,QAAQ,CAAC;EAClD,MAAMC,KAAK,GAAGN,UAAU,CAACK,GAAG,CAAC,CAAC;EAE9B,OAAO;IACNE,QAAQ,EAAEN,QAAQ,CAACO,EAAE,KAAK,KAAK,GAAG,QAAQ,GAAG,cAAc;IAC3DC,WAAW,EAAE,EAAE;IACfC,YAAY,EAAEC,IAAI,CAACC,KAAK,CAACT,KAAK,GAAGG,KAAK,CAAC;IACvCO,aAAa,EAAEF,IAAI,CAACC,KAAK,CAACR,MAAM,GAAGE,KAAK,CAAC;IACzCQ,QAAQ,EAAEC,eAAe,CAAC,CAAC;IAC3BC,YAAY,EAAE,KAAK;IACnBC,uBAAuB,EAAE,IAAIC,IAAI,CAAC,CAAC,CAACC,iBAAiB,CAAC,CAAC;IACvDC,UAAU,EAAE,2BAA2BnB,QAAQ,CAACO,EAAE,IAAIa,MAAM,CAACpB,QAAQ,CAACqB,OAAO,CAAC;EAC/E,CAAC;AACF;AAEA,SAASP,eAAeA,CAAA,EAAW;EAClC,MAAMQ,GAAG,GAAGC,YAAY,CAAC,CAAC;EAC1B,OAAOD,GAAG,GAAGA,GAAG,CAACE,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,OAAO;AAC9C;;AAEA;AACA,OAAO,SAASD,YAAYA,CAAA,EAAuB;EAClD,IAAIvB,QAAQ,CAACO,EAAE,KAAK,KAAK,EAAE;IAC1B,MAAMkB,QAAQ,GAAG3B,aAAa,CAAC4B,eAAe,EAAED,QAEpC;IACZ,OAAOA,QAAQ,EAAEE,WAAW,IAAIF,QAAQ,EAAEG,cAAc,GAAG,CAAC,CAAC;EAC9D;EACA,MAAMC,IAAI,GAAG/B,aAAa,CAACgC,WAAwD;EACnF,OAAOD,IAAI,EAAEE,gBAAgB;AAC9B","ignoreList":[]}
|