@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,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { TextElement, useBasisTheory } from '@basis-theory/react-native-elements';
|
|
5
|
+
import { fieldLabel, fieldMatches, methodTokenizerKey } from "../../core/payments/detail.js";
|
|
6
|
+
import { tokenizeSecureFields } from "../../core/payments/secure-fields.js";
|
|
7
|
+
import { useT } from "../../i18n/index.js";
|
|
8
|
+
import { alphaStep } from "../../theme/provider.js";
|
|
9
|
+
import { Field, FieldShell, Stack, useFieldStyles } from "../../ui/primitives.js";
|
|
10
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
|
+
/**
|
|
12
|
+
* A method's `required_fields`, rendered generically from what the matrix publishes.
|
|
13
|
+
*
|
|
14
|
+
* A `secure: true` field renders as a Basis Theory hosted text element, so the raw value never
|
|
15
|
+
* exists in this JavaScript. At collect time every secure instance is tokenized into ONE token
|
|
16
|
+
* intent keyed by field name, and the category payload carries `{ token_intent }` — the shape the
|
|
17
|
+
* web element produces and the backend already reads.
|
|
18
|
+
*/
|
|
19
|
+
export function useDeclaredFields(entry, country) {
|
|
20
|
+
const fields = useMemo(() => entry?.required_fields ?? [], [entry]);
|
|
21
|
+
// A method's secure fields tokenize under ITS OWN config-block key, which is a different Basis
|
|
22
|
+
// Theory application from the card one — the card key cannot mint token intents at all.
|
|
23
|
+
//
|
|
24
|
+
// The client is NOT constructed here: most methods declare no secure field, and constructing
|
|
25
|
+
// Basis Theory with a missing key makes its SDK show a "Please enter a valid API key" toast to
|
|
26
|
+
// the buyer. `SecureTokenizer` below mounts only when a secure field and a key both exist, and
|
|
27
|
+
// hands the instance back through this ref.
|
|
28
|
+
const btRef = useRef(undefined);
|
|
29
|
+
const [values, setValues] = useState({});
|
|
30
|
+
const [showErrors, setShowErrors] = useState(false);
|
|
31
|
+
const [secureComplete, setSecureComplete] = useState({});
|
|
32
|
+
const secureRefs = useRef({});
|
|
33
|
+
|
|
34
|
+
// Declared fields belong to the METHOD, and this state is keyed by field NAME — so two methods
|
|
35
|
+
// that both declare `bank_account` shared everything: a value typed for one, and its secure
|
|
36
|
+
// completeness, carried into the other and reported it ready before the buyer touched it.
|
|
37
|
+
const entryKey = entry?.type;
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
setValues({});
|
|
40
|
+
setShowErrors(false);
|
|
41
|
+
secureRefs.current = {};
|
|
42
|
+
}, [entryKey]);
|
|
43
|
+
const setValue = useCallback((name, value) => {
|
|
44
|
+
setValues(prev => prev[name] === value ? prev : {
|
|
45
|
+
...prev,
|
|
46
|
+
[name]: value
|
|
47
|
+
});
|
|
48
|
+
}, []);
|
|
49
|
+
const errorFor = useCallback(field => {
|
|
50
|
+
if (field.secure) return undefined;
|
|
51
|
+
const value = values[field.name] ?? '';
|
|
52
|
+
if (!value.trim()) return 'required';
|
|
53
|
+
// `input_formats` is what a buyer may TYPE; `formats` is the stored electronic value. The
|
|
54
|
+
// typing tolerance wins where the matrix publishes it.
|
|
55
|
+
const patterns = field.input_formats ?? field.formats;
|
|
56
|
+
return fieldMatches(patterns, country, value) ? undefined : 'invalid';
|
|
57
|
+
}, [values, country]);
|
|
58
|
+
const complete = useMemo(() =>
|
|
59
|
+
// A MOUNTED tokenizer field is not a filled one. Keying off the ref meant completeness
|
|
60
|
+
// flipped true the moment the element attached and stayed true after the buyer cleared it,
|
|
61
|
+
// so the form reported itself ready to submit values that were never entered.
|
|
62
|
+
fields.every(field => field.secure ? secureComplete[`${entryKey ?? ''}:${field.name}`] === true : !errorFor(field)), [fields, errorFor, secureComplete, entryKey]);
|
|
63
|
+
const collect = useCallback(async () => {
|
|
64
|
+
const paymentMethod = {};
|
|
65
|
+
const billingExtra = {};
|
|
66
|
+
const secure = {};
|
|
67
|
+
for (const field of fields) {
|
|
68
|
+
if (field.secure) {
|
|
69
|
+
const instance = secureRefs.current[field.name];
|
|
70
|
+
if (instance) secure[field.name] = instance;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const value = (values[field.name] ?? '').trim();
|
|
74
|
+
if (field.kind === 'billing_details') billingExtra[field.name] = value;else paymentMethod[field.name] = value;
|
|
75
|
+
}
|
|
76
|
+
let secureTokenIntent;
|
|
77
|
+
if (Object.keys(secure).length > 0) {
|
|
78
|
+
const key = entry ? methodTokenizerKey(entry) : undefined;
|
|
79
|
+
if (!key) throw new Error('This payment method is missing its tokenizer key');
|
|
80
|
+
// The values live inside the hosted elements, so the SDK has to interpolate them. A raw
|
|
81
|
+
// REST post would serialize the element objects instead of what the buyer typed — that
|
|
82
|
+
// path exists only for the wallet sheets, whose payload really is plain data.
|
|
83
|
+
secureTokenIntent = await tokenizeSecureFields(btRef.current, secure, key);
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
paymentMethod,
|
|
87
|
+
billingExtra,
|
|
88
|
+
secureTokenIntent
|
|
89
|
+
};
|
|
90
|
+
}, [fields, values, entry]);
|
|
91
|
+
return {
|
|
92
|
+
fields,
|
|
93
|
+
values,
|
|
94
|
+
setValue,
|
|
95
|
+
errorFor,
|
|
96
|
+
complete,
|
|
97
|
+
collect,
|
|
98
|
+
showErrors,
|
|
99
|
+
revealErrors: () => setShowErrors(true),
|
|
100
|
+
secureRefs,
|
|
101
|
+
tokenizerKey: fields.some(field => field.secure) && entry ? methodTokenizerKey(entry) : undefined,
|
|
102
|
+
btRef,
|
|
103
|
+
noteSecureComplete: (key, value) => setSecureComplete(previous => previous[key] === value ? previous : {
|
|
104
|
+
...previous,
|
|
105
|
+
[key]: value
|
|
106
|
+
}),
|
|
107
|
+
secureKey: name => `${entryKey ?? ''}:${name}`
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
export function DeclaredFields({
|
|
111
|
+
state
|
|
112
|
+
}) {
|
|
113
|
+
const t = useT();
|
|
114
|
+
if (state.fields.length === 0) return null;
|
|
115
|
+
return /*#__PURE__*/_jsxs(Stack, {
|
|
116
|
+
children: [state.tokenizerKey ? /*#__PURE__*/_jsx(SecureTokenizer, {
|
|
117
|
+
publicKey: state.tokenizerKey,
|
|
118
|
+
btRef: state.btRef
|
|
119
|
+
}) : null, state.fields.map(field => {
|
|
120
|
+
const label = fieldLabel(field.name);
|
|
121
|
+
const code = state.showErrors ? state.errorFor(field) : undefined;
|
|
122
|
+
const error = code === 'required' ? t('Required') : code === 'invalid' ? t("That doesn't look right") : undefined;
|
|
123
|
+
if (field.secure) {
|
|
124
|
+
return /*#__PURE__*/_jsx(SecureField, {
|
|
125
|
+
field: field,
|
|
126
|
+
label: label,
|
|
127
|
+
state: state
|
|
128
|
+
}, field.name);
|
|
129
|
+
}
|
|
130
|
+
return /*#__PURE__*/_jsx(Field, {
|
|
131
|
+
label: label,
|
|
132
|
+
accessibilityLabel: label,
|
|
133
|
+
value: state.values[field.name] ?? '',
|
|
134
|
+
onChangeText: value => state.setValue(field.name, value),
|
|
135
|
+
placeholder: field.placeholder,
|
|
136
|
+
error: error,
|
|
137
|
+
autoCapitalize: "characters",
|
|
138
|
+
autoCorrect: false
|
|
139
|
+
}, field.name);
|
|
140
|
+
})]
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** Constructs the Basis Theory client for a method that actually declares a secure field. */
|
|
145
|
+
function SecureTokenizer({
|
|
146
|
+
publicKey,
|
|
147
|
+
btRef
|
|
148
|
+
}) {
|
|
149
|
+
const {
|
|
150
|
+
bt
|
|
151
|
+
} = useBasisTheory(publicKey);
|
|
152
|
+
btRef.current = bt;
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
function SecureField({
|
|
156
|
+
field,
|
|
157
|
+
label,
|
|
158
|
+
state
|
|
159
|
+
}) {
|
|
160
|
+
const s = useFieldStyles();
|
|
161
|
+
const [focused, setFocused] = useState(false);
|
|
162
|
+
const note = state.noteSecureComplete;
|
|
163
|
+
return /*#__PURE__*/_jsx(FieldShell, {
|
|
164
|
+
label: label,
|
|
165
|
+
focused: focused,
|
|
166
|
+
children: /*#__PURE__*/_jsx(TextElement, {
|
|
167
|
+
btRef: instance => {
|
|
168
|
+
state.secureRefs.current[field.name] = instance;
|
|
169
|
+
if (!instance) note(state.secureKey(field.name), false);
|
|
170
|
+
},
|
|
171
|
+
onChange: event => note(state.secureKey(field.name), event?.complete === true),
|
|
172
|
+
placeholder: field.placeholder,
|
|
173
|
+
placeholderTextColor: alphaStep(s.theme.gray, 10),
|
|
174
|
+
style: {
|
|
175
|
+
color: s.input.color,
|
|
176
|
+
fontSize: s.input.fontSize,
|
|
177
|
+
fontFamily: s.input.fontFamily,
|
|
178
|
+
height: s.theme.tokens.controlHeight - 2,
|
|
179
|
+
padding: 0
|
|
180
|
+
},
|
|
181
|
+
onFocus: () => setFocused(true),
|
|
182
|
+
onBlur: () => setFocused(false)
|
|
183
|
+
})
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=declared-fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useCallback","useEffect","useMemo","useRef","useState","TextElement","useBasisTheory","fieldLabel","fieldMatches","methodTokenizerKey","tokenizeSecureFields","useT","alphaStep","Field","FieldShell","Stack","useFieldStyles","jsx","_jsx","jsxs","_jsxs","useDeclaredFields","entry","country","fields","required_fields","btRef","undefined","values","setValues","showErrors","setShowErrors","secureComplete","setSecureComplete","secureRefs","entryKey","type","current","setValue","name","value","prev","errorFor","field","secure","trim","patterns","input_formats","formats","complete","every","collect","paymentMethod","billingExtra","instance","kind","secureTokenIntent","Object","keys","length","key","Error","revealErrors","tokenizerKey","some","noteSecureComplete","previous","secureKey","DeclaredFields","state","t","children","SecureTokenizer","publicKey","map","label","code","error","SecureField","accessibilityLabel","onChangeText","placeholder","autoCapitalize","autoCorrect","bt","s","focused","setFocused","note","onChange","event","placeholderTextColor","theme","gray","style","color","input","fontSize","fontFamily","height","tokens","controlHeight","padding","onFocus","onBlur"],"sourceRoot":"../../../../src","sources":["elements/payment/declared-fields.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { Platform, Pressable, StyleSheet, Text, View } from 'react-native';
|
|
5
|
+
import { detailTemplate, formatMinorAmount, methodBillingCountries, orderRank, presentMethod } from "../../core/payments/detail.js";
|
|
6
|
+
import { PaymentsRefusalError } from "../../core/payments/refusals.js";
|
|
7
|
+
import { mergeBillingWithCollected } from "../../core/payments/billing-merge.js";
|
|
8
|
+
import { assertCardBilling, validateBillingEmail } from "../../core/payments/mint.js";
|
|
9
|
+
import { useLocale, useT } from "../../i18n/index.js";
|
|
10
|
+
import { usePaymentsState, usePaymentsStore } from "../../namespace.js";
|
|
11
|
+
import { WALLET_TYPE_FOR_PLATFORM, WhopPlatformPay } from "../../native/index.js";
|
|
12
|
+
import { alphaStep, step, useTheme } from "../../theme/provider.js";
|
|
13
|
+
import { ElementFrame } from "../../ui/element-frame.js";
|
|
14
|
+
import { ErrorFace, part, Skeleton, Stack } from "../../ui/primitives.js";
|
|
15
|
+
import { PaymentMethodIcon } from "../../ui/payment-method-icon.js";
|
|
16
|
+
import { CardElement } from "../card.js";
|
|
17
|
+
import { DeclaredFields, useDeclaredFields } from "./declared-fields.js";
|
|
18
|
+
import { mergeWalletContact } from "../../core/payments/wallet-contact.js";
|
|
19
|
+
import { collectWallet, useWalletAvailability, WalletPayButton, walletRequestFor } from "./wallet.js";
|
|
20
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
21
|
+
/**
|
|
22
|
+
* Shows the payment methods offered for this charge and collects the selected one's required
|
|
23
|
+
* fields.
|
|
24
|
+
*
|
|
25
|
+
* The offered set is the matrix filtered by the same eight `presentMethod` gates the web element
|
|
26
|
+
* applies, from the same inputs. The surface is declared `direct_checkout` because an app owns its
|
|
27
|
+
* own presentation the way a first-party document does — and unlike an iframe it can hand a
|
|
28
|
+
* full-page step to the system browser, so `full_page`-only methods stay in the list.
|
|
29
|
+
*/
|
|
30
|
+
export function PaymentElement({
|
|
31
|
+
order,
|
|
32
|
+
style,
|
|
33
|
+
fallback,
|
|
34
|
+
onChange,
|
|
35
|
+
onReady,
|
|
36
|
+
onError
|
|
37
|
+
}) {
|
|
38
|
+
const t = useT();
|
|
39
|
+
const locale = useLocale();
|
|
40
|
+
const theme = useTheme();
|
|
41
|
+
const store = usePaymentsStore();
|
|
42
|
+
const charge = usePaymentsState(s => s.charge);
|
|
43
|
+
const accountId = usePaymentsState(s => s.accountId);
|
|
44
|
+
const addressLive = usePaymentsState(s => s.addressLive);
|
|
45
|
+
// Reactive, like addressLive beside it. Read through store.getSnapshot() inside the walletRequest
|
|
46
|
+
// memo this went stale: the store's identity never changes, so clearing an email that had been
|
|
47
|
+
// present left requiresEmail false and the sheet stopped collecting one.
|
|
48
|
+
const buyerEmail = usePaymentsState(s => s.buyerEmail);
|
|
49
|
+
const options = store.getOptions();
|
|
50
|
+
const [entries, setEntries] = useState(null);
|
|
51
|
+
const [failure, setFailure] = useState(null);
|
|
52
|
+
const [selectedType, setSelectedType] = useState(undefined);
|
|
53
|
+
const currency = charge.configured ? charge.currency : undefined;
|
|
54
|
+
const amount = charge.configured ? charge.amount : undefined;
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (!accountId || !currency || amount === undefined) return;
|
|
57
|
+
let alive = true;
|
|
58
|
+
setEntries(null);
|
|
59
|
+
store.client.paymentMethodTypes.list({
|
|
60
|
+
account_id: accountId,
|
|
61
|
+
currency,
|
|
62
|
+
amount,
|
|
63
|
+
surface: store.surface
|
|
64
|
+
}).then(page => alive && setEntries(page.data)).catch(err => alive && setFailure({
|
|
65
|
+
message: err.message,
|
|
66
|
+
code: 'PAYMENT_METHODS_FAILED'
|
|
67
|
+
}));
|
|
68
|
+
return () => {
|
|
69
|
+
alive = false;
|
|
70
|
+
};
|
|
71
|
+
}, [accountId, currency, amount, store]);
|
|
72
|
+
const walletEntry = useMemo(() => entries?.find(entry => entry.type === WALLET_TYPE_FOR_PLATFORM), [entries]);
|
|
73
|
+
const walletAvailable = useWalletAvailability(walletEntry);
|
|
74
|
+
const availability = useMemo(() => {
|
|
75
|
+
if (walletAvailable === undefined) return undefined;
|
|
76
|
+
return Platform.OS === 'ios' ? {
|
|
77
|
+
applePay: walletAvailable
|
|
78
|
+
} : {
|
|
79
|
+
googlePay: walletAvailable
|
|
80
|
+
};
|
|
81
|
+
}, [walletAvailable]);
|
|
82
|
+
|
|
83
|
+
// Declared ahead of `offers`, which filters on it. A `const` read from a closure that runs during
|
|
84
|
+
// the same render is a temporal dead zone, not a hoist: this threw
|
|
85
|
+
// "Cannot access 'billingCountry' before initialization" and the element painted no tiles at all.
|
|
86
|
+
const billingCountry = usePaymentsState(s => s.addressCollected?.address?.country);
|
|
87
|
+
const offers = useMemo(() => {
|
|
88
|
+
if (!entries || !charge.configured) return [];
|
|
89
|
+
const filtered = entries.filter(entry => presentMethod(entry, charge.currency, charge.amount, charge.setupFutureUsage, availability, charge.paymentMethodConfiguration, store.surface, billingCountry));
|
|
90
|
+
const ranking = order ?? options.order ?? [];
|
|
91
|
+
return filtered.map((entry, index) => ({
|
|
92
|
+
entry,
|
|
93
|
+
index
|
|
94
|
+
})).sort((a, b) => orderRank(a.entry.type, ranking) - orderRank(b.entry.type, ranking) || a.index - b.index).map(({
|
|
95
|
+
entry
|
|
96
|
+
}) => entry);
|
|
97
|
+
}, [entries, charge, availability, order, options.order, store.surface, billingCountry]);
|
|
98
|
+
const selected = offers.find(entry => entry.type === selectedType);
|
|
99
|
+
const template = selected ? detailTemplate(selected) : undefined;
|
|
100
|
+
const declared = useDeclaredFields(selected, billingCountry);
|
|
101
|
+
const [cardComplete, setCardComplete] = useState(false);
|
|
102
|
+
const [walletCollected, setWalletCollected] = useState(null);
|
|
103
|
+
const [walletError, setWalletError] = useState(null);
|
|
104
|
+
const [walletPresenting, setWalletPresenting] = useState(false);
|
|
105
|
+
const isWallet = template === 'wallet_sheet';
|
|
106
|
+
const isCard = selected?.category === 'card';
|
|
107
|
+
const complete = Boolean(selected) && (isWallet ? Boolean(walletCollected) : isCard ? cardComplete && declared.complete : declared.complete);
|
|
108
|
+
|
|
109
|
+
// A wallet payload is bound to the sheet that produced it, and the sheet was priced. Clearing on
|
|
110
|
+
// the method alone left a token authorized for the OLD amount: `complete` stays true off that
|
|
111
|
+
// stale payload, so the button is disabled and the buyer cannot re-authorize, while confirm
|
|
112
|
+
// submits the old authorization against the new price.
|
|
113
|
+
const walletBinding = `${selectedType ?? ''}|${charge.currency}|${charge.amount}|${options.applePayMerchantId ?? ''}|${options.googlePayMerchantName ?? ''}`;
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
setWalletCollected(null);
|
|
116
|
+
setWalletError(null);
|
|
117
|
+
}, [walletBinding]);
|
|
118
|
+
|
|
119
|
+
// The first offer is selected once the list settles, so a single-method checkout needs no tap.
|
|
120
|
+
// A re-priced charge re-filters the matrix, and the selected method can drop out of it. Left
|
|
121
|
+
// alone the selection points at a type no tile renders: nothing looks selected and confirm
|
|
122
|
+
// refuses. Fall back to the new first offer.
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
if (offers.length === 0) return;
|
|
125
|
+
if (selectedType && offers.some(entry => entry.type === selectedType)) return;
|
|
126
|
+
setSelectedType(offers[0].type);
|
|
127
|
+
}, [offers, selectedType]);
|
|
128
|
+
|
|
129
|
+
// The entry's per-currency country list is the method's billing-country constraint, and "*"
|
|
130
|
+
// anywhere in it means unrestricted. A mounted address element intersects it with the
|
|
131
|
+
// integrator's own allowedCountries, so a method that only serves a few countries narrows the
|
|
132
|
+
// picker instead of letting the buyer choose one it will refuse.
|
|
133
|
+
const methodCountries = useMemo(() => charge.configured ? methodBillingCountries(selected, charge.currency) : null, [selected, charge]);
|
|
134
|
+
// The controller's mirror of the selection: the confirm dispatcher reads it, and a mounted
|
|
135
|
+
// address element narrows its country selector from it.
|
|
136
|
+
useEffect(() => {
|
|
137
|
+
store.patch({
|
|
138
|
+
selectedType,
|
|
139
|
+
selectedCategory: selected?.category,
|
|
140
|
+
selectedTemplate: template,
|
|
141
|
+
selectedComplete: complete,
|
|
142
|
+
methodCountries
|
|
143
|
+
});
|
|
144
|
+
}, [store, selectedType, selected?.category, template, complete, methodCountries]);
|
|
145
|
+
|
|
146
|
+
// Unmount only, so the mirror never outlives the surface that owns it: a still-mounted address
|
|
147
|
+
// element would otherwise keep narrowing its picker to a method the buyer can no longer see.
|
|
148
|
+
useEffect(() => () => store.patch({
|
|
149
|
+
selectedType: '',
|
|
150
|
+
selectedCategory: undefined,
|
|
151
|
+
selectedTemplate: undefined,
|
|
152
|
+
selectedComplete: false,
|
|
153
|
+
methodCountries: null
|
|
154
|
+
}), [store]);
|
|
155
|
+
const latestChange = useRef(onChange);
|
|
156
|
+
latestChange.current = onChange;
|
|
157
|
+
useEffect(() => {
|
|
158
|
+
latestChange.current?.({
|
|
159
|
+
complete,
|
|
160
|
+
type: selected?.type,
|
|
161
|
+
supportsBuyerFee: selected?.supports_buyer_fee,
|
|
162
|
+
method: selected ? {
|
|
163
|
+
type: selected.type,
|
|
164
|
+
category: selected.category,
|
|
165
|
+
template: detailTemplate(selected),
|
|
166
|
+
display_name: selected.display_name
|
|
167
|
+
} : undefined
|
|
168
|
+
});
|
|
169
|
+
}, [complete, selected]);
|
|
170
|
+
const walletRequest = useMemo(() => {
|
|
171
|
+
if (!selected || !isWallet || !charge.configured) return null;
|
|
172
|
+
return walletRequestFor(selected, {
|
|
173
|
+
currency: charge.currency,
|
|
174
|
+
amount: charge.amount,
|
|
175
|
+
merchantName: options.googlePayMerchantName ?? 'Whop',
|
|
176
|
+
applePayMerchantId: options.applePayMerchantId,
|
|
177
|
+
requiresBillingAddress: !addressLive,
|
|
178
|
+
requiresEmail: !buyerEmail
|
|
179
|
+
});
|
|
180
|
+
}, [selected, isWallet, charge, options, addressLive, buyerEmail]);
|
|
181
|
+
const collect = useCallback(async input => {
|
|
182
|
+
if (!selected) {
|
|
183
|
+
throw new PaymentsRefusalError('NO_COLLECTION_SURFACE', 'No payment method is selected');
|
|
184
|
+
}
|
|
185
|
+
if (isWallet) {
|
|
186
|
+
if (!walletCollected) {
|
|
187
|
+
throw new PaymentsRefusalError('WALLET_UNAVAILABLE', 'Tap the wallet button to authorize the payment before confirming');
|
|
188
|
+
}
|
|
189
|
+
// The sheet is asked for an email and a billing address exactly when no element is mounted
|
|
190
|
+
// to supply them, so its answers must be folded in BEFORE validation. Validating first
|
|
191
|
+
// rejected a buyer who had just typed their email into Apple Pay.
|
|
192
|
+
return {
|
|
193
|
+
paymentMethod: walletCollected.paymentMethod,
|
|
194
|
+
billingDetails: validateBillingEmail(mergeWalletContact(input?.billingDetails, walletCollected.contact))
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
const billingDetails = validateBillingEmail(input?.billingDetails);
|
|
198
|
+
if (!declared.complete) {
|
|
199
|
+
declared.revealErrors();
|
|
200
|
+
throw new PaymentsRefusalError('NO_COLLECTION_SURFACE', 'Complete the required fields for this method');
|
|
201
|
+
}
|
|
202
|
+
const values = await declared.collect();
|
|
203
|
+
if (isCard) {
|
|
204
|
+
// The address element supplies the billing NAME, and createConfirmationToken merges it
|
|
205
|
+
// only after this returns. Asserting against the seeded bag therefore rejected the
|
|
206
|
+
// default checkout — an AddressElement and a PaymentElement with no explicit
|
|
207
|
+
// billingDetails — for a name the form had already collected.
|
|
208
|
+
const settled = store.getSnapshot();
|
|
209
|
+
const withAddress = settled.addressLive ? mergeBillingWithCollected(billingDetails, settled.addressCollected) ?? billingDetails : billingDetails;
|
|
210
|
+
assertCardBilling(withAddress);
|
|
211
|
+
// The card tile mounts its own CardElement, which registers under `card`. Reaching it by
|
|
212
|
+
// kind is required: `liveSurface()` prefers `payment`, which is this very surface.
|
|
213
|
+
const cardSurface = store.surfaceOf('card');
|
|
214
|
+
if (!cardSurface) {
|
|
215
|
+
throw new PaymentsRefusalError('NO_COLLECTION_SURFACE', 'The card fields are not ready');
|
|
216
|
+
}
|
|
217
|
+
const collected = await cardSurface.collect({
|
|
218
|
+
billingDetails: withAddress
|
|
219
|
+
});
|
|
220
|
+
return {
|
|
221
|
+
paymentMethod: {
|
|
222
|
+
...collected.paymentMethod,
|
|
223
|
+
...values.paymentMethod
|
|
224
|
+
},
|
|
225
|
+
billingDetails: collected.billingDetails,
|
|
226
|
+
billingExtra: values.billingExtra
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
const categoryPayload = {
|
|
230
|
+
...values.paymentMethod
|
|
231
|
+
};
|
|
232
|
+
if (values.secureTokenIntent) categoryPayload.token_intent = values.secureTokenIntent;
|
|
233
|
+
return {
|
|
234
|
+
paymentMethod: {
|
|
235
|
+
type: selected.type,
|
|
236
|
+
category: selected.category,
|
|
237
|
+
[selected.category]: categoryPayload
|
|
238
|
+
},
|
|
239
|
+
billingDetails,
|
|
240
|
+
billingExtra: values.billingExtra
|
|
241
|
+
};
|
|
242
|
+
}, [selected, isWallet, isCard, walletCollected, declared, store]);
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* The sheet's own verdict settles at tokenization, not at confirm.
|
|
246
|
+
*
|
|
247
|
+
* Holding it open until the server answers needs the deferred-conclusion rail the composed
|
|
248
|
+
* checkout arms; a standalone payment element has no such rail on the web either, and its
|
|
249
|
+
* confirm is server-side and unobservable from here. A refused confirm therefore surfaces in the
|
|
250
|
+
* app's own UI rather than in the sheet.
|
|
251
|
+
*/
|
|
252
|
+
const presentWallet = useCallback(async () => {
|
|
253
|
+
if (!selected || !walletRequest || walletPresenting) return;
|
|
254
|
+
setWalletError(null);
|
|
255
|
+
setWalletPresenting(true);
|
|
256
|
+
try {
|
|
257
|
+
setWalletCollected(await collectWallet(selected, walletRequest));
|
|
258
|
+
WhopPlatformPay.complete(true);
|
|
259
|
+
} catch (err) {
|
|
260
|
+
WhopPlatformPay.complete(false);
|
|
261
|
+
const refused = err instanceof PaymentsRefusalError && err.code === 'WALLET_UNAVAILABLE';
|
|
262
|
+
// A dismissal is an outcome, not a failure.
|
|
263
|
+
if (!refused) setWalletError(err instanceof Error ? err.message : String(err));
|
|
264
|
+
} finally {
|
|
265
|
+
setWalletPresenting(false);
|
|
266
|
+
}
|
|
267
|
+
}, [selected, walletRequest, walletPresenting]);
|
|
268
|
+
|
|
269
|
+
// The payment element owns the selection, so it registers ahead of a bare card unit.
|
|
270
|
+
const latestCollect = useRef(collect);
|
|
271
|
+
latestCollect.current = collect;
|
|
272
|
+
useEffect(() => store.registerSurface({
|
|
273
|
+
kind: 'payment',
|
|
274
|
+
collect: input => latestCollect.current(input)
|
|
275
|
+
}), [store]);
|
|
276
|
+
const ready = entries !== null && (walletEntry === undefined || walletAvailable !== undefined);
|
|
277
|
+
return /*#__PURE__*/_jsx(ElementFrame, {
|
|
278
|
+
style: style,
|
|
279
|
+
fallback: fallback,
|
|
280
|
+
skeleton: /*#__PURE__*/_jsxs(Stack, {
|
|
281
|
+
children: [/*#__PURE__*/_jsx(Skeleton, {
|
|
282
|
+
height: 56
|
|
283
|
+
}), /*#__PURE__*/_jsx(Skeleton, {
|
|
284
|
+
height: 56
|
|
285
|
+
}), /*#__PURE__*/_jsx(Skeleton, {
|
|
286
|
+
height: 56
|
|
287
|
+
})]
|
|
288
|
+
}),
|
|
289
|
+
ready: ready,
|
|
290
|
+
error: failure,
|
|
291
|
+
onReady: onReady,
|
|
292
|
+
onError: onError,
|
|
293
|
+
children: offers.length === 0 && entries !== null ? /*#__PURE__*/_jsx(View, {
|
|
294
|
+
style: {
|
|
295
|
+
padding: theme.tokens.spacing * 4,
|
|
296
|
+
borderRadius: theme.tokens.radius,
|
|
297
|
+
backgroundColor: alphaStep(theme.gray, 2)
|
|
298
|
+
},
|
|
299
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
300
|
+
style: {
|
|
301
|
+
color: step(theme.gray, 11),
|
|
302
|
+
fontSize: theme.tokens.fontSize
|
|
303
|
+
},
|
|
304
|
+
children: t('No payment methods are available')
|
|
305
|
+
})
|
|
306
|
+
}) : /*#__PURE__*/_jsx(Stack, {
|
|
307
|
+
children: offers.map(entry => {
|
|
308
|
+
const active = entry.type === selectedType;
|
|
309
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
310
|
+
children: [/*#__PURE__*/_jsx(MethodTile, {
|
|
311
|
+
entry: entry,
|
|
312
|
+
active: active,
|
|
313
|
+
amountLabel: charge.configured ? formatMinorAmount(charge.amount, charge.currency, locale) : undefined,
|
|
314
|
+
onPress: () => setSelectedType(entry.type)
|
|
315
|
+
}), active ? /*#__PURE__*/_jsxs(View, {
|
|
316
|
+
style: [styles.detail, part(theme, 'whop-PaymentMethodDetail')],
|
|
317
|
+
children: [isCard ? /*#__PURE__*/_jsx(CardElement, {
|
|
318
|
+
onChange: payload => setCardComplete(payload.complete)
|
|
319
|
+
}) : null, /*#__PURE__*/_jsx(DeclaredFields, {
|
|
320
|
+
state: declared
|
|
321
|
+
}), isWallet && walletRequest ? /*#__PURE__*/_jsxs(_Fragment, {
|
|
322
|
+
children: [/*#__PURE__*/_jsx(WalletPayButton, {
|
|
323
|
+
onPress: presentWallet,
|
|
324
|
+
disabled: walletPresenting || Boolean(walletCollected)
|
|
325
|
+
}), walletError ? /*#__PURE__*/_jsx(ErrorFace, {
|
|
326
|
+
message: walletError
|
|
327
|
+
}) : null]
|
|
328
|
+
}) : null]
|
|
329
|
+
}) : null]
|
|
330
|
+
}, entry.type);
|
|
331
|
+
})
|
|
332
|
+
})
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
function MethodTile({
|
|
336
|
+
entry,
|
|
337
|
+
active,
|
|
338
|
+
amountLabel,
|
|
339
|
+
onPress
|
|
340
|
+
}) {
|
|
341
|
+
const theme = useTheme();
|
|
342
|
+
return /*#__PURE__*/_jsxs(Pressable, {
|
|
343
|
+
accessibilityRole: "radio",
|
|
344
|
+
accessibilityState: {
|
|
345
|
+
selected: active
|
|
346
|
+
},
|
|
347
|
+
accessibilityLabel: entry.display_name,
|
|
348
|
+
onPress: onPress,
|
|
349
|
+
style: ({
|
|
350
|
+
pressed
|
|
351
|
+
}) => [styles.tile, {
|
|
352
|
+
minHeight: theme.tokens.controlHeight + 12,
|
|
353
|
+
borderRadius: theme.tokens.radius,
|
|
354
|
+
borderWidth: theme.tokens.borderWidth,
|
|
355
|
+
borderColor: active ? step(theme.accent, 8) : alphaStep(theme.gray, 6),
|
|
356
|
+
backgroundColor: pressed ? alphaStep(theme.gray, 2) : step(theme.gray, 1),
|
|
357
|
+
paddingHorizontal: theme.tokens.spacing * 3
|
|
358
|
+
}, part(theme, 'whop-PaymentMethodTile'), active ? part(theme, 'whop-PaymentMethodRowSelected') : null],
|
|
359
|
+
children: [/*#__PURE__*/_jsx(View, {
|
|
360
|
+
style: [styles.radio, {
|
|
361
|
+
borderColor: active ? step(theme.accent, 9) : alphaStep(theme.gray, 7)
|
|
362
|
+
}],
|
|
363
|
+
children: active ? /*#__PURE__*/_jsx(View, {
|
|
364
|
+
style: [styles.dot, {
|
|
365
|
+
backgroundColor: step(theme.accent, 9)
|
|
366
|
+
}]
|
|
367
|
+
}) : null
|
|
368
|
+
}), /*#__PURE__*/_jsx(PaymentMethodIcon, {
|
|
369
|
+
icons: entry.icons,
|
|
370
|
+
size: 20
|
|
371
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
372
|
+
numberOfLines: 1,
|
|
373
|
+
style: [{
|
|
374
|
+
flexShrink: 1,
|
|
375
|
+
fontSize: theme.tokens.fontSize,
|
|
376
|
+
fontFamily: theme.tokens.fontFamily,
|
|
377
|
+
color: step(theme.gray, 12)
|
|
378
|
+
}, part(theme, 'whop-MethodTileLabel')],
|
|
379
|
+
children: entry.display_name
|
|
380
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
381
|
+
style: styles.spacer
|
|
382
|
+
}), entry.category === 'card' && !active ? /*#__PURE__*/_jsx(BrandStrip, {
|
|
383
|
+
networks: entry.card?.networks
|
|
384
|
+
}) : null, amountLabel ? /*#__PURE__*/_jsx(Text, {
|
|
385
|
+
style: {
|
|
386
|
+
fontSize: theme.tokens.labelFontSize,
|
|
387
|
+
color: step(theme.gray, 11)
|
|
388
|
+
},
|
|
389
|
+
children: amountLabel
|
|
390
|
+
}) : null]
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/** The card row's accepted-network art. API art only: an entry without networks renders nothing,
|
|
395
|
+
* the same rule the card fields follow. Tiles overlap left-under-right with the first on top,
|
|
396
|
+
* which is the web strip's stacking without its mask moat (React Native has no mask). */
|
|
397
|
+
function BrandStrip({
|
|
398
|
+
networks
|
|
399
|
+
}) {
|
|
400
|
+
const strip = (networks ?? []).slice(0, BRAND_STRIP_TILES);
|
|
401
|
+
if (strip.length === 0) return null;
|
|
402
|
+
return /*#__PURE__*/_jsx(View, {
|
|
403
|
+
style: styles.row,
|
|
404
|
+
children: strip.map((network, index) => /*#__PURE__*/_jsx(View, {
|
|
405
|
+
style: {
|
|
406
|
+
marginLeft: index > 0 ? -8 : 0,
|
|
407
|
+
zIndex: strip.length - index
|
|
408
|
+
},
|
|
409
|
+
children: /*#__PURE__*/_jsx(PaymentMethodIcon, {
|
|
410
|
+
icons: network.icons,
|
|
411
|
+
size: 19
|
|
412
|
+
})
|
|
413
|
+
}, network.brand))
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
const BRAND_STRIP_TILES = 4;
|
|
417
|
+
const styles = StyleSheet.create({
|
|
418
|
+
tile: {
|
|
419
|
+
flexDirection: 'row',
|
|
420
|
+
alignItems: 'center',
|
|
421
|
+
gap: 12
|
|
422
|
+
},
|
|
423
|
+
row: {
|
|
424
|
+
flexDirection: 'row',
|
|
425
|
+
alignItems: 'center'
|
|
426
|
+
},
|
|
427
|
+
spacer: {
|
|
428
|
+
flex: 1
|
|
429
|
+
},
|
|
430
|
+
radio: {
|
|
431
|
+
width: 18,
|
|
432
|
+
height: 18,
|
|
433
|
+
borderRadius: 9,
|
|
434
|
+
borderWidth: 1.5,
|
|
435
|
+
alignItems: 'center',
|
|
436
|
+
justifyContent: 'center'
|
|
437
|
+
},
|
|
438
|
+
dot: {
|
|
439
|
+
width: 8,
|
|
440
|
+
height: 8,
|
|
441
|
+
borderRadius: 4
|
|
442
|
+
},
|
|
443
|
+
detail: {
|
|
444
|
+
paddingTop: 12,
|
|
445
|
+
gap: 12
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
//# sourceMappingURL=index.js.map
|