framepayments-react-native 2.1.0 → 2.1.2

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.
Files changed (83) hide show
  1. package/README.md +101 -74
  2. package/android/build/.transforms/5a2061641b1fc5518a336681809507bc/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/framepayments/reactnativeframe/FrameCheckoutActivity$Companion.dex +0 -0
  3. package/android/build/.transforms/5a2061641b1fc5518a336681809507bc/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/framepayments/reactnativeframe/FrameCheckoutActivity$tryShowCheckout$1.dex +0 -0
  4. package/android/build/.transforms/5a2061641b1fc5518a336681809507bc/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/framepayments/reactnativeframe/FrameCheckoutActivity.dex +0 -0
  5. package/android/build/.transforms/5a2061641b1fc5518a336681809507bc/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/framepayments/reactnativeframe/FrameFlowActivity$CartItemDto.dex +0 -0
  6. package/android/build/.transforms/5a2061641b1fc5518a336681809507bc/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/framepayments/reactnativeframe/FrameFlowActivity$Companion.dex +0 -0
  7. package/android/build/.transforms/5a2061641b1fc5518a336681809507bc/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/framepayments/reactnativeframe/FrameFlowActivity$parseCartItems$type$1.dex +0 -0
  8. package/android/build/.transforms/5a2061641b1fc5518a336681809507bc/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/framepayments/reactnativeframe/FrameFlowActivity.dex +0 -0
  9. package/android/build/.transforms/5a2061641b1fc5518a336681809507bc/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/framepayments/reactnativeframe/FrameGooglePayActivity$Companion.dex +0 -0
  10. package/android/build/.transforms/5a2061641b1fc5518a336681809507bc/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/framepayments/reactnativeframe/FrameGooglePayActivity.dex +0 -0
  11. package/android/build/.transforms/5a2061641b1fc5518a336681809507bc/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/framepayments/reactnativeframe/FrameOnboardingActivity$Companion.dex +0 -0
  12. package/android/build/.transforms/5a2061641b1fc5518a336681809507bc/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/framepayments/reactnativeframe/FrameOnboardingActivity$parseCapabilities$type$1.dex +0 -0
  13. package/android/build/.transforms/5a2061641b1fc5518a336681809507bc/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/framepayments/reactnativeframe/FrameOnboardingActivity.dex +0 -0
  14. package/android/build/.transforms/5a2061641b1fc5518a336681809507bc/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/framepayments/reactnativeframe/FrameSDKModule.dex +0 -0
  15. package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  16. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
  17. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/framepayments/reactnativeframe/FrameCheckoutActivity$Companion.class +0 -0
  18. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/framepayments/reactnativeframe/FrameCheckoutActivity$tryShowCheckout$1.class +0 -0
  19. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/framepayments/reactnativeframe/FrameCheckoutActivity.class +0 -0
  20. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/framepayments/reactnativeframe/FrameFlowActivity$CartItemDto.class +0 -0
  21. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/framepayments/reactnativeframe/FrameFlowActivity$Companion.class +0 -0
  22. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/framepayments/reactnativeframe/FrameFlowActivity$parseCartItems$type$1.class +0 -0
  23. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/framepayments/reactnativeframe/FrameFlowActivity.class +0 -0
  24. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/framepayments/reactnativeframe/FrameGooglePayActivity$Companion.class +0 -0
  25. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/framepayments/reactnativeframe/FrameGooglePayActivity.class +0 -0
  26. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/framepayments/reactnativeframe/FrameOnboardingActivity$Companion.class +0 -0
  27. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/framepayments/reactnativeframe/FrameOnboardingActivity$parseCapabilities$type$1.class +0 -0
  28. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/framepayments/reactnativeframe/FrameOnboardingActivity.class +0 -0
  29. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/framepayments/reactnativeframe/FrameSDKModule.class +0 -0
  30. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab +0 -0
  31. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.values.at +0 -0
  32. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
  33. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
  34. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
  35. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
  36. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
  37. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
  38. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
  39. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
  40. package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
  41. package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
  42. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity$Companion.class +0 -0
  43. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity$tryShowCheckout$1.class +0 -0
  44. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity.class +0 -0
  45. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameFlowActivity$CartItemDto.class +0 -0
  46. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameFlowActivity$Companion.class +0 -0
  47. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameFlowActivity$parseCartItems$type$1.class +0 -0
  48. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameFlowActivity.class +0 -0
  49. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameGooglePayActivity$Companion.class +0 -0
  50. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameGooglePayActivity.class +0 -0
  51. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameOnboardingActivity$Companion.class +0 -0
  52. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameOnboardingActivity$parseCapabilities$type$1.class +0 -0
  53. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameOnboardingActivity.class +0 -0
  54. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameSDKModule.class +0 -0
  55. package/android/build.gradle +3 -3
  56. package/android/src/main/java/com/framepayments/reactnativeframe/FrameCheckoutActivity.kt +17 -13
  57. package/android/src/main/java/com/framepayments/reactnativeframe/FrameFlowActivity.kt +18 -11
  58. package/android/src/main/java/com/framepayments/reactnativeframe/FrameGooglePayActivity.kt +31 -8
  59. package/android/src/main/java/com/framepayments/reactnativeframe/FrameSDKModule.kt +37 -36
  60. package/ios/ApplePayPresenter.swift +53 -28
  61. package/ios/FrameRNTheme.swift +3 -24
  62. package/ios/FrameSDKBridge.m +10 -17
  63. package/ios/FrameSDKBridge.swift +89 -64
  64. package/lib/errors.d.ts +9 -1
  65. package/lib/errors.d.ts.map +1 -1
  66. package/lib/errors.js +9 -1
  67. package/lib/index.d.ts +4 -5
  68. package/lib/index.d.ts.map +1 -1
  69. package/lib/index.js +3 -4
  70. package/lib/native.d.ts +41 -13
  71. package/lib/native.d.ts.map +1 -1
  72. package/lib/native.js +64 -23
  73. package/lib/types.d.ts +18 -45
  74. package/lib/types.d.ts.map +1 -1
  75. package/package.json +1 -1
  76. package/src/__tests__/native.test.ts +179 -25
  77. package/src/errors.ts +9 -1
  78. package/src/index.ts +2 -7
  79. package/src/native.ts +83 -32
  80. package/src/types.ts +19 -58
  81. /package/android/build/.transforms/5a2061641b1fc5518a336681809507bc/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_global-synthetics/com/framepayments/reactnativeframe/{FrameSDKModule$$InternalSyntheticLambda$2$984ab30558bc904ed37602fa6e3ebf28f1ed69df6712b31b00c4f26fc26d3b70$0.globals → FrameSDKModule$$InternalSyntheticLambda$2$7347ff5b95d03cf5be9ee5177309c1bf4be5faabda2bbedb79f5f4c91917c2b1$0.globals} +0 -0
  82. /package/android/build/.transforms/5a2061641b1fc5518a336681809507bc/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_global-synthetics/com/framepayments/reactnativeframe/{FrameSDKModule$$InternalSyntheticLambda$2$f8d46f7169c404d37a1d505f19439b83090fbed62b5bdaf1e86717fdddebf622$0.globals → FrameSDKModule$$InternalSyntheticLambda$2$7347ff5b95d03cf5be9ee5177309c1bf4be5faabda2bbedb79f5f4c91917c2b1$1.globals} +0 -0
  83. /package/android/build/.transforms/5a2061641b1fc5518a336681809507bc/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_global-synthetics/com/framepayments/reactnativeframe/{FrameSDKModule$$InternalSyntheticLambda$2$f8d46f7169c404d37a1d505f19439b83090fbed62b5bdaf1e86717fdddebf622$1.globals → FrameSDKModule$$InternalSyntheticLambda$2$9816d2cb3db63bf5efb3411b62dbb57847dd7ef82f88bae5f375baced7880f11$0.globals} +0 -0
@@ -27,11 +27,19 @@ class FrameFlowActivity : AppCompatActivity() {
27
27
  override fun onCreate(savedInstanceState: Bundle?) {
28
28
  super.onCreate(savedInstanceState)
29
29
  setContentView(container)
30
- val customerId = intent.getStringExtra(EXTRA_CUSTOMER_ID)
30
+ val accountId = intent.getStringExtra(EXTRA_ACCOUNT_ID)
31
31
  val itemsJson = intent.getStringExtra(EXTRA_ITEMS_JSON)
32
32
  val shippingCents = intent.getIntExtra(EXTRA_SHIPPING_CENTS, 0)
33
33
  val items: List<FrameCartItem> = parseCartItems(itemsJson) ?: emptyList()
34
- showCart(customerId, items, shippingCents)
34
+
35
+ // Bundled cart → checkout always creates a Transfer, which requires an account.
36
+ if (accountId.isNullOrEmpty()) {
37
+ setResult(RESULT_CANCELED)
38
+ finish()
39
+ return
40
+ }
41
+
42
+ showCart(accountId, items, shippingCents)
35
43
  }
36
44
 
37
45
  private fun parseCartItems(json: String?): List<FrameCartItem>? {
@@ -52,22 +60,21 @@ class FrameFlowActivity : AppCompatActivity() {
52
60
  val imageUrl: String
53
61
  )
54
62
 
55
- private fun showCart(customerId: String?, items: List<FrameCartItem>, shippingCents: Int) {
63
+ private fun showCart(accountId: String, items: List<FrameCartItem>, shippingCents: Int) {
56
64
  container.removeAllViews()
57
65
  cartView = FrameCartView(this).apply {
58
- configure(customerId, items, shippingCents, { totalCents ->
59
- showCheckout(customerId, totalCents)
66
+ configure(accountId, items, shippingCents, { totalCents ->
67
+ showCheckout(accountId, totalCents)
60
68
  }, null)
61
69
  }
62
70
  container.addView(cartView)
63
71
  }
64
72
 
65
- private fun showCheckout(customerId: String?, amount: Int) {
73
+ private fun showCheckout(accountId: String, amount: Int) {
66
74
  container.removeAllViews()
67
75
  checkoutView = FrameCheckoutView(this).apply {
68
- configure(customerId, amount) { chargeIntent ->
69
- val json = Gson().toJson(chargeIntent)
70
- setResult(RESULT_OK, Intent().putExtra(EXTRA_CHARGE_INTENT_JSON, json))
76
+ configure(accountId, amount) { transferId ->
77
+ setResult(RESULT_OK, Intent().putExtra(EXTRA_TRANSFER_ID, transferId))
71
78
  finish()
72
79
  }
73
80
  }
@@ -75,10 +82,10 @@ class FrameFlowActivity : AppCompatActivity() {
75
82
  }
76
83
 
77
84
  companion object {
78
- const val EXTRA_CUSTOMER_ID = "customer_id"
85
+ const val EXTRA_ACCOUNT_ID = "account_id"
79
86
  const val EXTRA_ITEMS_JSON = "items_json"
80
87
  const val EXTRA_SHIPPING_CENTS = "shipping_cents"
81
- const val EXTRA_CHARGE_INTENT_JSON = "charge_intent_json"
88
+ const val EXTRA_TRANSFER_ID = "transfer_id"
82
89
  const val REQUEST_CODE = 9002
83
90
  }
84
91
  }
@@ -4,11 +4,9 @@ import android.content.Intent
4
4
  import android.os.Bundle
5
5
  import android.os.Handler
6
6
  import android.os.Looper
7
- import android.view.View
8
7
  import android.widget.FrameLayout
9
8
  import androidx.appcompat.app.AppCompatActivity
10
9
  import com.framepayments.framesdk_ui.buttons.FrameGooglePayButton
11
- import com.google.gson.Gson
12
10
 
13
11
  /**
14
12
  * Hidden host activity for Frame.presentGooglePay(). The Frame Android SDK only
@@ -39,7 +37,8 @@ class FrameGooglePayActivity : AppCompatActivity() {
39
37
  setContentView(container)
40
38
 
41
39
  val amountCents = intent.getIntExtra(EXTRA_AMOUNT_CENTS, 0)
42
- val customerId = intent.getStringExtra(EXTRA_CUSTOMER_ID)
40
+ val ownerType = intent.getStringExtra(EXTRA_OWNER_TYPE)
41
+ val ownerId = intent.getStringExtra(EXTRA_OWNER_ID)
43
42
  val currencyCode = intent.getStringExtra(EXTRA_CURRENCY) ?: "USD"
44
43
  val googlePayMerchantId = intent.getStringExtra(EXTRA_MERCHANT_ID)
45
44
 
@@ -47,6 +46,18 @@ class FrameGooglePayActivity : AppCompatActivity() {
47
46
  deliverFailure("Invalid amountCents")
48
47
  return
49
48
  }
49
+ if (ownerId.isNullOrEmpty()) {
50
+ deliverFailure("owner.id is required")
51
+ return
52
+ }
53
+ val owner: FrameGooglePayButton.Owner = when (ownerType) {
54
+ "customer" -> FrameGooglePayButton.Owner.Customer(ownerId)
55
+ "account" -> FrameGooglePayButton.Owner.Account(ownerId)
56
+ else -> {
57
+ deliverFailure("owner.type must be 'customer' or 'account'")
58
+ return
59
+ }
60
+ }
50
61
 
51
62
  val button = FrameGooglePayButton(this)
52
63
  button.layoutParams = FrameLayout.LayoutParams(1, 1) // tiny but measurable so click can fire
@@ -55,7 +66,7 @@ class FrameGooglePayActivity : AppCompatActivity() {
55
66
 
56
67
  button.configure(
57
68
  amountCents = amountCents,
58
- customerId = customerId,
69
+ owner = owner,
59
70
  currencyCode = currencyCode,
60
71
  googlePayMerchantId = googlePayMerchantId,
61
72
  onResult = { result -> handleResult(result) },
@@ -94,8 +105,14 @@ class FrameGooglePayActivity : AppCompatActivity() {
94
105
  didDeliverResult = true
95
106
  when (result) {
96
107
  is FrameGooglePayButton.Result.Success -> {
97
- val json = Gson().toJson(result.chargeIntent)
98
- deliverViaCallback(android.app.Activity.RESULT_OK, Intent().putExtra(EXTRA_CHARGE_INTENT_JSON, json))
108
+ // `result.id` is a Transfer id (for Owner.Account) or a ChargeIntent id
109
+ // (for Owner.Customer). JS knows which it is because it passed the owner.
110
+ deliverViaCallback(android.app.Activity.RESULT_OK, Intent().putExtra(EXTRA_CHARGE_ID, result.id))
111
+ }
112
+ is FrameGooglePayButton.Result.PaymentMethodCreated -> {
113
+ // RN bridge does not currently expose AddToOwner mode, so this branch
114
+ // shouldn't fire in practice. Surface it as failure instead of silently dropping.
115
+ deliverViaCallback(RESULT_FAILURE, Intent().putExtra(EXTRA_FAILURE_MESSAGE, "Unsupported Google Pay result"))
99
116
  }
100
117
  is FrameGooglePayButton.Result.Failure -> {
101
118
  deliverViaCallback(RESULT_FAILURE, Intent().putExtra(EXTRA_FAILURE_MESSAGE, result.message))
@@ -133,10 +150,16 @@ class FrameGooglePayActivity : AppCompatActivity() {
133
150
 
134
151
  companion object {
135
152
  const val EXTRA_AMOUNT_CENTS = "amount_cents"
136
- const val EXTRA_CUSTOMER_ID = "customer_id"
153
+ const val EXTRA_OWNER_TYPE = "owner_type"
154
+ const val EXTRA_OWNER_ID = "owner_id"
137
155
  const val EXTRA_CURRENCY = "currency"
138
156
  const val EXTRA_MERCHANT_ID = "merchant_id"
139
- const val EXTRA_CHARGE_INTENT_JSON = "charge_intent_json"
157
+ /**
158
+ * The id of the resource created by the wallet flow. Holds a Transfer id when
159
+ * the owner was an account, or a ChargeIntent id when the owner was a customer.
160
+ * JS knows which by inspecting the owner it passed in.
161
+ */
162
+ const val EXTRA_CHARGE_ID = "charge_id"
140
163
  const val EXTRA_FAILURE_MESSAGE = "failure_message"
141
164
 
142
165
  const val REQUEST_CODE = 9003
@@ -31,7 +31,15 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
31
31
  }
32
32
 
33
33
  @ReactMethod
34
- fun initialize(secretKey: String, publishableKey: String, debugMode: Boolean, promise: Promise) {
34
+ fun initialize(
35
+ secretKey: String,
36
+ publishableKey: String,
37
+ debugMode: Boolean,
38
+ @Suppress("UNUSED_PARAMETER") theme: com.facebook.react.bridge.ReadableMap?,
39
+ promise: Promise
40
+ ) {
41
+ // theme is accepted for cross-platform parity with iOS but is currently a
42
+ // no-op on Android — frame-android does not yet have a matching theme API.
35
43
  try {
36
44
  val ctx = reactApplicationContext.applicationContext
37
45
  FrameNetworking.initializeWithAPIKey(ctx, secretKey, publishableKey, debugMode)
@@ -42,7 +50,7 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
42
50
  }
43
51
 
44
52
  @ReactMethod
45
- fun presentCheckout(customerId: String?, amount: Double, promise: Promise) {
53
+ fun presentCheckout(accountId: String?, amount: Double, promise: Promise) {
46
54
  val activity = reactApplicationContext.currentActivity ?: run {
47
55
  promise.reject("NO_ACTIVITY", "No current activity", null)
48
56
  return
@@ -50,7 +58,7 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
50
58
  checkoutPromise = promise
51
59
  activity.runOnUiThread {
52
60
  val intent = Intent(activity, FrameCheckoutActivity::class.java).apply {
53
- putExtra(FrameCheckoutActivity.EXTRA_CUSTOMER_ID, customerId)
61
+ putExtra(FrameCheckoutActivity.EXTRA_ACCOUNT_ID, accountId)
54
62
  putExtra(FrameCheckoutActivity.EXTRA_AMOUNT, amount.toInt())
55
63
  }
56
64
  activity.startActivityForResult(intent, FrameCheckoutActivity.REQUEST_CODE)
@@ -59,7 +67,7 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
59
67
 
60
68
  @ReactMethod
61
69
  fun presentCart(
62
- customerId: String?,
70
+ accountId: String?,
63
71
  items: com.facebook.react.bridge.ReadableArray,
64
72
  shippingAmountInCents: Double,
65
73
  promise: Promise
@@ -75,7 +83,7 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
75
83
  cartPromise = promise
76
84
  activity.runOnUiThread {
77
85
  val intent = Intent(activity, FrameFlowActivity::class.java).apply {
78
- putExtra(FrameFlowActivity.EXTRA_CUSTOMER_ID, customerId)
86
+ putExtra(FrameFlowActivity.EXTRA_ACCOUNT_ID, accountId)
79
87
  putExtra(FrameFlowActivity.EXTRA_ITEMS_JSON, itemsJson)
80
88
  putExtra(FrameFlowActivity.EXTRA_SHIPPING_CENTS, shippingAmountInCents.toInt())
81
89
  }
@@ -86,7 +94,8 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
86
94
  @ReactMethod
87
95
  fun presentGooglePay(
88
96
  amountCents: Double,
89
- customerId: String?,
97
+ ownerType: String?,
98
+ ownerId: String?,
90
99
  currencyCode: String?,
91
100
  googlePayMerchantId: String?,
92
101
  promise: Promise
@@ -100,6 +109,14 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
100
109
  promise.reject("INVALID_AMOUNT", "amountCents must be positive", null)
101
110
  return
102
111
  }
112
+ if (ownerType != "customer" && ownerType != "account") {
113
+ promise.reject("INVALID_OWNER", "owner.type must be 'customer' or 'account'", null)
114
+ return
115
+ }
116
+ if (ownerId.isNullOrEmpty()) {
117
+ promise.reject("INVALID_OWNER", "owner.id is required", null)
118
+ return
119
+ }
103
120
  googlePayPromise = promise
104
121
  pendingGooglePayCallback = { resultCode, data ->
105
122
  handleGooglePayResult(resultCode, data)
@@ -107,7 +124,8 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
107
124
  activity.runOnUiThread {
108
125
  val intent = Intent(activity, FrameGooglePayActivity::class.java).apply {
109
126
  putExtra(FrameGooglePayActivity.EXTRA_AMOUNT_CENTS, amountInt)
110
- putExtra(FrameGooglePayActivity.EXTRA_CUSTOMER_ID, customerId)
127
+ putExtra(FrameGooglePayActivity.EXTRA_OWNER_TYPE, ownerType)
128
+ putExtra(FrameGooglePayActivity.EXTRA_OWNER_ID, ownerId)
111
129
  putExtra(FrameGooglePayActivity.EXTRA_CURRENCY, currencyCode ?: "USD")
112
130
  putExtra(FrameGooglePayActivity.EXTRA_MERCHANT_ID, googlePayMerchantId)
113
131
  }
@@ -174,17 +192,11 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
174
192
  val promise = checkoutPromise ?: return
175
193
  checkoutPromise = null
176
194
  if (resultCode == Activity.RESULT_OK && data != null) {
177
- val json = data.getStringExtra(FrameCheckoutActivity.EXTRA_CHARGE_INTENT_JSON)
178
- if (json != null) {
179
- try {
180
- val obj = JSONObject(json)
181
- val map = jsonObjectToWritableMap(obj)
182
- promise.resolve(map)
183
- } catch (e: Exception) {
184
- promise.reject("PARSE_ERROR", e.message, e)
185
- }
195
+ val transferId = data.getStringExtra(FrameCheckoutActivity.EXTRA_TRANSFER_ID)
196
+ if (!transferId.isNullOrEmpty()) {
197
+ promise.resolve(transferId)
186
198
  } else {
187
- promise.reject("NO_RESULT", "No charge intent in result", null)
199
+ promise.reject("NO_RESULT", "No transfer id in result", null)
188
200
  }
189
201
  } else {
190
202
  promise.reject("USER_CANCELED", "User cancelled checkout", null)
@@ -195,17 +207,11 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
195
207
  val promise = cartPromise ?: return
196
208
  cartPromise = null
197
209
  if (resultCode == Activity.RESULT_OK && data != null) {
198
- val json = data.getStringExtra(FrameFlowActivity.EXTRA_CHARGE_INTENT_JSON)
199
- if (json != null) {
200
- try {
201
- val obj = JSONObject(json)
202
- val map = jsonObjectToWritableMap(obj)
203
- promise.resolve(map)
204
- } catch (e: Exception) {
205
- promise.reject("PARSE_ERROR", e.message, e)
206
- }
210
+ val transferId = data.getStringExtra(FrameFlowActivity.EXTRA_TRANSFER_ID)
211
+ if (!transferId.isNullOrEmpty()) {
212
+ promise.resolve(transferId)
207
213
  } else {
208
- promise.reject("NO_RESULT", "No charge intent in result", null)
214
+ promise.reject("NO_RESULT", "No transfer id in result", null)
209
215
  }
210
216
  } else {
211
217
  promise.reject("USER_CANCELED", "User cancelled", null)
@@ -217,16 +223,11 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
217
223
  googlePayPromise = null
218
224
  when (resultCode) {
219
225
  Activity.RESULT_OK -> {
220
- val json = data?.getStringExtra(FrameGooglePayActivity.EXTRA_CHARGE_INTENT_JSON)
221
- if (json != null) {
222
- try {
223
- val map = jsonObjectToWritableMap(JSONObject(json))
224
- promise.resolve(map)
225
- } catch (e: Exception) {
226
- promise.reject("PARSE_ERROR", e.message, e)
227
- }
226
+ val id = data?.getStringExtra(FrameGooglePayActivity.EXTRA_CHARGE_ID)
227
+ if (id.isNullOrEmpty()) {
228
+ promise.reject("NO_RESULT", "Google Pay returned no charge id", null)
228
229
  } else {
229
- promise.reject("NO_RESULT", "No charge intent in result", null)
230
+ promise.resolve(id)
230
231
  }
231
232
  }
232
233
  FrameGooglePayActivity.RESULT_FAILURE -> {
@@ -3,10 +3,14 @@
3
3
  // FrameReactNative
4
4
  //
5
5
  // Programmatic Apple Pay presentation for Frame.presentApplePay(). Wraps
6
- // PKPaymentAuthorizationController + ApplePayAPI + ChargeIntentsAPI directly
7
- // so we can detect the user-cancel path (PKPaymentAuthorizationController's
8
- // didFinish fires for both success and cancel; the underlying SDK's view
9
- // model only delivers success, so we re-implement that flow here).
6
+ // PKPaymentAuthorizationController + ApplePayAPI + (ChargeIntentsAPI | TransfersAPI)
7
+ // directly so we can detect the user-cancel path PKPaymentAuthorizationController's
8
+ // didFinish fires for both success and cancel, and the underlying SDK's view
9
+ // model only delivers success, so we re-implement that flow here.
10
+ //
11
+ // Supports both:
12
+ // - `.customer(id)` owner → creates a `ChargeIntent`; resolves with the ChargeIntent id.
13
+ // - `.account(id)` owner → creates a `Transfer`; resolves with the Transfer id.
10
14
  //
11
15
 
12
16
  import Foundation
@@ -16,9 +20,14 @@ import Frame
16
20
  @MainActor
17
21
  final class ApplePayPresenter: NSObject, PKPaymentAuthorizationControllerDelegate {
18
22
 
23
+ enum Owner {
24
+ case customer(String)
25
+ case account(String)
26
+ }
27
+
19
28
  private let amount: Int
20
29
  private let currency: String
21
- private let owner: FrameApplePayViewModel.PaymentMethodOwner
30
+ private let owner: Owner
22
31
  private let merchantId: String
23
32
  private let resolve: (Any?) -> Void
24
33
  private let reject: (String, String, Error?) -> Void
@@ -36,7 +45,7 @@ final class ApplePayPresenter: NSObject, PKPaymentAuthorizationControllerDelegat
36
45
 
37
46
  init(amount: Int,
38
47
  currency: String,
39
- owner: FrameApplePayViewModel.PaymentMethodOwner,
48
+ owner: Owner,
40
49
  merchantId: String,
41
50
  resolve: @escaping (Any?) -> Void,
42
51
  reject: @escaping (String, String, Error?) -> Void) {
@@ -80,6 +89,8 @@ final class ApplePayPresenter: NSObject, PKPaymentAuthorizationControllerDelegat
80
89
  didAuthorizePayment payment: PKPayment
81
90
  ) async -> PKPaymentAuthorizationResult {
82
91
  do {
92
+ // 1. Create the Frame PaymentMethod from the Apple Pay token, scoped to
93
+ // whichever owner the caller asked for.
83
94
  let (paymentMethod, methodError): (FrameObjects.PaymentMethod?, NetworkingError?)
84
95
  switch owner {
85
96
  case .customer(let customerId):
@@ -97,27 +108,45 @@ final class ApplePayPresenter: NSObject, PKPaymentAuthorizationControllerDelegat
97
108
  return PKPaymentAuthorizationResult(status: .failure, errors: nil)
98
109
  }
99
110
 
100
- let request: ChargeIntentsRequests.CreateChargeIntentRequest
111
+ // 2. Create the charge. Customer owners produce a ChargeIntent; account
112
+ // owners produce a Transfer. Both surface the resulting id to JS — the
113
+ // caller knows which resource the id refers to based on the owner.
101
114
  switch owner {
102
115
  case .customer(let customerId):
103
- request = ChargeIntentsRequests.CreateChargeIntentRequest(
104
- amount: amount, currency: currency, customer: customerId,
105
- paymentMethod: paymentMethodId, confirm: true, authorizationMode: .automatic
116
+ let request = ChargeIntentsRequests.CreateChargeIntentRequest(
117
+ amount: amount,
118
+ currency: currency,
119
+ customer: customerId,
120
+ paymentMethod: paymentMethodId,
121
+ confirm: true,
122
+ authorizationMode: .automatic
106
123
  )
124
+ let (chargeIntent, chargeError) = try await ChargeIntentsAPI.createChargeIntent(request: request)
125
+
126
+ if let chargeIntent {
127
+ deliverSuccess(id: chargeIntent.id)
128
+ return PKPaymentAuthorizationResult(status: .success, errors: nil)
129
+ } else {
130
+ deliverFailure(code: "PAYMENT_FAILED", error: chargeError)
131
+ return PKPaymentAuthorizationResult(status: .failure, errors: nil)
132
+ }
133
+
107
134
  case .account(let accountId):
108
- request = ChargeIntentsRequests.CreateChargeIntentRequest(
109
- amount: amount, currency: currency, account: accountId,
110
- paymentMethod: paymentMethodId, confirm: true, authorizationMode: .automatic
135
+ let request = TransferRequests.CreateTransferRequest(
136
+ amount: amount,
137
+ accountId: accountId,
138
+ currency: currency,
139
+ sourcePaymentMethodId: paymentMethodId
111
140
  )
112
- }
113
- let (chargeIntent, chargeError) = try await ChargeIntentsAPI.createChargeIntent(request: request)
114
-
115
- if let chargeIntent {
116
- deliverSuccess(chargeIntent)
117
- return PKPaymentAuthorizationResult(status: .success, errors: nil)
118
- } else {
119
- deliverFailure(code: "CHARGE_INTENT_FAILED", error: chargeError)
120
- return PKPaymentAuthorizationResult(status: .failure, errors: nil)
141
+ let (transfer, transferError) = try await TransfersAPI.createTransfer(request: request)
142
+
143
+ if let transfer {
144
+ deliverSuccess(id: transfer.id)
145
+ return PKPaymentAuthorizationResult(status: .success, errors: nil)
146
+ } else {
147
+ deliverFailure(code: "PAYMENT_FAILED", error: transferError)
148
+ return PKPaymentAuthorizationResult(status: .failure, errors: nil)
149
+ }
121
150
  }
122
151
  } catch {
123
152
  deliverFailure(code: "PAYMENT_FAILED", error: error)
@@ -136,14 +165,10 @@ final class ApplePayPresenter: NSObject, PKPaymentAuthorizationControllerDelegat
136
165
 
137
166
  // MARK: - Result delivery
138
167
 
139
- private func deliverSuccess(_ intent: FrameObjects.ChargeIntent) {
168
+ private func deliverSuccess(id: String) {
140
169
  guard !didDeliverResult else { return }
141
170
  didDeliverResult = true
142
- if let dict = FrameSDKBridge.encodeChargeIntent(intent) {
143
- resolve(dict)
144
- } else {
145
- reject("ENCODE_ERROR", "Failed to encode charge intent", nil)
146
- }
171
+ resolve(id)
147
172
  }
148
173
 
149
174
  private func deliverFailure(code: String, error: Error?) {
@@ -2,8 +2,9 @@
2
2
  // FrameRNTheme.swift
3
3
  // FrameReactNative
4
4
  //
5
- // Bridges JS theme dictionaries to Frame-iOS's FrameTheme and applies it to
6
- // every SwiftUI root view we present. Read/written only on the main thread.
5
+ // Parses JS theme dictionaries into Frame-iOS's FrameTheme. The parsed
6
+ // theme is handed to FrameNetworking.shared.configureTheme(_:); the SDK
7
+ // owns storage and applies it via its FrameThemeKey environment default.
7
8
  //
8
9
 
9
10
  import Foundation
@@ -11,12 +12,6 @@ import SwiftUI
11
12
  import Frame
12
13
 
13
14
  enum FrameRNTheme {
14
- // Main-thread only: written by FrameSDKBridge.setTheme (dispatched to main),
15
- // read by present* methods (already on main).
16
- static var current: FrameTheme? = nil
17
-
18
- static func resolved() -> FrameTheme { current ?? .default }
19
-
20
15
  static func parse(_ dict: [String: Any]) -> FrameTheme {
21
16
  var theme = FrameTheme.default
22
17
 
@@ -75,22 +70,6 @@ enum FrameRNTheme {
75
70
  }
76
71
  }
77
72
 
78
- // Applies the supplied FrameTheme to a single root view. Captured at present
79
- // time so each UIHostingController has a stable, concrete rootView type.
80
- struct ThemedRoot<Content: View>: View {
81
- let theme: FrameTheme
82
- let content: Content
83
-
84
- init(_ content: Content, theme: FrameTheme) {
85
- self.content = content
86
- self.theme = theme
87
- }
88
-
89
- var body: some View {
90
- content.frameTheme(theme)
91
- }
92
- }
93
-
94
73
  extension Color {
95
74
  // Accepts "#RGB", "#RRGGBB", "#RRGGBBAA" with or without the leading '#'.
96
75
  init?(rnHex hex: String) {
@@ -28,19 +28,16 @@
28
28
  RCT_EXTERN_METHOD(initialize:(NSString *)secretKey
29
29
  publishableKey:(NSString *)publishableKey
30
30
  debugMode:(BOOL)debugMode
31
+ theme:(NSDictionary *)theme
31
32
  resolver:(RCTPromiseResolveBlock)resolve
32
33
  rejecter:(RCTPromiseRejectBlock)reject)
33
34
 
34
- RCT_EXTERN_METHOD(setTheme:(NSDictionary *)theme
35
- resolver:(RCTPromiseResolveBlock)resolve
36
- rejecter:(RCTPromiseRejectBlock)reject)
37
-
38
- RCT_EXTERN_METHOD(presentCheckout:(id)customerId
35
+ RCT_EXTERN_METHOD(presentCheckout:(id)accountId
39
36
  amount:(nonnull NSNumber *)amount
40
37
  resolver:(RCTPromiseResolveBlock)resolve
41
38
  rejecter:(RCTPromiseRejectBlock)reject)
42
39
 
43
- RCT_EXTERN_METHOD(presentCart:(id)customerId
40
+ RCT_EXTERN_METHOD(presentCart:(id)accountId
44
41
  items:(NSArray *)items
45
42
  shippingAmountInCents:(nonnull NSNumber *)shippingAmountInCents
46
43
  resolver:(RCTPromiseResolveBlock)resolve
@@ -71,34 +68,30 @@ RCT_EXTERN_METHOD(presentApplePay:(NSString *)ownerType
71
68
  return YES;
72
69
  }
73
70
 
74
- - (void)initialize:(NSString *)secretKey publishableKey:(NSString *)publishableKey debugMode:(BOOL)debugMode resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
75
- [[[ObjCFrameSDKBridge alloc] init] initialize:secretKey publishableKey:publishableKey debugMode:debugMode resolver:resolve rejecter:reject];
76
- }
77
-
78
- - (void)setTheme:(NSDictionary *)theme resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
79
- [[[ObjCFrameSDKBridge alloc] init] setTheme:theme resolver:resolve rejecter:reject];
71
+ - (void)initialize:(NSString *)secretKey publishableKey:(NSString *)publishableKey debugMode:(BOOL)debugMode theme:(NSDictionary *)theme resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
72
+ [[[ObjCFrameSDKBridge alloc] init] initialize:secretKey publishableKey:publishableKey debugMode:debugMode theme:theme resolver:resolve rejecter:reject];
80
73
  }
81
74
 
82
- - (void)presentCheckout:(id)customerId amount:(NSNumber *)amount resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
75
+ - (void)presentCheckout:(id)accountId amount:(NSNumber *)amount resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
83
76
  dispatch_async(dispatch_get_main_queue(), ^{
84
77
  UIViewController *topVC = FrameGetTopViewController();
85
78
  if (!topVC) {
86
79
  reject(@"NO_ROOT_VC", @"Could not find root view controller to present checkout", nil);
87
80
  return;
88
81
  }
89
- NSString *cId = [customerId isKindOfClass:[NSString class]] ? (NSString *)customerId : nil;
90
- [[[ObjCFrameSDKBridge alloc] init] presentCheckoutFrom:topVC customerId:cId amount:amount.intValue resolver:resolve rejecter:reject];
82
+ NSString *aId = [accountId isKindOfClass:[NSString class]] ? (NSString *)accountId : nil;
83
+ [[[ObjCFrameSDKBridge alloc] init] presentCheckoutFrom:topVC accountId:aId amount:amount.intValue resolver:resolve rejecter:reject];
91
84
  });
92
85
  }
93
86
 
94
- - (void)presentCart:(id)customerId items:(NSArray *)items shippingAmountInCents:(NSNumber *)shippingAmountInCents resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
87
+ - (void)presentCart:(id)accountId items:(NSArray *)items shippingAmountInCents:(NSNumber *)shippingAmountInCents resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
95
88
  dispatch_async(dispatch_get_main_queue(), ^{
96
89
  UIViewController *topVC = FrameGetTopViewController();
97
90
  if (!topVC) {
98
91
  reject(@"NO_ROOT_VC", @"Could not find root view controller to present cart", nil);
99
92
  return;
100
93
  }
101
- [[[ObjCFrameSDKBridge alloc] init] presentCartFrom:topVC customerId:customerId items:items shippingAmountInCents:shippingAmountInCents.integerValue resolver:resolve rejecter:reject];
94
+ [[[ObjCFrameSDKBridge alloc] init] presentCartFrom:topVC accountId:accountId items:items shippingAmountInCents:shippingAmountInCents.integerValue resolver:resolve rejecter:reject];
102
95
  });
103
96
  }
104
97