Skip to content
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

Refactor PayPal Web Demo App into Single View #227

Merged
merged 17 commits into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Demo/Demo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@
BC9D4D2627C6D1720089E5B1 /* XCUIElement+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC9D4D2527C6D1720089E5B1 /* XCUIElement+Helpers.swift */; };
BE1766B326F911A2007EF438 /* URLResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE1766B226F911A2007EF438 /* URLResponseError.swift */; };
BE1766D926FA7BC8007EF438 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = BE1766D826FA7BC8007EF438 /* Settings.bundle */; };
BE5898952B2B91F800AA196E /* LabelViewText.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE5898942B2B91F800AA196E /* LabelViewText.swift */; };
BE8117642B07E778009867B9 /* PayPalWebResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE8117632B07E778009867B9 /* PayPalWebResultView.swift */; };
BE8117662B080202009867B9 /* PayPalWebStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE8117652B080202009867B9 /* PayPalWebStatusView.swift */; };
BE8117682B080472009867B9 /* CurrentState.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE8117672B080472009867B9 /* CurrentState.swift */; };
BE9F36D82745490400AFC7DA /* FloatingLabelTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE9F36D72745490400AFC7DA /* FloatingLabelTextField.swift */; };
BECD84A027036DC2007CCAE4 /* Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = BECD849F27036DC2007CCAE4 /* Environment.swift */; };
Expand Down Expand Up @@ -198,8 +198,8 @@
BE1766B226F911A2007EF438 /* URLResponseError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLResponseError.swift; sourceTree = "<group>"; };
BE1766D826FA7BC8007EF438 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; };
BE420F3628189A7A00D8D66A /* PayPalUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PayPalUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BE5898942B2B91F800AA196E /* LabelViewText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelViewText.swift; sourceTree = "<group>"; };
BE8117632B07E778009867B9 /* PayPalWebResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalWebResultView.swift; sourceTree = "<group>"; };
BE8117652B080202009867B9 /* PayPalWebStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalWebStatusView.swift; sourceTree = "<group>"; };
BE8117672B080472009867B9 /* CurrentState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentState.swift; sourceTree = "<group>"; };
BE9F36D72745490400AFC7DA /* FloatingLabelTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingLabelTextField.swift; sourceTree = "<group>"; };
BECD849F27036DC2007CCAE4 /* Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Environment.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -287,7 +287,6 @@
3BA570022AA053AE0081D14F /* PayPalWebCreateOrderView.swift */,
3BA570002AA052E80081D14F /* PayPalWebPaymentsView.swift */,
BE8117632B07E778009867B9 /* PayPalWebResultView.swift */,
BE8117652B080202009867B9 /* PayPalWebStatusView.swift */,
3B6472A62AFAEB3A004745C4 /* PayPalWebTransactionView.swift */,
3BA56FFB2A9FEFE90081D14F /* PayPalWebViewModel.swift */,
);
Expand All @@ -313,6 +312,7 @@
3BC6220A2A97204E00251B85 /* CircularProgressView.swift */,
3BC622082A97198500251B85 /* LeadingText.swift */,
3BA5700A2AA13C1C0081D14F /* CoreConfigManager.swift */,
BE5898942B2B91F800AA196E /* LabelViewText.swift */,
);
path = CommonComponents;
sourceTree = "<group>";
Expand Down Expand Up @@ -606,6 +606,7 @@
3BC622092A97198500251B85 /* LeadingText.swift in Sources */,
3B80D5102A291CB100D2EAC4 /* ClientIDResponse.swift in Sources */,
3BCCFE462A9D47AC00C5102F /* CardExtensions.swift in Sources */,
BE5898952B2B91F800AA196E /* LabelViewText.swift in Sources */,
CB34B32328BE3A9A001325B9 /* PayPalViewModel.swift in Sources */,
3BC622072A97115700251B85 /* RoundedBlueButtonStyle.swift in Sources */,
3B4DD9A22A8982B000F4A716 /* CardFormView.swift in Sources */,
Expand All @@ -629,7 +630,6 @@
3BA0A58B2B1E240300330681 /* VaultViewModel.swift in Sources */,
80F33CF326F8EA50006811B1 /* DemoSettings.swift in Sources */,
3BA56FE72A9DC9D70081D14F /* CardPaymentViewModel.swift in Sources */,
BE8117662B080202009867B9 /* PayPalWebStatusView.swift in Sources */,
3BA5700B2AA13C1C0081D14F /* CoreConfigManager.swift in Sources */,
80E4300C2AD82C8D003CA748 /* ShippingPreference.swift in Sources */,
BEDE304A275EA33500D275FD /* UIViewController+Extension.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import SwiftUI

struct LabelViewText: View {
jaxdesmarais marked this conversation as resolved.
Show resolved Hide resolved

var titleText: String
var bodyText: String

var body: some View {
HStack {
Text(titleText).fontWeight(.bold)
Text(bodyText)
}
}

init(_ titleText: String, bodyText: String) {
self.titleText = titleText
self.bodyText = bodyText
}
}
Original file line number Diff line number Diff line change
@@ -1,49 +1,52 @@
import SwiftUI
import PaymentButtons
import PayPalWebPayments

struct PayPalWebButtonsView: View {

@ObservedObject var payPalWebViewModel: PayPalWebViewModel

@State private var selectedFundingSource: PayPalWebCheckoutFundingSource = .paypal

var body: some View {
VStack {
VStack(alignment: .center, spacing: 40) {
PayPalButton.Representable(color: .blue, size: .mini) {
payPalWebViewModel.paymentButtonTapped(funding: .paypal)
VStack(alignment: .center, spacing: 16) {
HStack {
Text("Checkout with PayPal")
.font(.system(size: 20))
Spacer()
}
.frame(maxWidth: .infinity, maxHeight: 40)
PayPalCreditButton.Representable(color: .black, edges: .softEdges, size: .expanded) {
payPalWebViewModel.paymentButtonTapped(funding: .paypalCredit)
.frame(maxWidth: .infinity)
.font(.headline)
Picker("Funding Source", selection: $selectedFundingSource) {
Text("PayPal").tag(PayPalWebCheckoutFundingSource.paypal)
Text("PayPal Credit").tag(PayPalWebCheckoutFundingSource.paylater)
Text("Pay Later").tag(PayPalWebCheckoutFundingSource.paypalCredit)
}
.frame(maxWidth: .infinity, maxHeight: 40)
PayPalPayLaterButton.Representable(color: .silver, edges: .rounded, size: .full) {
payPalWebViewModel.paymentButtonTapped(funding: .paylater)
.pickerStyle(SegmentedPickerStyle())

switch selectedFundingSource {
case .paypalCredit:
PayPalCreditButton.Representable(color: .black, size: .full) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the buttons are the same size now. We have a separate Payment Button demo that displays all of the options of size/color/etc.

payPalWebViewModel.paymentButtonTapped(funding: .paypalCredit)
}
case .paylater:
PayPalPayLaterButton.Representable(color: .silver, edges: .softEdges, size: .full) {
payPalWebViewModel.paymentButtonTapped(funding: .paylater)
}
case .paypal:
PayPalButton.Representable(color: .blue, size: .full) {
payPalWebViewModel.paymentButtonTapped(funding: .paypal)
}
}
.frame(maxWidth: .infinity, maxHeight: 40)
}
.frame(height: 150)
.padding(20)
.padding()
.background(
RoundedRectangle(cornerRadius: 10)
.stroke(.gray, lineWidth: 2)
.padding(5)
)

if payPalWebViewModel.checkoutResult != nil && payPalWebViewModel.state == .success {
PayPalWebResultView(payPalWebViewModel: payPalWebViewModel, status: .approved)
NavigationLink {
PayPalWebTransactionView(payPalWebViewModel: payPalWebViewModel)
.navigationTitle("Complete Transaction")
} label: {
Text("Complete Transaction")
}
.navigationViewStyle(StackNavigationViewStyle())
.buttonStyle(RoundedBlueButtonStyle())
.padding()
} else if case .error = payPalWebViewModel.state {
PayPalWebResultView(payPalWebViewModel: payPalWebViewModel, status: .error)
}
Spacer()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ struct PayPalWebCreateOrderView: View {
Text("Create an Order")
.font(.system(size: 20))
Spacer()
Button("Reset") {
payPalWebViewModel.resetState()
}
}
.frame(maxWidth: .infinity)
.font(.headline)
Expand All @@ -37,7 +40,7 @@ struct PayPalWebCreateOrderView: View {
}
}
.buttonStyle(RoundedBlueButtonStyle())
if payPalWebViewModel.state == .loading {
if payPalWebViewModel.state == .loading && payPalWebViewModel.checkoutResult == nil {
CircularProgressView()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,31 @@ struct PayPalWebPaymentsView: View {

var body: some View {
ScrollView {
VStack(spacing: 16) {
PayPalWebCreateOrderView(payPalWebViewModel: payPalWebViewModel)
if payPalWebViewModel.createOrderResult != nil && payPalWebViewModel.state == .success {
PayPalWebResultView(payPalWebViewModel: payPalWebViewModel, status: .created)
NavigationLink {
ScrollViewReader { scrollView in
VStack(spacing: 16) {
PayPalWebCreateOrderView(payPalWebViewModel: payPalWebViewModel)

if payPalWebViewModel.orderID != nil {
PayPalWebButtonsView(payPalWebViewModel: payPalWebViewModel)
.navigationTitle("Checkout with PayPal")
} label: {
Text("Checkout with PayPal")
}
.buttonStyle(RoundedBlueButtonStyle())
.padding()
} else if case .error = payPalWebViewModel.state {
PayPalWebResultView(payPalWebViewModel: payPalWebViewModel, status: .error)

PayPalWebResultView(payPalWebViewModel: payPalWebViewModel)

if payPalWebViewModel.checkoutResult != nil {
PayPalWebTransactionView(payPalWebViewModel: payPalWebViewModel)
.padding(.bottom, 20)
.id("bottomView")
.onAppear {
withAnimation {
scrollView.scrollTo("bottomView")
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scrolling to the bottom of a view is most commonly used with table views or a view that has incrementing IDs to reference. In order to scroll to the bottom both when displaying this view as well as the bottom of the result after authorizing/capturing we need to duplicate this scrollTo logic. Bit odd but it seemed like the solution for this from what I found online. 🤷‍♂️

}
}
}
}
.onChange(of: payPalWebViewModel.state) { _ in
withAnimation {
scrollView.scrollTo("bottomView")
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,57 @@
import SwiftUI

enum OrderStatus {
case created
case approved
case completed
case error
}

struct PayPalWebResultView: View {

@ObservedObject var payPalWebViewModel: PayPalWebViewModel

var status: OrderStatus

var body: some View {
switch payPalWebViewModel.state {
case .idle, .loading:
EmptyView()
case .success:
PayPalWebStatusView(status: status, payPalWebViewModel: payPalWebViewModel)
successView
case .error(let errorMessage):
ErrorView(errorMessage: errorMessage)
}
}

var successView: some View {
VStack(alignment: .leading, spacing: 16) {
HStack {
Text("Order Details")
.font(.system(size: 20))
Spacer()
}
if let orderID = payPalWebViewModel.orderID {
LabelViewText("Order ID:", bodyText: orderID)
}

if let status = payPalWebViewModel.order?.status {
LabelViewText("Status:", bodyText: status)
}

if let payerID = payPalWebViewModel.checkoutResult?.payerID {
LabelViewText("Payer ID:", bodyText: payerID)
}

if let emailAddress = payPalWebViewModel.order?.paymentSource?.paypal?.emailAddress {
LabelViewText("Email:", bodyText: emailAddress)
}

if let vaultID = payPalWebViewModel.order?.paymentSource?.paypal?.attributes?.vault.id {
LabelViewText("Payment Token:", bodyText: vaultID)
}

if let customerID = payPalWebViewModel.order?.paymentSource?.paypal?.attributes?.vault.customer.id {
LabelViewText("Customer ID:", bodyText: customerID)
}
}
.frame(maxWidth: .infinity)
.padding()
.background(
RoundedRectangle(cornerRadius: 10)
.stroke(.gray, lineWidth: 2)
.padding(5)
)
}
}

This file was deleted.

Loading
Loading