Skip to content

Commit

Permalink
Update stripe-react-native to 0.18.1 to fix compilation errors in Xco…
Browse files Browse the repository at this point in the history
…de 14
  • Loading branch information
tsapeta committed Sep 13, 2022
1 parent c9efd57 commit 7c2c37d
Show file tree
Hide file tree
Showing 32 changed files with 2,888 additions and 139 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Package-specific changes not released in any SDK will be added here just before

### 📚 3rd party library updates

- Updated `@stripe/stripe-react-native` from `0.13.1` to `0.18.1`.

### 🛠 Breaking changes

### 🎉 New features
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
package versioned.host.exp.exponent.modules.api.components.reactnativestripesdk

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import com.facebook.react.bridge.*
import versioned.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.*
import versioned.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.createError
import versioned.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.createMissingActivityError
import versioned.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.mapFromToken
import com.stripe.android.financialconnections.FinancialConnectionsSheet
import com.stripe.android.financialconnections.FinancialConnectionsSheetForTokenResult
import com.stripe.android.financialconnections.FinancialConnectionsSheetResult
import com.stripe.android.financialconnections.model.*

class FinancialConnectionsSheetFragment : Fragment() {
enum class Mode {
ForToken, ForSession
}

private lateinit var promise: Promise
private lateinit var context: ReactApplicationContext
private lateinit var configuration: FinancialConnectionsSheet.Configuration
private lateinit var mode: Mode

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
return FrameLayout(requireActivity()).also {
it.visibility = View.GONE
}
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
when (mode) {
Mode.ForToken -> {
FinancialConnectionsSheet.createForBankAccountToken(
this,
::onFinancialConnectionsSheetForTokenResult
).present(
configuration = configuration
)
}
Mode.ForSession -> {
FinancialConnectionsSheet.create(
this,
::onFinancialConnectionsSheetForDataResult
).present(
configuration = configuration
)
}
}
}

private fun onFinancialConnectionsSheetForTokenResult(result: FinancialConnectionsSheetForTokenResult) {
when(result) {
is FinancialConnectionsSheetForTokenResult.Canceled -> {
promise.resolve(
createError(ErrorType.Canceled.toString(), "The flow has been canceled")
)
}
is FinancialConnectionsSheetForTokenResult.Failed -> {
promise.resolve(
createError(ErrorType.Failed.toString(), result.error)
)
}
is FinancialConnectionsSheetForTokenResult.Completed -> {
promise.resolve(createTokenResult(result))
(context.currentActivity as? AppCompatActivity)?.supportFragmentManager?.beginTransaction()?.remove(this)?.commitAllowingStateLoss()
}
}
}

private fun onFinancialConnectionsSheetForDataResult(result: FinancialConnectionsSheetResult) {
when(result) {
is FinancialConnectionsSheetResult.Canceled -> {
promise.resolve(
createError(ErrorType.Canceled.toString(), "The flow has been canceled")
)
}
is FinancialConnectionsSheetResult.Failed -> {
promise.resolve(
createError(ErrorType.Failed.toString(), result.error)
)
}
is FinancialConnectionsSheetResult.Completed -> {
promise.resolve(
WritableNativeMap().also {
it.putMap("session", mapFromSession(result.financialConnectionsSession))
}
)
(context.currentActivity as? AppCompatActivity)?.supportFragmentManager?.beginTransaction()?.remove(this)?.commitAllowingStateLoss()
}
}
}

fun presentFinancialConnectionsSheet(clientSecret: String, mode: Mode, publishableKey: String, stripeAccountId: String?, promise: Promise, context: ReactApplicationContext) {
this.promise = promise
this.context = context
this.mode = mode
this.configuration = FinancialConnectionsSheet.Configuration(
financialConnectionsSessionClientSecret = clientSecret,
publishableKey = publishableKey,
stripeAccountId = stripeAccountId,
)

(context.currentActivity as? AppCompatActivity)?.let {
attemptToCleanupPreviousFragment(it)
commitFragmentAndStartFlow(it)
} ?: run {
promise.resolve(createMissingActivityError())
return
}
}

private fun attemptToCleanupPreviousFragment(currentActivity: AppCompatActivity) {
currentActivity.supportFragmentManager.beginTransaction()
.remove(this)
.commitAllowingStateLoss()
}

private fun commitFragmentAndStartFlow(currentActivity: AppCompatActivity) {
try {
currentActivity.supportFragmentManager.beginTransaction()
.add(this, "financial_connections_sheet_launch_fragment")
.commit()
} catch (error: IllegalStateException) {
promise.resolve(createError(ErrorType.Failed.toString(), error.message))
}
}

companion object {
private fun createTokenResult(result: FinancialConnectionsSheetForTokenResult.Completed): WritableMap {
return WritableNativeMap().also {
it.putMap("session", mapFromSession(result.financialConnectionsSession))
it.putMap("token", mapFromToken(result.token))
}
}

private fun mapFromSession(financialConnectionsSession: FinancialConnectionsSession): WritableMap {
val session = WritableNativeMap()
session.putString("id", financialConnectionsSession.id)
session.putString("clientSecret", financialConnectionsSession.clientSecret)
session.putBoolean("livemode", financialConnectionsSession.livemode)
session.putArray("accounts", mapFromAccountsList(financialConnectionsSession.accounts))
return session
}

private fun mapFromAccountsList(accounts: FinancialConnectionsAccountList): ReadableArray {
val results: WritableArray = Arguments.createArray()
for (account in accounts.data) {
val map = WritableNativeMap()
map.putString("id", account.id)
map.putBoolean("livemode", account.livemode)
map.putString("displayName", account.displayName)
map.putString("status", mapFromStatus(account.status))
map.putString("institutionName", account.institutionName)
map.putString("last4", account.last4)
map.putDouble("created", account.created * 1000.0)
map.putMap("balance", mapFromAccountBalance(account.balance))
map.putMap("balanceRefresh", mapFromAccountBalanceRefresh(account.balanceRefresh))
map.putString("category", mapFromCategory(account.category))
map.putString("subcategory", mapFromSubcategory(account.subcategory))
map.putArray("permissions", (account.permissions?.map { permission -> mapFromPermission(permission) })?.toReadableArray())
map.putArray("supportedPaymentMethodTypes", (account.supportedPaymentMethodTypes.map { type -> mapFromSupportedPaymentMethodTypes(type) }).toReadableArray())
results.pushMap(map)
}
return results
}

private fun mapFromAccountBalance(balance: Balance?): WritableMap? {
if (balance == null) {
return null
}
val map = WritableNativeMap()
map.putDouble("asOf", balance.asOf * 1000.0)
map.putString("type", mapFromBalanceType(balance.type))
map.putMap("current", balance.current as ReadableMap)
WritableNativeMap().also {
it.putMap("available", balance.cash?.available as ReadableMap)
map.putMap("cash", it)
}
WritableNativeMap().also {
it.putMap("used", balance.credit?.used as ReadableMap)
map.putMap("credit", it)
}
return map
}

private fun mapFromAccountBalanceRefresh(balanceRefresh: BalanceRefresh?): WritableMap? {
if (balanceRefresh == null) {
return null
}
val map = WritableNativeMap()
map.putString("status", mapFromBalanceRefreshStatus(balanceRefresh.status))
map.putDouble("lastAttemptedAt", balanceRefresh.lastAttemptedAt * 1000.0)
return map
}

private fun mapFromStatus(status: FinancialConnectionsAccount.Status): String {
return when (status) {
FinancialConnectionsAccount.Status.ACTIVE -> "active"
FinancialConnectionsAccount.Status.DISCONNECTED -> "disconnected"
FinancialConnectionsAccount.Status.INACTIVE -> "inactive"
FinancialConnectionsAccount.Status.UNKNOWN -> "unparsable"
}
}

private fun mapFromCategory(category: FinancialConnectionsAccount.Category): String {
return when (category) {
FinancialConnectionsAccount.Category.CASH -> "cash"
FinancialConnectionsAccount.Category.CREDIT -> "credit"
FinancialConnectionsAccount.Category.INVESTMENT -> "investment"
FinancialConnectionsAccount.Category.OTHER -> "other"
FinancialConnectionsAccount.Category.UNKNOWN -> "unparsable"
}
}

private fun mapFromSubcategory(subcategory: FinancialConnectionsAccount.Subcategory): String {
return when (subcategory) {
FinancialConnectionsAccount.Subcategory.CHECKING -> "checking"
FinancialConnectionsAccount.Subcategory.CREDIT_CARD -> "creditCard"
FinancialConnectionsAccount.Subcategory.LINE_OF_CREDIT -> "lineOfCredit"
FinancialConnectionsAccount.Subcategory.MORTGAGE -> "mortgage"
FinancialConnectionsAccount.Subcategory.OTHER -> "other"
FinancialConnectionsAccount.Subcategory.SAVINGS -> "savings"
FinancialConnectionsAccount.Subcategory.UNKNOWN -> "unparsable"
}
}

private fun mapFromPermission(permission: FinancialConnectionsAccount.Permissions): String {
return when (permission) {
FinancialConnectionsAccount.Permissions.PAYMENT_METHOD -> "paymentMethod"
FinancialConnectionsAccount.Permissions.BALANCES -> "balances"
FinancialConnectionsAccount.Permissions.OWNERSHIP -> "ownership"
FinancialConnectionsAccount.Permissions.TRANSACTIONS -> "transactions"
FinancialConnectionsAccount.Permissions.UNKNOWN -> "unparsable"
}
}

private fun mapFromSupportedPaymentMethodTypes(type: FinancialConnectionsAccount.SupportedPaymentMethodTypes): String {
return when (type) {
FinancialConnectionsAccount.SupportedPaymentMethodTypes.US_BANK_ACCOUNT -> "usBankAccount"
FinancialConnectionsAccount.SupportedPaymentMethodTypes.LINK -> "link"
FinancialConnectionsAccount.SupportedPaymentMethodTypes.UNKNOWN -> "unparsable"
}
}

private fun mapFromBalanceType(type: Balance.Type): String {
return when (type) {
Balance.Type.CASH -> "cash"
Balance.Type.CREDIT -> "credit"
Balance.Type.UNKNOWN -> "unparsable"
}
}

private fun mapFromBalanceRefreshStatus(status: BalanceRefresh.BalanceRefreshStatus?): String {
return when (status) {
BalanceRefresh.BalanceRefreshStatus.SUCCEEDED -> "succeeded"
BalanceRefresh.BalanceRefreshStatus.FAILED -> "failed"
BalanceRefresh.BalanceRefreshStatus.PENDING -> "pending"
BalanceRefresh.BalanceRefreshStatus.UNKNOWN -> "unparsable"
null -> "null"
}
}
}
}

fun List<String>.toReadableArray(): ReadableArray {
val results: WritableArray = Arguments.createArray()
for (s in this) {
results.pushString(s)
}
return results
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package versioned.host.exp.exponent.modules.api.components.reactnativestripesdk

import com.facebook.react.uimanager.SimpleViewManager
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.annotations.ReactProp

class GooglePayButtonManager : SimpleViewManager<GooglePayButtonView?>() {
override fun getName(): String {
return REACT_CLASS
}

override fun onAfterUpdateTransaction(view: GooglePayButtonView) {
super.onAfterUpdateTransaction(view)

view.initialize()
}

@ReactProp(name = "buttonType")
fun buttonType(view: GooglePayButtonView, buttonType: String) {
view.setType(buttonType)
}

override fun createViewInstance(reactContext: ThemedReactContext): GooglePayButtonView {
return GooglePayButtonView(reactContext)
}

companion object {
const val REACT_CLASS = "GooglePayButton"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package versioned.host.exp.exponent.modules.api.components.reactnativestripesdk

import android.content.res.Configuration
import android.view.LayoutInflater
import android.widget.FrameLayout
import com.facebook.react.uimanager.ThemedReactContext

class GooglePayButtonView(private val context: ThemedReactContext) : FrameLayout(context) {
private var buttonType: String? = null

fun initialize() {
val type =
when (buttonType) {
"pay" -> R.layout.pay_with_googlepay_button_no_shadow
"pay_dark" -> R.layout.pay_with_googlepay_button_dark
"pay_shadow" -> R.layout.pay_with_googlepay_button
"standard" -> R.layout.googlepay_button_no_shadow
"standard_dark" -> R.layout.googlepay_button_dark
"standard_shadow" -> R.layout.googlepay_button
else -> if (isNightMode()) R.layout.googlepay_button_dark else R.layout.googlepay_button
}

val button = LayoutInflater.from(context).inflate(
type, null
)

addView(button)
}

fun setType(type: String) {
buttonType = type
}

private fun isNightMode(): Boolean {
val nightModeFlags: Int = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
return nightModeFlags == Configuration.UI_MODE_NIGHT_YES
}
}

0 comments on commit 7c2c37d

Please sign in to comment.