From f295e9d0c4069b8c0b03425a91061a65545251d6 Mon Sep 17 00:00:00 2001 From: Kaushil Ruparelia Date: Thu, 30 Jan 2025 22:38:03 -0500 Subject: [PATCH] [Fix] Fixes #1812 CardField onCardChange not triggering in React Native Stripe - Updated CardChangedEvent and CardFocusEvent to conform to the Fabric protocol - Updates the dispatcher in CardFieldView to Fabric compatible code - Checks the id of the view before dispatching the events in a case where the event is fired before the render is complete, thereby causing the id to be -1. This also leads to the following error > Maximum call stack size exceeded (native stack depth) No stack --- .../reactnativestripesdk/CardChangedEvent.kt | 13 ++++--------- .../com/reactnativestripesdk/CardFieldView.kt | 18 ++++++++++++------ .../com/reactnativestripesdk/CardFocusEvent.kt | 12 ++++-------- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/android/src/main/java/com/reactnativestripesdk/CardChangedEvent.kt b/android/src/main/java/com/reactnativestripesdk/CardChangedEvent.kt index d97252ba8..855e06617 100644 --- a/android/src/main/java/com/reactnativestripesdk/CardChangedEvent.kt +++ b/android/src/main/java/com/reactnativestripesdk/CardChangedEvent.kt @@ -3,18 +3,13 @@ package com.reactnativestripesdk import com.facebook.react.bridge.Arguments import com.facebook.react.bridge.WritableMap import com.facebook.react.uimanager.events.Event -import com.facebook.react.uimanager.events.RCTEventEmitter internal class CardChangedEvent constructor(viewTag: Int, private val cardDetails: MutableMap, private val postalCodeEnabled: Boolean, private val complete: Boolean, private val dangerouslyGetFullCardDetails: Boolean) : Event(viewTag) { - override fun getEventName(): String { - return EVENT_NAME - } - - override fun dispatch(rctEventEmitter: RCTEventEmitter) { - rctEventEmitter.receiveEvent(viewTag, eventName, serializeEventData()) - } + override fun getEventName() = EVENT_NAME - private fun serializeEventData(): WritableMap { + override fun getCoalescingKey(): Short = 0 + + override fun getEventData(): WritableMap { val eventData = Arguments.createMap() eventData.putString("brand", cardDetails["brand"]?.toString()) eventData.putString("last4", cardDetails["last4"]?.toString()) diff --git a/android/src/main/java/com/reactnativestripesdk/CardFieldView.kt b/android/src/main/java/com/reactnativestripesdk/CardFieldView.kt index 2ac656f66..129c8637a 100644 --- a/android/src/main/java/com/reactnativestripesdk/CardFieldView.kt +++ b/android/src/main/java/com/reactnativestripesdk/CardFieldView.kt @@ -10,10 +10,12 @@ import android.text.TextWatcher import android.util.Log import android.widget.FrameLayout import androidx.core.os.LocaleListCompat +import com.facebook.react.bridge.ReactContext import com.facebook.react.bridge.ReadableMap import com.facebook.react.uimanager.PixelUtil import com.facebook.react.uimanager.ThemedReactContext -import com.facebook.react.uimanager.UIManagerModule +import com.facebook.react.uimanager.UIManagerHelper +import com.facebook.react.uimanager.events.Event import com.facebook.react.uimanager.events.EventDispatcher import com.facebook.react.views.text.ReactTypefaceUtils import com.google.android.material.shape.CornerFamily @@ -37,7 +39,7 @@ class CardFieldView(context: ThemedReactContext) : FrameLayout(context) { val cardDetails: MutableMap = mutableMapOf("brand" to "", "last4" to "", "expiryMonth" to null, "expiryYear" to null, "postalCode" to "", "validNumber" to "Unknown", "validCVC" to "Unknown", "validExpiryDate" to "Unknown") var cardParams: PaymentMethodCreateParams.Card? = null var cardAddress: Address? = null - private var mEventDispatcher: EventDispatcher? = context.getNativeModule(UIManagerModule::class.java)?.eventDispatcher + private var mEventDispatcher: EventDispatcher? = UIManagerHelper.getEventDispatcherForReactTag(context as ReactContext, id) private var dangerouslyGetFullCardDetails: Boolean = false private var currentFocusedField: String? = null private var isCardValid = false @@ -81,8 +83,10 @@ class CardFieldView(context: ThemedReactContext) : FrameLayout(context) { } private fun onChangeFocus() { - mEventDispatcher?.dispatchEvent( - CardFocusEvent(id, currentFocusedField)) + if (id != -1 ) { + val event: Event = CardFocusEvent(id, currentFocusedField); + mEventDispatcher?.dispatchEvent(event) + } } fun setCardStyle(value: ReadableMap) { @@ -262,8 +266,10 @@ class CardFieldView(context: ThemedReactContext) : FrameLayout(context) { } private fun sendCardDetailsEvent() { - mEventDispatcher?.dispatchEvent( - CardChangedEvent(id, cardDetails, mCardWidget.postalCodeEnabled, isCardValid, dangerouslyGetFullCardDetails)) + if (id != -1 ) { + val event: Event = CardChangedEvent(id, cardDetails, mCardWidget.postalCodeEnabled, isCardValid, dangerouslyGetFullCardDetails); + mEventDispatcher?.dispatchEvent(event) + } } private fun setListeners() { diff --git a/android/src/main/java/com/reactnativestripesdk/CardFocusEvent.kt b/android/src/main/java/com/reactnativestripesdk/CardFocusEvent.kt index 84ee559ed..fe1b8bdd4 100644 --- a/android/src/main/java/com/reactnativestripesdk/CardFocusEvent.kt +++ b/android/src/main/java/com/reactnativestripesdk/CardFocusEvent.kt @@ -1,19 +1,15 @@ package com.reactnativestripesdk + import com.facebook.react.bridge.Arguments import com.facebook.react.bridge.WritableMap import com.facebook.react.uimanager.events.Event -import com.facebook.react.uimanager.events.RCTEventEmitter internal class CardFocusEvent constructor(viewTag: Int, private val focusField: String?) : Event(viewTag) { - override fun getEventName(): String { - return EVENT_NAME - } + override fun getEventName() = EVENT_NAME - override fun dispatch(rctEventEmitter: RCTEventEmitter) { - rctEventEmitter.receiveEvent(viewTag, eventName, serializeEventData()) - } + override fun getCoalescingKey(): Short = 0 - private fun serializeEventData(): WritableMap { + override fun getEventData(): WritableMap { val eventData = Arguments.createMap() eventData.putString("focusedField", focusField)