-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Authorize/Capture for PayPalWebPayments in Demo App #216
Conversation
Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalOrderActionButton.swift
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🌊
Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalTransactionButtonsView.swift
Outdated
Show resolved
Hide resolved
@@ -0,0 +1,53 @@ | |||
import SwiftUI | |||
|
|||
struct PayPalWebOrderCompletionResultView: View { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The names of these classes confuse me a bit. What is the difference b/w PayPalWebOrderCompletionResultView
& PayPalWebOrderCompletionView
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the order completion has already taken place maybe PayPalWebResultView
is more appropriate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are several results in these flows. For PayPalWeb, I have order creation result, approval result and the order completion result (result of authorize/capture). So I am distinguishing them with the names.
@@ -0,0 +1,38 @@ | |||
import SwiftUI | |||
|
|||
struct PayPalWebOrderCompletionView: View { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class looks pretty much the exact same as CardPaymentOrderCompletionView.swift. The views should be re-usable across payment method/ view model types.
This way if we want to update this view, we do it in 1 place versus multiple.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment below.
func captureOrder(orderID: String, selectedMerchantIntegration: MerchantIntegration) async throws { | ||
do { | ||
DispatchQueue.main.async { | ||
self.state.capturedOrderResponse = .loading | ||
} | ||
let order = try await DemoMerchantAPI.sharedService.captureOrder( | ||
orderID: orderID, | ||
selectedMerchantIntegration: selectedMerchantIntegration | ||
) | ||
DispatchQueue.main.async { | ||
self.state.capturedOrderResponse = .loaded(order) | ||
} | ||
} catch { | ||
DispatchQueue.main.async { | ||
self.state.capturedOrderResponse = .error(message: error.localizedDescription) | ||
} | ||
print("Error capturing order: \(error.localizedDescription)") | ||
} | ||
} | ||
|
||
func authorizeOrder(orderID: String, selectedMerchantIntegration: MerchantIntegration) async throws { | ||
do { | ||
DispatchQueue.main.async { | ||
self.state.authorizedOrderResponse = .loading | ||
} | ||
let order = try await DemoMerchantAPI.sharedService.authorizeOrder( | ||
orderID: orderID, | ||
selectedMerchantIntegration: selectedMerchantIntegration | ||
) | ||
DispatchQueue.main.async { | ||
self.state.authorizedOrderResponse = .loaded(order) | ||
} | ||
} catch { | ||
DispatchQueue.main.async { | ||
self.state.authorizedOrderResponse = .error(message: error.localizedDescription) | ||
} | ||
print("Error authorizing order: \(error.localizedDescription)") | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, this looks like a copy-paste from CardPaymentViewModel
(see snippet). That duplication is usually a good sign that we should refactor.
Happy to talk through some refactor options. We could go the route of a parent class or a protocol to represent a generic PaymentMethodViewModel
that has a set of default functionality that is re-usable across all payment methods (ex: auth, capture).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is a great suggestion. I will start with PaymentMethodViewModel protocol and incorporate it into common views.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@scannillo , I looked into making a PaymentMethodViewModel
protocol and extension to provide common default authorizeOrder
and captureOrder
function implementations and I ran into issue of having to change stored properties(states) in the conforming types. Protocol extensions, as I understand, cannot mutate stored properties of conforming types. For instance:
self.state.authorizedOrderResponse = .loaded(order)
I could provide in PaymentMethodViewModel
protocol delegate methods like didAuthorizeOrder
and didCaptureOrder
but it would reduce duplication only slightly and introduce complexity.
I am looking into protocol with associatedType but it doesn't look pretty imo.
I ran into similar issue with factoring out views that looks the same - state
in each ViewModel is of different type. I would need to use associated types and also run into issue of observing different properties of states of different types for each viewModels.
I think benefits of reducing a bit of code duplication doesn't justify the complexity introduced.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like there could be a few options in this StackOverflow that may be worth exploring: https://stackoverflow.com/questions/38885622/swift-protocol-extensions-property-default-values. Not sure if Sammy had a different approach in mind as well!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will continue working w PaymentMethodViewModel protocol. I guess all both flows have views for order creation result, order approval result and order capture/authorize result.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created another ticket for refactoring common views and functionalities in the viewModels. https://paypal.atlassian.net/browse/DTPPCPSDK-1437
@@ -1,6 +1,6 @@ | |||
import SwiftUI | |||
|
|||
struct OrderCreateCardPaymentResultView: View { | |||
struct OrderCreateCardResultView: View { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the refactor ticket can we please include updating some of these names? This name doesn't seem to match up with what the code in this file is doing and it's not clear why it's being changed since there are no other code changes in this file. I don't think the original name was super clear but it's especially confusing we made this change with no other changes here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically we have result views for each Orders API calls to check if they are working as expected.
so there are OrderCreateCardResultView, OrderCreatePayPalWebResultView, etc.
And there are also container views since I didn't want them to be all on one scrollable page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It sounds like this will be a great thing to refactor or can be shared in some way across payment methods since most of the logic is the same. I think that will help with naming as then we can have a singular OrderResultView
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is what I want to investigate in the refactor ticket. How to organize the different states to minimize views where it makes sense. Most of the result views have different content. There are two that are identical, order create result views and the "action buttons" for authorize/capture. To me, it's easier to follow if there are separate views for each API call result so we can find them more easily but I will explore different options.
That's why I wanted to create a different PR for the refactor as it will be quite a bit of code change in the viewModels and some backtracking and modifications based on feedback. I wanted to be able to track these changes.
Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalOrderActionButton.swift
Outdated
Show resolved
Hide resolved
Demo/Demo/SwiftUIComponents/PayPalWebViews/PayPalOrderActionButton.swift
Outdated
Show resolved
Hide resolved
@@ -1,7 +1,7 @@ | |||
import SwiftUI | |||
import PaymentButtons | |||
|
|||
struct PayPalTransactionButtonsView: View { | |||
struct PayPalTransactionsView: View { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
struct PayPalTransactionsView: View { | |
struct PayPalTransactionView: View { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are three options of transactions on that view PayPal, PayPal Credit, Pay Later. That's why I put Transactions. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the singular is fine even though it's used in multiple places there will ever only be 1 transaction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for addressing all of my questions/suggestions!
try await paypalWebViewModel.completeOrder( | ||
with: intent, | ||
orderID: orderID, | ||
selectedMerchantIntegration: selectedMerchantIntegration | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
Summary of changes
PayPalWebAuth.mp4
Checklist
- [ ] Added a changelog entryAuthors