diff --git a/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt b/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt index c397449e5..cef09eacc 100644 --- a/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +++ b/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt @@ -23,8 +23,7 @@ import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncher import com.stripe.android.model.* import com.stripe.android.paymentsheet.PaymentSheetResult import com.stripe.android.view.AddPaymentMethodActivityStarter -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.* @ReactModule(name = StripeSdkModule.NAME) class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { @@ -406,67 +405,16 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ fun createToken(params: ReadableMap, promise: Promise) { val type = getValOr(params, "type", null) if (type == null) { - promise.resolve(createError(CreateTokenErrorType.Failed.toString(), "type is required")) + promise.resolve(createError(CreateTokenErrorType.Failed.toString(), "type parameter is required")) return } when (type) { "BankAccount" -> { - val accountHolderName = getValOr(params, "accountHolderName") - val accountHolderType = getValOr(params, "accountHolderType") - val accountNumber = getValOr(params, "accountNumber", null) - val country = getValOr(params, "country", null) - val currency = getValOr(params, "currency", null) - val routingNumber = getValOr(params, "routingNumber") - - runCatching { - val bankAccountParams = BankAccountTokenParams( - country = country!!, - currency = currency!!, - accountNumber = accountNumber!!, - accountHolderName = accountHolderName, - routingNumber = routingNumber, - accountHolderType = mapToBankAccountType(accountHolderType) - ) - runBlocking { - val token = stripe.createBankAccountToken(bankAccountParams, null, stripeAccountId) - promise.resolve(createResult("token", mapFromToken(token))) - } - }.onFailure { - promise.resolve(createError(CreateTokenErrorType.Failed.toString(), it.message)) - } + createTokenFromBankAccount(params, promise) } "Card" -> { - val cardParamsMap = (cardFieldView?.cardParams ?: cardFormView?.cardParams)?.toParamMap() - ?: run { - promise.resolve(createError(CreateTokenErrorType.Failed.toString(), "Card details not complete")) - return - } - - val cardAddress = cardFieldView?.cardAddress ?: cardFormView?.cardAddress - val address = getMapOrNull(params, "address") - val cardParams = CardParams( - number = cardParamsMap["number"] as String, - expMonth = cardParamsMap["exp_month"] as Int, - expYear = cardParamsMap["exp_year"] as Int, - cvc = cardParamsMap["cvc"] as String, - address = mapToAddress(address, cardAddress), - name = getValOr(params, "name", null) - ) - runBlocking { - try { - val token = stripe.createCardToken( - cardParams = cardParams, - stripeAccountId = stripeAccountId - ) - promise.resolve(createResult("token", mapFromToken(token))) - } catch (e: Exception) { - promise.resolve(createError(CreateTokenErrorType.Failed.toString(), e.message)) - } - } - } - null -> { - promise.resolve(createError(CreateTokenErrorType.Failed.toString(), "type is required")) + createTokenFromCard(params, promise) } else -> { promise.resolve(createError(CreateTokenErrorType.Failed.toString(), "$type type is not supported yet")) @@ -474,6 +422,63 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ } } + private fun createTokenFromBankAccount(params: ReadableMap, promise: Promise) { + val accountHolderName = getValOr(params, "accountHolderName") + val accountHolderType = getValOr(params, "accountHolderType") + val accountNumber = getValOr(params, "accountNumber", null) + val country = getValOr(params, "country", null) + val currency = getValOr(params, "currency", null) + val routingNumber = getValOr(params, "routingNumber") + + runCatching { + val bankAccountParams = BankAccountTokenParams( + country = country!!, + currency = currency!!, + accountNumber = accountNumber!!, + accountHolderName = accountHolderName, + routingNumber = routingNumber, + accountHolderType = mapToBankAccountType(accountHolderType) + ) + CoroutineScope(Dispatchers.IO).launch { + val token = stripe.createBankAccountToken(bankAccountParams, null, stripeAccountId) + promise.resolve(createResult("token", mapFromToken(token))) + } + }.onFailure { + promise.resolve(createError(CreateTokenErrorType.Failed.toString(), it.message)) + } + } + + private fun createTokenFromCard(params: ReadableMap, promise: Promise) { + val cardParamsMap = (cardFieldView?.cardParams ?: cardFormView?.cardParams)?.toParamMap() + ?: run { + promise.resolve(createError(CreateTokenErrorType.Failed.toString(), "Card details not complete")) + return + } + + val cardAddress = cardFieldView?.cardAddress ?: cardFormView?.cardAddress + val address = getMapOrNull(params, "address") + val cardParams = CardParams( + number = cardParamsMap["number"] as String, + expMonth = cardParamsMap["exp_month"] as Int, + expYear = cardParamsMap["exp_year"] as Int, + cvc = cardParamsMap["cvc"] as String, + address = mapToAddress(address, cardAddress), + name = getValOr(params, "name", null) + ) + + CoroutineScope(Dispatchers.IO).launch { + try { + val token = stripe.createCardToken( + cardParams = cardParams, + stripeAccountId = stripeAccountId + ) + promise.resolve(createResult("token", mapFromToken(token))) + } catch (e: Exception) { + promise.resolve(createError(CreateTokenErrorType.Failed.toString(), e.message)) + } + } + } + @ReactMethod fun createTokenForCVCUpdate(cvc: String, promise: Promise) { stripe.createCvcUpdateToken( diff --git a/ios/StripeSdk.swift b/ios/StripeSdk.swift index 3c2caccaf..8b3b8ca10 100644 --- a/ios/StripeSdk.swift +++ b/ios/StripeSdk.swift @@ -536,43 +536,55 @@ class StripeSdk: RCTEventEmitter, STPApplePayContextDelegate, STPBankSelectionVi resolve(Errors.createError(CreateTokenErrorType.Failed.rawValue, "type parameter is required")) return } - - if (type != "Card" && type != "BankAccount") { + + // TODO: Consider moving this to its own class when more types are supported. + switch type { + case "BankAccount": + createTokenFromBankAccount(params: params, resolver: resolve, rejecter: reject) + case "Card": + createTokenFromCard(params: params, resolver: resolve, rejecter: reject) + default: resolve(Errors.createError(CreateTokenErrorType.Failed.rawValue, type + " type is not supported yet")) - return } - - // TODO: create a service for creating tokens from a difference sources. - if (type == "BankAccount") { - let accountHolderName = params["accountHolderName"] as? String - let accountHolderType = params["accountHolderType"] as? String - let accountNumber = params["accountNumber"] as? String - let country = params["country"] as? String - let currency = params["currency"] as? String - let routingNumber = params["routingNumber"] as? String + } + + func createTokenFromBankAccount( + params: NSDictionary, + resolver resolve: @escaping RCTPromiseResolveBlock, + rejecter reject: @escaping RCTPromiseRejectBlock + ) -> Void { + let accountHolderName = params["accountHolderName"] as? String + let accountHolderType = params["accountHolderType"] as? String + let accountNumber = params["accountNumber"] as? String + let country = params["country"] as? String + let currency = params["currency"] as? String + let routingNumber = params["routingNumber"] as? String - let bankAccountParams = STPBankAccountParams() - bankAccountParams.accountHolderName = accountHolderName - bankAccountParams.accountNumber = accountNumber - bankAccountParams.country = country - bankAccountParams.currency = currency - bankAccountParams.routingNumber = routingNumber - - if let holderType = Mappers.mapToBankAccountHolderType(accountHolderType) { - bankAccountParams.accountHolderType = holderType - } - - STPAPIClient.shared.createToken(withBankAccount: bankAccountParams) { token, error in - if let token = token { - resolve(Mappers.createResult("token", Mappers.mapFromToken(token: token))) - } else { - resolve(Errors.createError(CreateTokenErrorType.Failed.rawValue, error?.localizedDescription)) - } - } - return - } + let bankAccountParams = STPBankAccountParams() + bankAccountParams.accountHolderName = accountHolderName + bankAccountParams.accountNumber = accountNumber + bankAccountParams.country = country + bankAccountParams.currency = currency + bankAccountParams.routingNumber = routingNumber + if let holderType = Mappers.mapToBankAccountHolderType(accountHolderType) { + bankAccountParams.accountHolderType = holderType + } + STPAPIClient.shared.createToken(withBankAccount: bankAccountParams) { token, error in + if let token = token { + resolve(Mappers.createResult("token", Mappers.mapFromToken(token: token))) + } else { + resolve(Errors.createError(CreateTokenErrorType.Failed.rawValue, error?.localizedDescription)) + } + } + } + + func createTokenFromCard( + params: NSDictionary, + resolver resolve: @escaping RCTPromiseResolveBlock, + rejecter reject: @escaping RCTPromiseRejectBlock + ) -> Void { guard let cardParams = cardFieldView?.cardParams ?? cardFormView?.cardParams else { resolve(Errors.createError(CreateTokenErrorType.Failed.rawValue, "Card details not complete")) return