From 6b834cea5dec3f206d274181057239ae1756f390 Mon Sep 17 00:00:00 2001 From: charliecruzan-stripe <97612659+charliecruzan-stripe@users.noreply.github.com> Date: Tue, 30 May 2023 13:16:32 -0400 Subject: [PATCH] feat: add disabled prop to CardField and CardForm (#1403) * feat: add disabled prop to CardField and CardForm * [skip actions] changelog --- CHANGELOG.md | 4 ++++ .../com/reactnativestripesdk/CardFieldView.kt | 4 ++++ .../CardFieldViewManager.kt | 5 +++++ .../com/reactnativestripesdk/CardFormView.kt | 4 ++++ .../CardFormViewManager.kt | 5 +++++ .../screens/MultilineWebhookPaymentScreen.tsx | 4 ++++ example/src/screens/WebhookPaymentScreen.tsx | 4 +++- ios/CardFieldManager.m | 1 + ios/CardFieldView.swift | 6 ++++++ ios/CardFormManager.m | 4 ++-- ios/CardFormView.swift | 18 +++++++++--------- src/components/CardField.tsx | 2 ++ src/components/CardForm.tsx | 6 ++---- src/types/components/CardFieldInput.ts | 1 + src/types/components/CardFormView.ts | 2 +- 15 files changed, 53 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bdaa56d1b..57ca2cb5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## Features + +- Added a `disabled` prop to `CardField` and `CardForm` which applies a disabled state such that user input is not accepted. [#1403](https://github.com/stripe/stripe-react-native/pull/1403) + ## Fixes - Fixed an instance on Android where `collectBankAccountToken` or `collectFinancialConnectionsAccounts` could result in a fatal error. [#1401](https://github.com/stripe/stripe-react-native/pull/1401) diff --git a/android/src/main/java/com/reactnativestripesdk/CardFieldView.kt b/android/src/main/java/com/reactnativestripesdk/CardFieldView.kt index 53b7c2063..8e4cf6b08 100644 --- a/android/src/main/java/com/reactnativestripesdk/CardFieldView.kt +++ b/android/src/main/java/com/reactnativestripesdk/CardFieldView.kt @@ -209,6 +209,10 @@ class CardFieldView(context: ThemedReactContext) : FrameLayout(context) { } } + fun setDisabled(isDisabled: Boolean) { + mCardWidget.isEnabled = !isDisabled + } + /** * We can reliable assume that setPostalCodeEnabled is called before * setCountryCode because of the order of the props in CardField.tsx diff --git a/android/src/main/java/com/reactnativestripesdk/CardFieldViewManager.kt b/android/src/main/java/com/reactnativestripesdk/CardFieldViewManager.kt index 5d18e7d2f..0daaa60d5 100644 --- a/android/src/main/java/com/reactnativestripesdk/CardFieldViewManager.kt +++ b/android/src/main/java/com/reactnativestripesdk/CardFieldViewManager.kt @@ -56,6 +56,11 @@ class CardFieldViewManager : SimpleViewManager() { view.setPlaceHolders(placeholders) } + @ReactProp(name = "disabled") + fun setDisabled(view: CardFieldView, isDisabled: Boolean) { + view.setDisabled(isDisabled) + } + override fun createViewInstance(reactContext: ThemedReactContext): CardFieldView { val stripeSdkModule: StripeSdkModule? = reactContext.getNativeModule(StripeSdkModule::class.java) val view = CardFieldView(reactContext) diff --git a/android/src/main/java/com/reactnativestripesdk/CardFormView.kt b/android/src/main/java/com/reactnativestripesdk/CardFormView.kt index 6fc3cd4e1..b78d45716 100644 --- a/android/src/main/java/com/reactnativestripesdk/CardFormView.kt +++ b/android/src/main/java/com/reactnativestripesdk/CardFormView.kt @@ -58,6 +58,10 @@ class CardFormView(context: ThemedReactContext) : FrameLayout(context) { setCountry(defaults.getString("countryCode")) } + fun setDisabled(isDisabled: Boolean) { + cardForm.isEnabled = !isDisabled + } + private fun setCountry(countryString: String?) { if (countryString != null) { cardFormViewBinding.countryLayout.setSelectedCountryCode(CountryCode(countryString)) diff --git a/android/src/main/java/com/reactnativestripesdk/CardFormViewManager.kt b/android/src/main/java/com/reactnativestripesdk/CardFormViewManager.kt index c5e5c123d..0659f27f5 100644 --- a/android/src/main/java/com/reactnativestripesdk/CardFormViewManager.kt +++ b/android/src/main/java/com/reactnativestripesdk/CardFormViewManager.kt @@ -56,6 +56,11 @@ class CardFormViewManager : SimpleViewManager() { view.setDefaultValues(defaults) } + @ReactProp(name = "disabled") + fun setDisabled(view: CardFormView, isDisabled: Boolean) { + view.setDisabled(isDisabled) + } + override fun createViewInstance(reactContext: ThemedReactContext): CardFormView { val stripeSdkModule: StripeSdkModule? = reactContext.getNativeModule(StripeSdkModule::class.java) val view = CardFormView(reactContext) diff --git a/example/src/screens/MultilineWebhookPaymentScreen.tsx b/example/src/screens/MultilineWebhookPaymentScreen.tsx index 32d2e4c76..d16f0a4c3 100644 --- a/example/src/screens/MultilineWebhookPaymentScreen.tsx +++ b/example/src/screens/MultilineWebhookPaymentScreen.tsx @@ -19,6 +19,7 @@ export default function MultilineWebhookPaymentScreen() { const [email, setEmail] = useState(''); const [saveCard, setSaveCard] = useState(false); const [isComplete, setComplete] = useState(false); + const [inputDisabled, setInputDisabled] = useState(false); const { confirmPayment, loading } = useConfirmPayment(); @@ -42,6 +43,7 @@ export default function MultilineWebhookPaymentScreen() { const handlePayPress = async () => { setComplete(false); + setInputDisabled(true); // 1. fetch Intent Client Secret from backend const clientSecret = await fetchPaymentIntentClientSecret(); @@ -80,6 +82,7 @@ export default function MultilineWebhookPaymentScreen() { console.log('Success from promise', paymentIntent); } setComplete(true); + setInputDisabled(false); }; return ( @@ -92,6 +95,7 @@ export default function MultilineWebhookPaymentScreen() { style={styles.input} /> { + setCanPay(false); // 1. fetch Intent Client Secret from backend const clientSecret = await fetchPaymentIntentClientSecret(); @@ -51,7 +52,7 @@ export default function WebhookPaymentScreen() { postalCode: '77063', }, }; // mocked data for tests - setCanPay(false); + // 3. Confirm payment with card details // The rest will be done automatically using webhooks const { error, paymentIntent } = await confirmPayment( @@ -90,6 +91,7 @@ export default function WebhookPaymentScreen() { style={styles.input} /> ; autofocus?: boolean; testID?: string; - + /** Applies a disabled state such that user input is not accepted. Defaults to false. */ + disabled?: boolean; /** All styles except backgroundColor, cursorColor, borderColor, and borderRadius are Android only */ cardStyle?: CardFormView.Styles; - // isUserInteractionEnabled?: boolean; // TODO: will make it public when iOS SDK allows for this // postalCodeEnabled?: boolean; @@ -78,7 +78,6 @@ export const CardForm = forwardRef( { onFormComplete, cardStyle, - // isUserInteractionEnabled = true, // postalCodeEnabled = true, // onFocus, // onBlur, @@ -181,7 +180,6 @@ export const CardForm = forwardRef( // disabledBackgroundColor: cardStyle?.disabledBackgroundColor, // type: cardStyle?.type, }} - // isUserInteractionEnabledValue={isUserInteractionEnabled} placeholders={{ number: placeholders?.number, expiration: placeholders?.expiration, diff --git a/src/types/components/CardFieldInput.ts b/src/types/components/CardFieldInput.ts index 26226f166..b666e3b85 100644 --- a/src/types/components/CardFieldInput.ts +++ b/src/types/components/CardFieldInput.ts @@ -66,6 +66,7 @@ export interface NativeProps { ): void; cardStyle?: Styles; placeholders?: Placeholders; + disabled?: boolean; } export interface Methods { diff --git a/src/types/components/CardFormView.ts b/src/types/components/CardFormView.ts index 1d3a98010..d6567338b 100644 --- a/src/types/components/CardFormView.ts +++ b/src/types/components/CardFormView.ts @@ -55,7 +55,6 @@ export type DefaultValues = { export interface NativeProps { style?: StyleProp; autofocus?: boolean; - // isUserInteractionEnabledValue?: boolean; cardStyle?: Styles; /** Android only */ placeholders?: Placeholders; @@ -66,6 +65,7 @@ export interface NativeProps { event: NativeSyntheticEvent<{ focusedField: FieldName | null }> ): void; onFormComplete(event: NativeSyntheticEvent
): void; + disabled?: boolean; } export interface Methods {