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 BTShopperInsights public API shell #1142

Merged
merged 9 commits into from
Dec 7, 2023
16 changes: 16 additions & 0 deletions Braintree.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@
8053F05929FB2F700076F988 /* URL+IsPayPal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8053F05829FB2F700076F988 /* URL+IsPayPal.swift */; };
80581A8C25531D0A00006F53 /* BTConfiguration+ThreeDSecure_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80581A8B25531D0A00006F53 /* BTConfiguration+ThreeDSecure_Tests.swift */; };
80581B1D2553319C00006F53 /* BTGraphQLHTTP_SSLPinning_IntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80581B1C2553319C00006F53 /* BTGraphQLHTTP_SSLPinning_IntegrationTests.swift */; };
8064F38F2B1E492F0059C4CB /* BTShopperInsightsClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8064F38E2B1E492F0059C4CB /* BTShopperInsightsClient.swift */; };
8064F3912B1E49E10059C4CB /* BTShopperInsightsResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8064F3902B1E49E10059C4CB /* BTShopperInsightsResult.swift */; };
8064F3952B1E4FEB0059C4CB /* BTShopperInsightsClient_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8064F3942B1E4FEB0059C4CB /* BTShopperInsightsClient_Tests.swift */; };
8064F3972B1E63800059C4CB /* BTShopperInsightsRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8064F3962B1E63800059C4CB /* BTShopperInsightsRequest.swift */; };
80BA64AC29D788E000E15264 /* BTLocalPaymentResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80BA64AB29D788E000E15264 /* BTLocalPaymentResult.swift */; };
80BA64B229D7937E00E15264 /* BTLocalPaymentRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80BA64B129D7937E00E15264 /* BTLocalPaymentRequest.swift */; };
80BA64B429D795D000E15264 /* BTLocalPaymentRequestDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80BA64B329D795D000E15264 /* BTLocalPaymentRequestDelegate.swift */; };
Expand Down Expand Up @@ -699,6 +703,10 @@
80581A8B25531D0A00006F53 /* BTConfiguration+ThreeDSecure_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BTConfiguration+ThreeDSecure_Tests.swift"; sourceTree = "<group>"; };
80581B1C2553319C00006F53 /* BTGraphQLHTTP_SSLPinning_IntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTGraphQLHTTP_SSLPinning_IntegrationTests.swift; sourceTree = "<group>"; };
805FD35B2331780F0000B514 /* BTPostalAddress_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTPostalAddress_Tests.swift; sourceTree = "<group>"; };
8064F38E2B1E492F0059C4CB /* BTShopperInsightsClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTShopperInsightsClient.swift; sourceTree = "<group>"; };
8064F3902B1E49E10059C4CB /* BTShopperInsightsResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTShopperInsightsResult.swift; sourceTree = "<group>"; };
8064F3942B1E4FEB0059C4CB /* BTShopperInsightsClient_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTShopperInsightsClient_Tests.swift; sourceTree = "<group>"; };
8064F3962B1E63800059C4CB /* BTShopperInsightsRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTShopperInsightsRequest.swift; sourceTree = "<group>"; };
80A1EE3D2236AAC600F6218B /* BTThreeDSecureAdditionalInformation_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTThreeDSecureAdditionalInformation_Tests.swift; sourceTree = "<group>"; };
80B6190C28C9535F00FB5022 /* PayPalCheckout.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PayPalCheckout.xcframework; path = Frameworks/XCFrameworks/PayPalCheckout.xcframework; sourceTree = "<group>"; };
80BA64AB29D788E000E15264 /* BTLocalPaymentResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTLocalPaymentResult.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1184,6 +1192,9 @@
5708E0A728809BC6007946B9 /* BTJSONError.swift */,
570B93D82853C6180041BAFE /* BTLogLevel.swift */,
570B93D62853C29A0041BAFE /* BTLogLevelDescription.swift */,
8064F38E2B1E492F0059C4CB /* BTShopperInsightsClient.swift */,
8064F3962B1E63800059C4CB /* BTShopperInsightsRequest.swift */,
8064F3902B1E49E10059C4CB /* BTShopperInsightsResult.swift */,
BE9FB82A2898324C00D6FE2F /* BTPaymentMethodNonce.swift */,
BE9FB82C28984ADE00D6FE2F /* BTPaymentMethodNonceParser.swift */,
BE63A3A6288F3026001936DA /* BTPostalAddress.swift */,
Expand Down Expand Up @@ -1657,6 +1668,7 @@
BEBC6F272937BD1F004E25A0 /* BTGraphQLHTTP_Tests.swift */,
BE54C0322912B68E009C6CEE /* BTHTTP_Tests.swift */,
16CD2E9E1B4077FC00E68495 /* BTJSON_Tests.swift */,
8064F3942B1E4FEB0059C4CB /* BTShopperInsightsClient_Tests.swift */,
4149C91C1BA218830090665E /* BTPaymentMethodNonceParser_Tests.swift */,
805FD35B2331780F0000B514 /* BTPostalAddress_Tests.swift */,
A7E93E571B601EE900957223 /* BTURLUtils_Tests.swift */,
Expand Down Expand Up @@ -2735,12 +2747,14 @@
BEC3F11328A4401E0074DF0F /* BTHTTPError.swift in Sources */,
574891EB286F7E4F0020DA36 /* BTClientMetadataIntegration.swift in Sources */,
BE698EA428AD2C10001D9B10 /* BTCoreConstants.swift in Sources */,
8064F3912B1E49E10059C4CB /* BTShopperInsightsResult.swift in Sources */,
BE24C67528E7491E0067B11A /* BTAPIClientAuthorization.swift in Sources */,
BE32ACBC2907744400A61FED /* BTCardNetwork.swift in Sources */,
570B93D92853C6180041BAFE /* BTLogLevel.swift in Sources */,
579DAEC5286E04A700FCE87F /* BTAppContextSwitcher.swift in Sources */,
570B93D72853C29A0041BAFE /* BTLogLevelDescription.swift in Sources */,
57CBBCE828B033760037F4EE /* BTGraphQLHTTP.swift in Sources */,
8064F38F2B1E492F0059C4CB /* BTShopperInsightsClient.swift in Sources */,
BE63A3A7288F3026001936DA /* BTPostalAddress.swift in Sources */,
BE2F98D028A2BCCD008EF189 /* BTConfiguration.swift in Sources */,
BED00CB228A57AD400D74AEC /* BTClientTokenError.swift in Sources */,
Expand All @@ -2753,6 +2767,7 @@
BE698EA028AA8DCB001D9B10 /* BTHTTP.swift in Sources */,
BC17F9B428D23C5C004B18CC /* BTGraphQLMultiErrorNode.swift in Sources */,
5708E0A828809BC6007946B9 /* BTJSONError.swift in Sources */,
8064F3972B1E63800059C4CB /* BTShopperInsightsRequest.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -3035,6 +3050,7 @@
A908436324FD82C0004134CA /* BTBinData_Tests.swift in Sources */,
A908436224FD82A9004134CA /* BTAppContextSwitcher_Tests.swift in Sources */,
BEBC6F282937BD1F004E25A0 /* BTGraphQLHTTP_Tests.swift in Sources */,
8064F3952B1E4FEB0059C4CB /* BTShopperInsightsClient_Tests.swift in Sources */,
BE54C0352912B6BC009C6CEE /* BTHTTPTestProtocol.swift in Sources */,
BEDA91A028EDDE64007441D9 /* FakeAnalyticsService.swift in Sources */,
);
Expand Down
27 changes: 27 additions & 0 deletions Sources/BraintreeCore/BTShopperInsightsClient.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Foundation

/// Use `BTShopperInsightsClient` to optimize your checkout experience by prioritizing the customer’s preferred payment methods in your UI.
/// By customizing each customer’s checkout experience, you can improve conversion, increase sales/repeat buys and boost user retention/loyalty.
/// - Note: This feature is in beta. It's public API may change or be removed in future releases.
@objcMembers class BTShopperInsightsClient: NSObject {
Copy link
Contributor

Choose a reason for hiding this comment

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

Just curious about new modules supporting objective-c - is this required by project setup still or could we move to only swift classes?

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually I see now that this feature lives in core - what is the reason for not having a separate module for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These are great questions - I honestly am very down to not add Objective-C support to this feature. We could always add it later if we see demand for it. Also worth noting - this feature will go out as an "alpha" so we have the room to iterate on it, break the API, etc.

Done in 0884b78. Will loop @jaxdesmarais in on this one though to confirm.

Copy link
Contributor Author

@scannillo scannillo Dec 6, 2023

Choose a reason for hiding this comment

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

Actually I see now that this feature lives in core - what is the reason for not having a separate module for this?

We could make this a separate module. I was approaching this from a path of least resistance approach for now as we target "alpha". We might save us the headache from creating and documenting an entire new module, if the feature doesn't get adopted. And should be relatively simple to move the files into a module if we do want to go that route later on. Open to folks thoughts, though!

Copy link
Contributor

Choose a reason for hiding this comment

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

Done in 0884b78. Will loop @jaxdesmarais in on this one though to confirm.

I am totally down for this! Should we take the same approach with the Messaging module (Swift only/init first/etc)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let's do it!

Copy link
Contributor

Choose a reason for hiding this comment

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

Should we also drop the BT prefix? Or do we want to leave that consistent until v7?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Another great question - maybe let's leave the prefix until we're ready to do that overhaul holistically?

Copy link
Contributor

Choose a reason for hiding this comment

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

That makes sense to me! I agree it could be confusing to have some things prefixed and some not so the consistency would be great then we can say goodbye to it in v7. 🚀


private let apiClient: BTAPIClient

/// Creates a `BTShopperInsightsClient`
/// - Parameter apiClient: A `BTAPIClient` instance.
/// - Note: This features only works with a client token.
public init(apiClient: BTAPIClient) {
self.apiClient = apiClient
}

/// This method confirms if the customer is a user of PayPal services using their email and phone number.
/// - Parameters:
/// - request: A `BTShopperInsightsRequest` containing the buyer's user information
/// - Returns: A `BTShopperInsightsResult` instance
/// - Note: This feature is in beta. It's public API may change or be removed in future releases.
public func getRecommendedPaymentMethods(request: BTShopperInsightsRequest) async throws -> BTShopperInsightsResult {
scannillo marked this conversation as resolved.
Show resolved Hide resolved
// TODO: - Add isAppInstalled checks for PP & Venmo. DTBTSDK-3176
// TODO: - Make API call to PaymentReadyAPI. DTBTSDK-3176
return BTShopperInsightsResult()
}
}
28 changes: 28 additions & 0 deletions Sources/BraintreeCore/BTShopperInsightsRequest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Foundation

/// Buyer data required to use the Shopper Insights feature.
/// - Note: This feature is in beta. It's public API may change or be removed in future releases.
@objcMembers public class BTShopperInsightsRequest: NSObject {
scannillo marked this conversation as resolved.
Show resolved Hide resolved

/// The buyer's email address.
public let email: String

/// The buyer's country code prefix to the national telephone number. An identifier for a specific country.
scannillo marked this conversation as resolved.
Show resolved Hide resolved
/// Must not contain special characters.
public let phoneCountryCode: String

/// The buyer's national phone number. Must not contain special characters.
public let phoneNationalNumber: String
scannillo marked this conversation as resolved.
Show resolved Hide resolved

/// Initialize a `BTShopperInsightsRequest`
/// - Parameters:
/// - email: The buyer's email address.
/// - phoneCountryCode: The buyer's country code prefix to the national telephone number. An identifier for a specific country.
/// - phoneNationalNumber: The buyer's national phone number.
scannillo marked this conversation as resolved.
Show resolved Hide resolved
/// - Note: This feature is in beta. It's public API may change or be removed in future releases.
init(email: String, phoneCountryCode: String, phoneNationalNumber: String) {
self.email = email
self.phoneCountryCode = phoneCountryCode
self.phoneNationalNumber = phoneNationalNumber
scannillo marked this conversation as resolved.
Show resolved Hide resolved
}
}
12 changes: 12 additions & 0 deletions Sources/BraintreeCore/BTShopperInsightsResult.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Foundation

/// A summary of the buyer's recommended payment methods.
/// - Note: This feature is in beta. It's public API may change or be removed in future releases.
@objcMembers public class BTShopperInsightsResult: NSObject {

/// If true, display the PayPal button with high priority.
public var isPayPalRecommended = false

/// If true dislpay the Venmo button with high priority.
scannillo marked this conversation as resolved.
Show resolved Hide resolved
public var isVenmoRecommended = false
}
27 changes: 27 additions & 0 deletions UnitTests/BraintreeCoreTests/BTShopperInsightsClient_Tests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Foundation
import XCTest
@testable import BraintreeCore
@testable import BraintreeTestShared

class BTShopperInsightsClient_Tests: XCTestCase {

var mockAPIClient = MockAPIClient(authorization: "development_client_key")!
var sut: BTShopperInsightsClient!

override func setUp() {
super.setUp()
sut = BTShopperInsightsClient(apiClient: mockAPIClient)
}

func testGetRecommendedPaymentMethods_returnsDefaultRecommendations() async {
let request = BTShopperInsightsRequest(
email: "fake-email",
phoneCountryCode: "fake-country-code",
phoneNationalNumber: "fake-national-phone"
)
let result = try? await sut.getRecommendedPaymentMethods(request: request)

XCTAssertNotNil(result!.isPayPalRecommended)
XCTAssertNotNil(result!.isPayPalRecommended)
scannillo marked this conversation as resolved.
Show resolved Hide resolved
}
}