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

Add Shopper Insights Demo feature #1158

Merged
merged 22 commits into from
Dec 15, 2023
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
aacf5d9
Create new Source & UnitTest directories & targets
scannillo Dec 11, 2023
5e9e19e
Update UnitTests scheme
scannillo Dec 11, 2023
c753d8a
Package manager updates + test info.plist
scannillo Dec 11, 2023
9b6f87f
Fixup - address duplicate info.plist build error
scannillo Dec 11, 2023
42eeff3
Add CHANGELOG entry
scannillo Dec 11, 2023
8e713c7
Fixup - remove redundant top-level directory
scannillo Dec 11, 2023
fbf68cb
Fixup - remove reference to non-existing .h file
scannillo Dec 12, 2023
36a110b
add BraintreeCore target to BraintreeShopperInsights Frameworks & Lib…
scannillo Dec 12, 2023
8f75e1d
Fixup - fix typo in podspec sources path
scannillo Dec 12, 2023
54a8f58
Only support iOS platform in ShopperInsights target
scannillo Dec 12, 2023
599e714
Update CHANGELOG.md
scannillo Dec 12, 2023
a39153f
Fixup - remove reference to top-level, accidental, ShopperInsights dir
scannillo Dec 12, 2023
0df387a
Restore old PreferredPaymentMethods demo ViewController
scannillo Dec 12, 2023
f619a69
Remove nested PreferredPayments dir
scannillo Dec 12, 2023
df9c4ee
Rename & update file for latest API & iOS V6 changes
scannillo Dec 12, 2023
a44a61d
Add Shopper Insights feature into Settings
scannillo Dec 12, 2023
8d73d4c
Cleanup - rename old variables with PreferredPayments reference
scannillo Dec 12, 2023
69bd6da
Adjust syntax/indendation for constraints array
scannillo Dec 12, 2023
95845c0
Merge branch 'payment-insights-feature' into shopper-insights-demo
scannillo Dec 12, 2023
4f47a26
Delete Braintree.xcworkspace/xcshareddata/swiftpm/Package.resolved
scannillo Dec 12, 2023
92676b6
PR Feedback - cleanup demo to leverage PaymentButtonBaseViewControlle…
scannillo Dec 14, 2023
45eb5f8
Fixup - move to lazy button initialization to be able to disable/enab…
scannillo Dec 14, 2023
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
2 changes: 2 additions & 0 deletions Demo/Application/Base/ContainmentViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@ class ContainmentViewController: UIViewController {
return PayPalWebCheckoutViewController(authorization: authorization)
case "SEPADirectDebitViewController":
return SEPADirectDebitViewController(authorization: authorization)
case "ShopperInsightsViewController":
return ShopperInsightsViewController(authorization: authorization)
case "ThreeDSecureViewController":
return ThreeDSecureViewController(authorization: authorization)
case "VenmoViewController":
Expand Down
2 changes: 2 additions & 0 deletions Demo/Application/Base/Settings/Settings.bundle/Root.plist
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
<string>iDEAL</string>
<string>Amex</string>
<string>SEPA Direct Debit</string>
<string>Shopper Insights</string>
</array>
<key>Values</key>
<array>
Expand All @@ -40,6 +41,7 @@
<string>IdealViewController</string>
<string>AmexViewController</string>
<string>SEPADirectDebitViewController</string>
<string>ShopperInsightsViewController</string>
</array>
</dict>
<dict>
Expand Down
150 changes: 150 additions & 0 deletions Demo/Application/Features/ShopperInsightsViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import UIKit
import BraintreeCore
import BraintreePayPal
import BraintreeVenmo
import BraintreeShopperInsights

class ShopperInsightsViewController: PaymentButtonBaseViewController {
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure if we want to 🏈 on this based on the PR description but subclassing PaymentButtonBaseViewController should allow us to get a lot of this for "free". Specially the createButton and ability to remove the override of the auth init.

Copy link
Contributor

Choose a reason for hiding this comment

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

I know this is in the Demo app, so not as merchant impacting, but I personally think it's acceptable to take a little time and do this work now. If folks push back we can lean on the company's leadership principles.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a great callout! Addressed in 92676b6


private let shopperInsightsClient: BTShopperInsightsClient
private let paypalClient: BTPayPalClient
private let venmoClient: BTVenmoClient
private let payPalCheckoutButton = UIButton(type: .system)
private let payPalVaultButton = UIButton(type: .system)
private let venmoButton = UIButton(type: .system)

override init(authorization: String) {
let apiClient = BTAPIClient(authorization: authorization)!

shopperInsightsClient = BTShopperInsightsClient(apiClient: apiClient)
paypalClient = BTPayPalClient(apiClient: apiClient)
venmoClient = BTVenmoClient(apiClient: apiClient)

super.init(authorization: authorization)

title = "Shopper Insights"

let shopperInsightsButton = UIButton(type: .system)
shopperInsightsButton.setTitle("Fetch recommended payments", for: .normal)
shopperInsightsButton.translatesAutoresizingMaskIntoConstraints = false
shopperInsightsButton.addTarget(self, action: #selector(shopperInsightsButtonTapped(_:)), for: .touchUpInside)
view.addSubview(shopperInsightsButton)

payPalCheckoutButton.setTitle("PayPal Checkout", for: .normal)
payPalCheckoutButton.translatesAutoresizingMaskIntoConstraints = false
payPalCheckoutButton.addTarget(self, action: #selector(payPalCheckoutButtonTapped(_:)), for: .touchUpInside)
payPalCheckoutButton.isEnabled = false
view.addSubview(payPalCheckoutButton)

payPalVaultButton.setTitle("PayPal Vault", for: .normal)
payPalVaultButton.translatesAutoresizingMaskIntoConstraints = false
payPalVaultButton.addTarget(self, action: #selector(payPalVaultButtonTapped(_:)), for: .touchUpInside)
payPalVaultButton.isEnabled = false
view.addSubview(payPalVaultButton)

venmoButton.setTitle("Venmo", for: .normal)
venmoButton.translatesAutoresizingMaskIntoConstraints = false
venmoButton.addTarget(self, action: #selector(venmoButtonTapped(_:)), for: .touchUpInside)
venmoButton.isEnabled = false
view.addSubview(venmoButton)

view.addConstraints([
shopperInsightsButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
shopperInsightsButton.centerYAnchor.constraint(equalTo: view.centerYAnchor),
payPalVaultButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
payPalVaultButton.bottomAnchor.constraint(equalTo: payPalCheckoutButton.bottomAnchor, constant: -40),
payPalCheckoutButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
payPalCheckoutButton.bottomAnchor.constraint(equalTo: venmoButton.bottomAnchor, constant: -40),
venmoButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
venmoButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -40)
])
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
scannillo marked this conversation as resolved.
Show resolved Hide resolved

@objc func shopperInsightsButtonTapped(_ button: UIButton) {
self.progressBlock("Fetching shopper insights...")

let request = BTShopperInsightsRequest(
email: "[email protected]",
phone: Phone(
countryCode: "1",
nationalNumber: "1234567"
)
)
Task {
do {
let result = try await shopperInsightsClient.getRecommendedPaymentMethods(request: request)
self.progressBlock("PayPal Recommended: \(result.isPayPalRecommended)\nVenmo Recommended: \(result.isVenmoRecommended)")
self.payPalCheckoutButton.isEnabled = result.isPayPalRecommended
self.payPalVaultButton.isEnabled = result.isPayPalRecommended
self.venmoButton.isEnabled = result.isVenmoRecommended
} catch {
self.progressBlock("Error: \(error.localizedDescription)")
}
}
}

@objc func payPalCheckoutButtonTapped(_ button: UIButton) {
self.progressBlock("Tapped PayPal Checkout")

button.setTitle("Processing...", for: .disabled)
button.isEnabled = false

let paypalRequest = BTPayPalCheckoutRequest(amount: "4.30")
paypalClient.tokenize(paypalRequest) { (nonce, error) in
button.isEnabled = true

if let e = error {
self.progressBlock(e.localizedDescription)
} else if let n = nonce {
self.completionBlock(n)
scannillo marked this conversation as resolved.
Show resolved Hide resolved
} else {
self.progressBlock("Canceled")
}
}
}

@objc func payPalVaultButtonTapped(_ button: UIButton) {
self.progressBlock("Tapped PayPal Vault")

button.setTitle("Processing...", for: .disabled)
button.isEnabled = false

let paypalRequest = BTPayPalVaultRequest()
paypalClient.tokenize(paypalRequest) { (nonce, error) in
button.isEnabled = true

if let e = error {
self.progressBlock(e.localizedDescription)
} else if let n = nonce {
self.completionBlock(n)
scannillo marked this conversation as resolved.
Show resolved Hide resolved
} else {
self.progressBlock("Canceled")
}
}
}

@objc func venmoButtonTapped(_ button: UIButton) {
self.progressBlock("Tapped Venmo")

button.setTitle("Processing...", for: .disabled)
button.isEnabled = false

let venmoRequest = BTVenmoRequest(paymentMethodUsage: .multiUse)
venmoClient.tokenize(venmoRequest) { (nonce, error) in
button.isEnabled = true

if let e = error {
self.progressBlock(e.localizedDescription)
} else if let n = nonce {
self.completionBlock(n)
scannillo marked this conversation as resolved.
Show resolved Hide resolved
} else {
self.progressBlock("Canceled")
}
}
}
}

4 changes: 4 additions & 0 deletions Demo/Demo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
57108A152832E789004EB870 /* PayPalNativeCheckoutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57108A142832E789004EB870 /* PayPalNativeCheckoutViewController.swift */; };
57108A172832EA04004EB870 /* BraintreePayPalNativeCheckout.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 57108A162832EA04004EB870 /* BraintreePayPalNativeCheckout.framework */; };
57108A182832EA04004EB870 /* BraintreePayPalNativeCheckout.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 57108A162832EA04004EB870 /* BraintreePayPalNativeCheckout.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
8028B9762B28C9E100C88CE8 /* ShopperInsightsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8028B9752B28C9E100C88CE8 /* ShopperInsightsViewController.swift */; };
8028B9782B28D42400C88CE8 /* BraintreeShopperInsights.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8028B9772B28D42400C88CE8 /* BraintreeShopperInsights.framework */; };
8028B9792B28D42400C88CE8 /* BraintreeShopperInsights.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8028B9772B28D42400C88CE8 /* BraintreeShopperInsights.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
803D64F5256DAF9A00ACE692 /* BraintreeAmericanExpress.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 803D64EA256DAF9A00ACE692 /* BraintreeAmericanExpress.framework */; };
Expand Down Expand Up @@ -138,6 +139,7 @@
57108A162832EA04004EB870 /* BraintreePayPalNativeCheckout.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BraintreePayPalNativeCheckout.framework; sourceTree = BUILT_PRODUCTS_DIR; };
6D23244B5E9EE59BAB3F3003 /* Pods_Demo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Demo.framework; sourceTree = BUILT_PRODUCTS_DIR; };
73498B4265CA7D315E2FBF38 /* Pods-Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Demo.debug.xcconfig"; path = "Target Support Files/Pods-Demo/Pods-Demo.debug.xcconfig"; sourceTree = "<group>"; };
8028B9752B28C9E100C88CE8 /* ShopperInsightsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShopperInsightsViewController.swift; sourceTree = "<group>"; };
8028B9772B28D42400C88CE8 /* BraintreeShopperInsights.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BraintreeShopperInsights.framework; sourceTree = BUILT_PRODUCTS_DIR; };
803D64EA256DAF9A00ACE692 /* BraintreeAmericanExpress.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BraintreeAmericanExpress.framework; sourceTree = BUILT_PRODUCTS_DIR; };
803D64EB256DAF9A00ACE692 /* BraintreeApplePay.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BraintreeApplePay.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -346,6 +348,7 @@
57108A142832E789004EB870 /* PayPalNativeCheckoutViewController.swift */,
BED7C4C92ABDD35700EF8550 /* PayPalWebCheckoutViewController.swift */,
BE777AC327D9370400487D23 /* SEPADirectDebitViewController.swift */,
8028B9752B28C9E100C88CE8 /* ShopperInsightsViewController.swift */,
BEBD52862AABA513005D6687 /* ThreeDSecureViewController.swift */,
80D36DED2A7967F20035380E /* VenmoViewController.swift */,
809E86A42ACF6607004998B0 /* Helpers */,
Expand Down Expand Up @@ -653,6 +656,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8028B9762B28C9E100C88CE8 /* ShopperInsightsViewController.swift in Sources */,
BEAAAA342A98E5E6001ECA63 /* IdealViewController.swift in Sources */,
BE994B0D2AD838A500470773 /* PaymentButtonBaseViewController.swift in Sources */,
BED7C4CA2ABDD35700EF8550 /* PayPalWebCheckoutViewController.swift in Sources */,
Expand Down