Skip to content

Commit 61b222a

Browse files
committed
[DTPP-142] PayPalWebPayments show stages of order
1 parent 8194323 commit 61b222a

File tree

7 files changed

+149
-53
lines changed

7 files changed

+149
-53
lines changed

Demo/Demo/CardPayments/CardPaymentViewModel/CardPaymentState.swift

+47
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,50 @@ struct CardPaymentState: Equatable {
4949
}
5050
}
5151
}
52+
53+
struct PayPalPaymentState: Equatable {
54+
55+
struct ApprovalResult: Decodable, Equatable {
56+
let id: String
57+
let status: String?
58+
59+
}
60+
var createOrder: Order?
61+
var authorizedOrder: Order?
62+
var capturedOrder: Order?
63+
var intent: Intent = .authorize
64+
var approveResult: ApprovalResult?
65+
66+
var createdOrderResponse: LoadingState<Order> = .idle {
67+
didSet {
68+
if case .loaded(let value) = createdOrderResponse {
69+
createOrder = value
70+
}
71+
}
72+
}
73+
74+
var approveResultResponse: LoadingState<ApprovalResult> = .idle {
75+
didSet {
76+
if case .loaded(let value) = approveResultResponse {
77+
78+
approveResult = value
79+
}
80+
}
81+
}
82+
83+
var capturedOrderResponse: LoadingState<Order> = .idle {
84+
didSet {
85+
if case .loaded(let value) = capturedOrderResponse {
86+
capturedOrder = value
87+
}
88+
}
89+
}
90+
91+
var authorizedOrderResponse: LoadingState<Order> = .idle {
92+
didSet {
93+
if case .loaded(let value) = authorizedOrderResponse {
94+
authorizedOrder = value
95+
}
96+
}
97+
}
98+
}

Demo/Demo/PayPalWebPayments/PayPalWebPaymentsView/PayPalWebButtonsView.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ struct PayPalWebButtonsView: View {
3939
payPalWebViewModel.paymentButtonTapped(funding: .paypal)
4040
}
4141
}
42-
if payPalWebViewModel.state == .loading &&
42+
if payPalWebViewModel.state.createdOrderResponse == .loading &&
4343
payPalWebViewModel.checkoutResult == nil &&
4444
payPalWebViewModel.orderID != nil {
4545
CircularProgressView()

Demo/Demo/PayPalWebPayments/PayPalWebPaymentsView/PayPalWebCreateOrderView.swift

+4-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ struct PayPalWebCreateOrderView: View {
4040
}
4141
}
4242
.buttonStyle(RoundedBlueButtonStyle())
43-
if payPalWebViewModel.state == .loading && payPalWebViewModel.checkoutResult == nil && payPalWebViewModel.orderID == nil {
43+
// if payPalWebViewModel.state == .loading && payPalWebViewModel.checkoutResult == nil && payPalWebViewModel.orderID == nil {
44+
// CircularProgressView()
45+
// }
46+
if case .loading = payPalWebViewModel.state.createdOrderResponse {
4447
CircularProgressView()
4548
}
4649
}

Demo/Demo/PayPalWebPayments/PayPalWebPaymentsView/PayPalWebPaymentsView.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ struct PayPalWebPaymentsView: View {
1010
VStack(spacing: 16) {
1111
PayPalWebCreateOrderView(payPalWebViewModel: payPalWebViewModel)
1212

13-
if payPalWebViewModel.orderID != nil {
13+
if payPalWebViewModel.state.createOrder?.id != nil {
1414
PayPalWebButtonsView(payPalWebViewModel: payPalWebViewModel)
1515
}
1616

Demo/Demo/PayPalWebPayments/PayPalWebPaymentsView/PayPalWebResultView.swift

+12-15
Original file line numberDiff line numberDiff line change
@@ -5,44 +5,41 @@ struct PayPalWebResultView: View {
55
@ObservedObject var payPalWebViewModel: PayPalWebViewModel
66

77
var body: some View {
8-
switch payPalWebViewModel.state {
8+
switch payPalWebViewModel.state.createdOrderResponse {
99
case .idle, .loading:
1010
EmptyView()
11-
case .success:
12-
successView
11+
case .loaded(let createOrderResponse):
12+
getSuccessView(createOrderResponse: createOrderResponse)
1313
case .error(let errorMessage):
1414
ErrorView(errorMessage: errorMessage)
1515
}
1616
}
1717

18-
var successView: some View {
18+
func getSuccessView(createOrderResponse: Order) -> some View {
1919
VStack(alignment: .leading, spacing: 16) {
2020
HStack {
2121
Text("Order Details")
2222
.font(.system(size: 20))
2323
Spacer()
2424
}
25-
if let orderID = payPalWebViewModel.orderID {
26-
LabelViewText("Order ID:", bodyText: orderID)
27-
}
28-
29-
if let status = payPalWebViewModel.order?.status {
30-
LabelViewText("Status:", bodyText: status)
31-
}
25+
26+
LabelViewText("Order ID:", bodyText: createOrderResponse.id)
27+
28+
LabelViewText("Status:", bodyText: createOrderResponse.status)
3229

3330
if let payerID = payPalWebViewModel.checkoutResult?.payerID {
34-
LabelViewText("Payer ID:", bodyText: payerID)
31+
LabelViewText("Payer ID:", bodyText: createOrderResponse.status)
3532
}
3633

37-
if let emailAddress = payPalWebViewModel.order?.paymentSource?.paypal?.emailAddress {
34+
if let emailAddress = createOrderResponse.paymentSource?.paypal?.emailAddress {
3835
LabelViewText("Email:", bodyText: emailAddress)
3936
}
4037

41-
if let vaultID = payPalWebViewModel.order?.paymentSource?.paypal?.attributes?.vault.id {
38+
if let vaultID = createOrderResponse.paymentSource?.paypal?.attributes?.vault.id {
4239
LabelViewText("Payment Token:", bodyText: vaultID)
4340
}
4441

45-
if let customerID = payPalWebViewModel.order?.paymentSource?.paypal?.attributes?.vault.customer?.id {
42+
if let customerID = createOrderResponse.paymentSource?.paypal?.attributes?.vault.customer?.id {
4643
LabelViewText("Customer ID:", bodyText: customerID)
4744
}
4845
}

Demo/Demo/PayPalWebPayments/PayPalWebPaymentsView/PayPalWebTransactionView.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ struct PayPalWebTransactionView: View {
1919
.buttonStyle(RoundedBlueButtonStyle())
2020
.padding()
2121

22-
if payPalWebViewModel.state == .loading {
22+
if payPalWebViewModel.state.capturedOrderResponse == .loading {
2323
CircularProgressView()
2424
}
2525
}

Demo/Demo/PayPalWebPayments/PayPalWebViewModel/PayPalWebViewModel.swift

+83-34
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import FraudProtection
55

66
class PayPalWebViewModel: ObservableObject {
77

8-
@Published var state: CurrentState = .idle
8+
@Published var state = PayPalPaymentState()
99
@Published var intent: Intent = .authorize
1010
@Published var order: Order?
1111
@Published var checkoutResult: PayPalWebCheckoutResult?
@@ -44,25 +44,75 @@ class PayPalWebViewModel: ObservableObject {
4444
)
4545

4646
do {
47-
updateState(.loading)
47+
DispatchQueue.main.async {
48+
self.state.createdOrderResponse = .loading
49+
}
4850
let order = try await DemoMerchantAPI.sharedService.createOrder(
4951
orderParams: orderRequestParams,
5052
selectedMerchantIntegration: DemoSettings.merchantIntegration
5153
)
52-
53-
updateOrder(order)
54-
updateState(.success)
54+
DispatchQueue.main.async {
55+
self.state.createdOrderResponse = .loaded(order)
56+
}
57+
// updateOrder(order)
58+
// updateState(.success)
5559
print("✅ fetched orderID: \(order.id) with status: \(order.status)")
5660
} catch {
57-
updateState(.error(message: error.localizedDescription))
61+
DispatchQueue.main.async {
62+
self.state.createdOrderResponse = .error(message: error.localizedDescription)
63+
}
5864
print("❌ failed to fetch orderID with error: \(error.localizedDescription)")
5965
}
6066
}
67+
68+
func captureOrder(orderID: String, selectedMerchantIntegration: MerchantIntegration) async {
69+
do {
70+
self.state.capturedOrderResponse = .loading
71+
let payPalClientMetadataID = payPalDataCollector?.collectDeviceData()
72+
let order = try await DemoMerchantAPI.sharedService.captureOrder(
73+
orderID: orderID,
74+
selectedMerchantIntegration: selectedMerchantIntegration,
75+
payPalClientMetadataID: payPalClientMetadataID
76+
)
77+
DispatchQueue.main.async {
78+
self.state.capturedOrderResponse = .loaded(order)
79+
}
80+
} catch {
81+
DispatchQueue.main.async {
82+
self.state.capturedOrderResponse = .error(message: error.localizedDescription)
83+
}
84+
print("❌ Failed to capture order: \(error.localizedDescription)")
85+
}
86+
}
87+
88+
func authorizeOrder(orderID: String, selectedMerchantIntegration: MerchantIntegration) async {
89+
do {
90+
DispatchQueue.main.async {
91+
self.state.authorizedOrderResponse = .loading
92+
}
93+
let payPalClientMetadataID = payPalDataCollector?.collectDeviceData()
94+
let order = try await DemoMerchantAPI.sharedService.authorizeOrder(
95+
orderID: orderID,
96+
selectedMerchantIntegration: selectedMerchantIntegration,
97+
payPalClientMetadataID: payPalClientMetadataID
98+
)
99+
DispatchQueue.main.async {
100+
self.state.authorizedOrderResponse = .loaded(order)
101+
}
102+
} catch {
103+
DispatchQueue.main.async {
104+
self.state.authorizedOrderResponse = .error(message: error.localizedDescription)
105+
}
106+
print("❌ Failed to authorize order: \(error.localizedDescription)")
107+
}
108+
}
61109

62110
func paymentButtonTapped(funding: PayPalWebCheckoutFundingSource) {
63111
Task {
64112
do {
65-
self.updateState(.loading)
113+
DispatchQueue.main.async {
114+
self.state.createdOrderResponse = .loading
115+
}
66116
payPalWebCheckoutClient = try await getPayPalClient()
67117
guard let payPalWebCheckoutClient else {
68118
print("Error initializing PayPalWebCheckoutClient")
@@ -73,22 +123,28 @@ class PayPalWebViewModel: ObservableObject {
73123
let payPalRequest = PayPalWebCheckoutRequest(orderID: orderID, fundingSource: funding)
74124
payPalWebCheckoutClient.start(request: payPalRequest) { result, error in
75125
if let error {
76-
if error == PayPalError.checkoutCanceledError {
77-
print("Canceled")
78-
self.updateState(.idle)
79-
} else {
80-
self.updateState(.error(message: error.localizedDescription))
126+
DispatchQueue.main.async {
127+
if error == PayPalError.checkoutCanceledError {
128+
print("Canceled")
129+
self.state.createdOrderResponse = .idle
130+
} else {
131+
self.state.createdOrderResponse = .error(message: error.localizedDescription)
132+
}
81133
}
82134
} else {
83-
self.updateState(.success)
84-
self.checkoutResult = result
135+
// self.updateState(.success)
136+
DispatchQueue.main.async {
137+
self.state.createdOrderResponse = .loaded(Order(id: orderID, status: "COMPLETED"))
138+
self.checkoutResult = result
139+
print("✅ Checkout result: \(String(describing: result))")
140+
}
85141
}
86142
}
87143
}
88-
updateState(.success)
144+
// updateState(.success)
89145
} catch {
90146
print("Error starting PayPalWebCheckoutClient")
91-
updateState(.error(message: error.localizedDescription))
147+
self.state.createdOrderResponse = .error(message: error.localizedDescription)
92148
}
93149
}
94150
}
@@ -100,15 +156,17 @@ class PayPalWebViewModel: ObservableObject {
100156
payPalDataCollector = PayPalDataCollector(config: config)
101157
return payPalClient
102158
} catch {
103-
updateState(.error(message: error.localizedDescription))
159+
DispatchQueue.main.async {
160+
self.state.createdOrderResponse = .error(message: error.localizedDescription)
161+
}
104162
print("❌ failed to create PayPalWebCheckoutClient with error: \(error.localizedDescription)")
105163
return nil
106164
}
107165
}
108166

109167
func completeTransaction() async throws {
110168
do {
111-
updateState(.loading)
169+
self.state.authorizedOrderResponse = .loading
112170

113171
let payPalClientMetadataID = payPalDataCollector?.collectDeviceData()
114172
if let orderID {
@@ -117,30 +175,21 @@ class PayPalWebViewModel: ObservableObject {
117175
orderID: orderID,
118176
payPalClientMetadataID: payPalClientMetadataID
119177
)
120-
updateOrder(order)
121-
updateState(.success)
178+
DispatchQueue.main.async {
179+
self.state.authorizedOrderResponse = .loaded(order)
180+
}
122181
}
123182
} catch {
124-
updateState(.error(message: error.localizedDescription))
183+
DispatchQueue.main.async {
184+
self.state.authorizedOrderResponse = .error(message: error.localizedDescription)
185+
}
125186
print("Error with \(intent) order: \(error.localizedDescription)")
126187
}
127188
}
128189

129190
func resetState() {
130-
updateState(.idle)
191+
self.state = PayPalPaymentState()
131192
order = nil
132193
checkoutResult = nil
133194
}
134-
135-
private func updateOrder(_ order: Order) {
136-
DispatchQueue.main.async {
137-
self.order = order
138-
}
139-
}
140-
141-
private func updateState(_ state: CurrentState) {
142-
DispatchQueue.main.async {
143-
self.state = state
144-
}
145-
}
146195
}

0 commit comments

Comments
 (0)