Skip to content

Commit

Permalink
Convert Delegation Pattern to Completion Handler (#293)
Browse files Browse the repository at this point in the history
* PayPal remove delgation pattern for completion handler function for checkout

* lint error for paypal start

* completion and analytics into notify functions

* paypal vault completion, unit tests

* remove PayPal delegates, references

* Card vault to completion, unit tests

* Card approve to completion, unit tests

* docstrings for approve completion param

* wrap paypal functions in async await

* async await wrapper for CardClient functions

* remove CardDelegate and references

* fix error in notifyCheckoutFailure

* Make error names and messages payPal caps consistent

* changelog entires

* Steven PR feedback: typo in Chagelog
  • Loading branch information
KunJeongPark authored Oct 29, 2024
1 parent b747307 commit 6030da7
Show file tree
Hide file tree
Showing 21 changed files with 522 additions and 738 deletions.
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,32 @@
* Breaking Changes
* PayPalNativePayments
* Remove entire PayPalNativePayments module
* PayPalWebPayments
* Replace delegate pattern with completion handlers and Swift concurrency
* Remove `PayPalWebCheckoutDelegate` and `PayPalVaultDelegate`
* Remove `start(request:)` method that uses delegate callbacks
* Remove `vault(vaultRequest:)` method that uses delegate callbacks
* Add `start(request:completion(PayPalWebCheckoutResult?, Error?) -> Void)` to `PayPalWebCheckoutClient`
* Add `vault(vaultRequest:completion(PayPalVaultResult?, Error?) -> Void)` to `PayPalWebCheckoutClient`
* Add `start(request:) async throws -> PayPalCheckoutResult`
* Add `vault(vaultRequest:) async throws -> PayPalVaultResult`
* CardPayments
* Replace delegate pattern with completion handlers and Swift concurrency
* Remove `CardDelegate` and `CardVaultDelegate`
* Remove `approveOrder(request:)` method that uses delegate callbacks
* Remove `vault(vaultRequest:)` method that uses delegate callbacks
* Add `approveOrder(request:completion:(CardResult?, Error?) -> Void)` to `CardClient`
* Add `vault(request:completion:(CardVaultResult?, Error?) -> Void)` to `CardClient`
* Add `approveOrder(request:) async throws -> CardResult`
* Add `vault(vaultRequest:) async throws -> CardVaultResult`
* PayPalWebPayments
* Deprecate `PayPalVaultRequest(url:setupTokenID:)`
* Add `PayPalVaultRequest(setupTokenID:)`
* Add new error types for cancellation handling:
* `PayPalWebCheckoutClientError.payPalCancellationError`
* `PayPalWebCheckoutClientError.payPalVaultCancellationError`
* CardPayments
* Add new error type `CardClientError.threeDSecureCancellation` for handling 3DS cancellation

## 1.4.0 (2024-07-09)
* PayPalNativePayments (DEPRECATED)
Expand Down
15 changes: 10 additions & 5 deletions Demo/Demo/SwiftUIComponents/PayPalVaultViews/PayPalVaultView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,18 @@ struct PayPalVaultView: View {
)
SetupTokenResultView(vaultViewModel: paypalVaultViewModel)
if let setupTokenID = paypalVaultViewModel.state.setupToken?.id {
Button("Vault PayPal") {
Task {
await paypalVaultViewModel.vault(setupTokenID: setupTokenID)
ZStack {
Button("Vault PayPal") {
Task {
await paypalVaultViewModel.vault(setupTokenID: setupTokenID)
}
}
.buttonStyle(RoundedBlueButtonStyle())
.padding()
if case .loading = paypalVaultViewModel.state.paypalVaultTokenResponse {
CircularProgressView()
}
}
.buttonStyle(RoundedBlueButtonStyle())
.padding()
}
PayPalVaultResultView(viewModel: paypalVaultViewModel)
if let paypalVaultResult = paypalVaultViewModel.state.paypalVaultToken {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import CorePayments
import PayPalWebPayments
import FraudProtection

class PayPalWebViewModel: ObservableObject, PayPalWebCheckoutDelegate {
class PayPalWebViewModel: ObservableObject {

@Published var state: CurrentState = .idle
@Published var intent: Intent = .authorize
Expand Down Expand Up @@ -63,15 +63,21 @@ class PayPalWebViewModel: ObservableObject, PayPalWebCheckoutDelegate {
Task {
do {
payPalWebCheckoutClient = try await getPayPalClient()
payPalWebCheckoutClient?.delegate = self
guard let payPalWebCheckoutClient else {
print("Error initializing PayPalWebCheckoutClient")
return
}

if let orderID {
let payPalRequest = PayPalWebCheckoutRequest(orderID: orderID, fundingSource: funding)
payPalWebCheckoutClient.start(request: payPalRequest)
payPalWebCheckoutClient.start(request: payPalRequest) { result, error in
if let error {
self.updateState(.error(message: error.localizedDescription))
} else {
self.updateState(.success)
self.checkoutResult = result
}
}
}
updateState(.success)
} catch {
Expand Down
21 changes: 16 additions & 5 deletions Demo/Demo/ViewModels/CardPaymentViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import CardPayments
import CorePayments
import FraudProtection

class CardPaymentViewModel: ObservableObject, CardDelegate {
class CardPaymentViewModel: ObservableObject {

@Published var state = CardPaymentState()
private var payPalDataCollector: PayPalDataCollector?
Expand Down Expand Up @@ -117,11 +117,22 @@ class CardPaymentViewModel: ObservableObject, CardDelegate {
let config = try await configManager.getCoreConfig()
cardClient = CardClient(config: config)
payPalDataCollector = PayPalDataCollector(config: config)
cardClient?.delegate = self
let cardRequest = CardRequest(orderID: orderID, card: card, sca: sca)
cardClient?.approveOrder(request: cardRequest)
cardClient?.approveOrder(request: cardRequest) { result, error in
if let error {
self.setUpdateSetupTokenFailureResult(vaultError: error)
} else if let result {
self.approveResultSuccessResult(
approveResult: CardPaymentState.CardResult(
id: result.orderID,
status: result.status,
didAttemptThreeDSecureAuthentication: result.didAttemptThreeDSecureAuthentication
)
)
}
}
} catch {
self.state.approveResultResponse = .error(message: error.localizedDescription)
setUpdateSetupTokenFailureResult(vaultError: error)
print("failed in checkout with card. \(error.localizedDescription)")
}
}
Expand All @@ -134,7 +145,7 @@ class CardPaymentViewModel: ObservableObject, CardDelegate {
}
}

func setUpdateSetupTokenFailureResult(vaultError: CorePayments.CoreSDKError) {
func setUpdateSetupTokenFailureResult(vaultError: Error) {
DispatchQueue.main.async {
self.state.approveResultResponse = .error(message: vaultError.localizedDescription)
}
Expand Down
42 changes: 10 additions & 32 deletions Demo/Demo/ViewModels/CardVaultViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Foundation
import CardPayments
import CorePayments

class CardVaultViewModel: VaultViewModel, CardVaultDelegate {
class CardVaultViewModel: VaultViewModel {

let configManager = CoreConfigManager(domain: "Card Vault")

Expand All @@ -13,11 +13,16 @@ class CardVaultViewModel: VaultViewModel, CardVaultDelegate {
do {
let config = try await configManager.getCoreConfig()
let cardClient = CardClient(config: config)
cardClient.vaultDelegate = self
let cardVaultRequest = CardVaultRequest(card: card, setupTokenID: setupToken)
cardClient.vault(cardVaultRequest)
cardClient.vault(cardVaultRequest) { result, error in
if let result {
self.setUpdateSetupTokenResult(vaultResult: result, vaultError: nil)
} else if let error {
self.setUpdateSetupTokenResult(vaultResult: nil, vaultError: error)
}
}
} catch {
self.state.updateSetupTokenResponse = .error(message: error.localizedDescription)
self.setUpdateSetupTokenResult(vaultResult: nil, vaultError: error)
print("failed in updating setup token. \(error.localizedDescription)")
}
}
Expand All @@ -31,7 +36,7 @@ class CardVaultViewModel: VaultViewModel, CardVaultDelegate {
return enabled
}

func setUpdateSetupTokenResult(vaultResult: CardVaultResult? = nil, vaultError: CoreSDKError? = nil) {
func setUpdateSetupTokenResult(vaultResult: CardVaultResult? = nil, vaultError: Error? = nil) {
DispatchQueue.main.async {
if let vaultResult {
self.state.updateSetupTokenResponse = .loaded(
Expand All @@ -46,31 +51,4 @@ class CardVaultViewModel: VaultViewModel, CardVaultDelegate {
}
}
}

// MARK: - CardVault Delegate

func card(_ cardClient: CardPayments.CardClient, didFinishWithVaultResult vaultResult: CardPayments.CardVaultResult) {
print("vaultResult: \(vaultResult)")
setUpdateSetupTokenResult(vaultResult: vaultResult)
}

func card(_ cardClient: CardPayments.CardClient, didFinishWithVaultError vaultError: CorePayments.CoreSDKError) {
print("error: \(vaultError.errorDescription ?? "")")
setUpdateSetupTokenResult(vaultError: vaultError)
}

func cardThreeDSecureDidCancel(_ cardClient: CardClient) {
DispatchQueue.main.async {
self.state.updateSetupTokenResponse = .idle
self.state.updateSetupToken = nil
}
}

func cardThreeDSecureWillLaunch(_ cardClient: CardPayments.CardClient) {
print("About to launch 3DS")
}

func cardThreeDSecureDidFinish(_ cardClient: CardPayments.CardClient) {
print("Finished 3DS")
}
}
43 changes: 15 additions & 28 deletions Demo/Demo/ViewModels/PayPalVaultViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import UIKit
import PayPalWebPayments
import CorePayments

class PayPalVaultViewModel: VaultViewModel, PayPalVaultDelegate {
class PayPalVaultViewModel: VaultViewModel {

let configManager = CoreConfigManager(domain: "PayPal Vault")

Expand All @@ -13,36 +13,23 @@ class PayPalVaultViewModel: VaultViewModel, PayPalVaultDelegate {
do {
let config = try await configManager.getCoreConfig()
let paypalClient = PayPalWebCheckoutClient(config: config)
paypalClient.vaultDelegate = self
let vaultRequest = PayPalVaultRequest(setupTokenID: setupTokenID)
paypalClient.vault(vaultRequest)
paypalClient.vault(vaultRequest) { result, error in
if let error {
DispatchQueue.main.async {
self.state.paypalVaultTokenResponse = .error(message: error.localizedDescription)
}
} else if let result {
DispatchQueue.main.async {
self.state.paypalVaultTokenResponse = .loaded(result)
}
}
}
} catch {
print("Error in vaulting PayPal Payment")
DispatchQueue.main.async {
self.state.paypalVaultTokenResponse = .error(message: error.localizedDescription)
}
}
}

// MARK: - PayPalVault Delegate

func paypal(
_ paypalWebClient: PayPalWebPayments.PayPalWebCheckoutClient,
didFinishWithVaultResult paypalVaultResult: PayPalVaultResult
) {
DispatchQueue.main.async {
self.state.paypalVaultTokenResponse = .loaded(paypalVaultResult)
}
}

func paypal(
_ paypalWebClient: PayPalWebPayments.PayPalWebCheckoutClient,
didFinishWithVaultError vaultError: CorePayments.CoreSDKError
) {

DispatchQueue.main.async {
self.state.paypalVaultTokenResponse = .error(message: vaultError.localizedDescription)
}
}

func paypalDidCancel(_ payPalWebClient: PayPalWebCheckoutClient) {
print("PayPal Checkout Canceled")
}
}
Loading

0 comments on commit 6030da7

Please sign in to comment.