Skip to content

Commit

Permalink
Shopper insights rp2 feature presentment details (#1244)
Browse files Browse the repository at this point in the history
* Add new classes and enums

* Update new objects, introduce new method

* Use a data class instead

* Use the built in functionality to convert the treatment to a string

* Update content, update analyticsEventParam to take in a buttonType

* Use refactored sendPresentedEvent fun

* Remove comments

* Update sendPresentedEvent signature

* Remove unused methods

* Update comments button order

* Update comments for button type

* Update comments

* Update signature

* Resolve conflicts

* Update PresentmentDetails signature

* Update analyticsEvent and add button selected string name

* Add comment for shopperSessionId

* Update AnalyticsClient

* Update unit test

* Update presentment signature

* Add changelog

* Remove shopperSessionId from signature

* Remove comment

* Remove extra line

* Fix lint issues

* Newline

* Update unit test to test venmo and control type button

* Lint issues

* Update ButtonOrder

* Update keys

* PR Comments

* Analytics update

* Add accessors to enum func to get internal string value

* Use upper case notation for enums with a string representation for the page type

* Updates

* Fix unit test
  • Loading branch information
warmkesselj authored Dec 19, 2024
1 parent f93a608 commit 894fc2d
Show file tree
Hide file tree
Showing 13 changed files with 291 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ class AnalyticsClient internal constructor(
experiment = analyticsEventParams.experiment,
paymentMethodsDisplayed = analyticsEventParams.paymentMethodsDisplayed,
appSwitchUrl = analyticsEventParams.appSwitchUrl,
shopperSessionId = analyticsEventParams.shopperSessionId
shopperSessionId = analyticsEventParams.shopperSessionId,
buttonType = analyticsEventParams.buttonType,
buttonOrder = analyticsEventParams.buttonOrder,
pageType = analyticsEventParams.pageType
)
configurationLoader.loadConfiguration { result ->
if (result is ConfigurationLoaderResult.Success) {
Expand Down Expand Up @@ -244,6 +247,9 @@ class AnalyticsClient internal constructor(
event.paymentMethodsDisplayed.ifEmpty { null })
.putOpt(FPTI_KEY_URL, event.appSwitchUrl)
.putOpt(FPTI_KEY_SHOPPER_SESSION_ID, event.shopperSessionId)
.putOpt(FPTI_KEY_BUTTON_TYPE, event.buttonType)
.putOpt(FPTI_KEY_BUTTON_POSITION, event.buttonOrder)
.putOpt(FPTI_KEY_PAGE_TYPE, event.pageType)
return json.toString()
}

Expand Down Expand Up @@ -298,6 +304,9 @@ class AnalyticsClient internal constructor(
private const val FPTI_KEY_MERCHANT_PAYMENT_METHODS_DISPLAYED = "payment_methods_displayed"
private const val FPTI_KEY_URL = "url"
private const val FPTI_KEY_SHOPPER_SESSION_ID = "shopper_session_id"
private const val FPTI_KEY_BUTTON_TYPE = "button_type"
private const val FPTI_KEY_BUTTON_POSITION = "button_position"
private const val FPTI_KEY_PAGE_TYPE = "page_type"

private const val FPTI_BATCH_KEY_VENMO_INSTALLED = "venmo_installed"
private const val FPTI_BATCH_KEY_PAYPAL_INSTALLED = "paypal_installed"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,8 @@ internal data class AnalyticsEvent(
val experiment: String? = null,
val paymentMethodsDisplayed: List<String> = emptyList(),
val appSwitchUrl: String? = null,
val shopperSessionId: String? = null
val shopperSessionId: String? = null,
val buttonType: String? = null,
val buttonOrder: String? = null,
val pageType: String? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ import androidx.annotation.RestrictTo
* order of payment methods displayed to the shopper by the merchant.
* @property shopperSessionId The Shopper Insights customer session ID created by a merchant's
* server SDK or graphQL integration.
* @property buttonType buttonType Represents the tapped button type.
* @property buttonOrder The order or ranking in which payment buttons appear.
* @property pageType The page or view that a button is displayed on.
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
data class AnalyticsEventParams @JvmOverloads constructor(
Expand All @@ -31,5 +34,8 @@ data class AnalyticsEventParams @JvmOverloads constructor(
val experiment: String? = null,
val paymentMethodsDisplayed: List<String> = emptyList(),
val appSwitchUrl: String? = null,
val shopperSessionId: String? = null
val shopperSessionId: String? = null,
val buttonType: String? = null,
val buttonOrder: String? = null,
val pageType: String? = null
)
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Add `shopperSessionId` parameter to `ShopperInsightsClient`
* BraintreePayPal
* Add `shopperSessionId` to `PayPalCheckoutRequest` and `PayPalVaultRequest`
* Replace `sendPayPalPresentedEvent()` and `sendVenmoPresentedEvent()` with `sendPresentedEvent()`

## 5.3.0 (2024-12-11)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ import com.braintreepayments.api.paypal.PayPalPaymentAuthRequest
import com.braintreepayments.api.paypal.PayPalPaymentAuthResult
import com.braintreepayments.api.paypal.PayPalPendingRequest
import com.braintreepayments.api.paypal.PayPalResult
import com.braintreepayments.api.shopperinsights.ButtonOrder
import com.braintreepayments.api.shopperinsights.ButtonType
import com.braintreepayments.api.shopperinsights.ExperimentType
import com.braintreepayments.api.shopperinsights.PageType
import com.braintreepayments.api.shopperinsights.PresentmentDetails
import com.braintreepayments.api.shopperinsights.ShopperInsightsBuyerPhone
import com.braintreepayments.api.shopperinsights.ShopperInsightsClient
import com.braintreepayments.api.shopperinsights.ShopperInsightsRequest
Expand Down Expand Up @@ -193,17 +198,25 @@ class ShopperInsightsFragment : BaseFragment() {
is ShopperInsightsResult.Success -> {
if (result.response.isPayPalRecommended) {
payPalVaultButton.isEnabled = true
shopperInsightsClient.sendPayPalPresentedEvent(
"""{"exp_name":"PaymentReady","treatment_name":"control"}""",
listOf("PayPal", "Venmo", "other")
shopperInsightsClient.sendPresentedEvent(
ButtonType.PAYPAL,
PresentmentDetails(
ExperimentType.TEST,
ButtonOrder.FIRST,
PageType.HOMEPAGE
)
)
}

if (result.response.isVenmoRecommended) {
venmoButton.isEnabled = true
shopperInsightsClient.sendVenmoPresentedEvent(
"""{"exp_name":"PaymentReady","treatment_name":"test"}""",
listOf("Venmo", "PayPal", "other")
shopperInsightsClient.sendPresentedEvent(
ButtonType.VENMO,
PresentmentDetails(
ExperimentType.TEST,
ButtonOrder.OTHER,
PageType.HOMEPAGE
)
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.braintreepayments.api.shopperinsights

/**
* The order or ranking in which payment buttons appear.
*/
enum class ButtonOrder(internal val stringValue: String) {

/**
* First place
*/
FIRST("1"),

/**
* Second place
*/
SECOND("2"),

/**
* Third place
*/
THIRD("3"),

/**
* Fourth place
*/
FOURTH("4"),

/**
* Fifth place
*/
FIFTH("5"),

/**
* Sixth place
*/
SIXTH("6"),

/**
* Seventh place
*/
SEVENTH("7"),

/**
* Eighth place
*/
Eighth("8"),

/**
* Greater than Eighth place
*/
OTHER("other");

internal fun getStringRepresentation(): String {
return stringValue
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.braintreepayments.api.shopperinsights

/**
* The button type to be displayed or presented.
*/
enum class ButtonType(internal val stringValue: String) {
/**
* PayPal button
*/
PAYPAL("PayPal"),

/**
* Venmo button
*/
VENMO("Venmo"),

/**
* Other button
*/
OTHER("Other");

internal fun getStringRepresentation(): String {
return stringValue
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.braintreepayments.api.shopperinsights

/**
* An ExperimentType that is either a control or test type.
*/
enum class ExperimentType(private val rawValue: String) {
CONTROL("control"),
TEST("test");

internal fun formattedExperiment(): String {
return """
[
{ "exp_name" : "PaymentReady" }
{ "treatment_name" : $rawValue }
]
"""
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.braintreepayments.api.shopperinsights

/**
* The page or view that a button is displayed on.
*/
enum class PageType(internal val stringValue: String) {
/**
* The homepage
*/
HOMEPAGE("homepage"),

/**
* The about page
*/
ABOUT("about"),

/**
* The contact page
*/
CONTACT("contact"),

/**
* A product category page
*/
PRODUCT_CATEGORY("product_category"),

/**
* The product details page
*/
PRODUCT_DETAILS("product_details"),

/**
* The search page
*/
SEARCH("search"),

/**
* The checkout page
*/
CHECKOUT("checkout"),

/**
* The order review page
*/
ORDER_REVIEW("order_review"),

/**
* The order confirmation page
*/
ORDER_CONFIRMATION("order_confirmation"),

/**
* The mini cart
*/
MINI_CART("mini_cart"),

/**
* Some other page
*/
OTHER("other");

internal fun getStringRepresentation(): String {
return stringValue
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.braintreepayments.api.shopperinsights

/**
* Initializes a new PresentmentDetails instance
*
* @property type An ExperimentType that is either a control or test type
* @property buttonOrder optional Represents this buttons order in context of other buttons.
* @property pageType optional Represents the page or view the button is rendered on.
*/
data class PresentmentDetails(
val type: ExperimentType,
val buttonOrder: ButtonOrder,
val pageType: PageType
)
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package com.braintreepayments.api.shopperinsights

internal object ShopperInsightsAnalytics {
const val PAYPAL_PRESENTED = "shopper-insights:paypal-presented"
const val PAYPAL_SELECTED = "shopper-insights:paypal-selected"
const val VENMO_PRESENTED = "shopper-insights:venmo-presented"
const val VENMO_SELECTED = "shopper-insights:venmo-selected"
const val BUTTON_PRESENTED = "shopper-insights:button-presented"

const val GET_RECOMMENDED_PAYMENTS_FAILED = "shopper-insights:get-recommended-payments:failed"
const val GET_RECOMMENDED_PAYMENTS_STARTED = "shopper-insights:get-recommended-payments:started"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ import com.braintreepayments.api.core.DeviceInspector
import com.braintreepayments.api.core.ExperimentalBetaApi
import com.braintreepayments.api.core.MerchantRepository
import com.braintreepayments.api.core.TokenizationKey
import com.braintreepayments.api.shopperinsights.ShopperInsightsAnalytics.BUTTON_PRESENTED
import com.braintreepayments.api.shopperinsights.ShopperInsightsAnalytics.GET_RECOMMENDED_PAYMENTS_FAILED
import com.braintreepayments.api.shopperinsights.ShopperInsightsAnalytics.GET_RECOMMENDED_PAYMENTS_STARTED
import com.braintreepayments.api.shopperinsights.ShopperInsightsAnalytics.GET_RECOMMENDED_PAYMENTS_SUCCEEDED
import com.braintreepayments.api.shopperinsights.ShopperInsightsAnalytics.PAYPAL_PRESENTED
import com.braintreepayments.api.shopperinsights.ShopperInsightsAnalytics.PAYPAL_SELECTED
import com.braintreepayments.api.shopperinsights.ShopperInsightsAnalytics.VENMO_PRESENTED
import com.braintreepayments.api.shopperinsights.ShopperInsightsAnalytics.VENMO_SELECTED

/**
Expand Down Expand Up @@ -169,23 +168,24 @@ class ShopperInsightsClient internal constructor(
/**
* Call this method when the PayPal button has been successfully displayed to the buyer.
* This method sends analytics to help improve the Shopper Insights feature experience.
*
* @param experiment optional JSON string representing an experiment you want to run
* @param paymentMethodsDisplayed optional The list of available payment methods,
* rendered in the same order in which they are displayed
* @param buttonType Type of button presented - PayPal, Venmo, or Other.
* @param presentmentDetails Detailed information, including button order, experiment type,
* and page type about the payment button that is sent to analytics to help improve the Shopper
* Insights feature experience.
*/
fun sendPayPalPresentedEvent(
experiment: String? = null,
paymentMethodsDisplayed: List<String> = emptyList()
fun sendPresentedEvent(
buttonType: ButtonType,
presentmentDetails: PresentmentDetails
) {
braintreeClient.sendAnalyticsEvent(
PAYPAL_PRESENTED,
AnalyticsEventParams(
experiment = experiment,
paymentMethodsDisplayed = paymentMethodsDisplayed,
shopperSessionId = shopperSessionId
)
val params = AnalyticsEventParams(
experiment = presentmentDetails.type?.formattedExperiment(),
shopperSessionId = shopperSessionId,
buttonType = buttonType.getStringRepresentation(),
buttonOrder = presentmentDetails.buttonOrder.getStringRepresentation(),
pageType = presentmentDetails.pageType.getStringRepresentation()
)

braintreeClient.sendAnalyticsEvent(BUTTON_PRESENTED, params)
}

/**
Expand All @@ -196,28 +196,6 @@ class ShopperInsightsClient internal constructor(
braintreeClient.sendAnalyticsEvent(PAYPAL_SELECTED, analyticsParams)
}

/**
* Call this method when the Venmo button has been successfully displayed to the buyer.
* This method sends analytics to help improve the Shopper Insights feature experience.
*
* @param experiment optional JSON string representing an experiment you want to run
* @param paymentMethodsDisplayed optional The list of available payment methods,
* rendered in the same order in which they are displayed
*/
fun sendVenmoPresentedEvent(
experiment: String? = null,
paymentMethodsDisplayed: List<String> = emptyList()
) {
braintreeClient.sendAnalyticsEvent(
VENMO_PRESENTED,
AnalyticsEventParams(
experiment = experiment,
paymentMethodsDisplayed = paymentMethodsDisplayed,
shopperSessionId = shopperSessionId
)
)
}

/**
* Call this method when the Venmo button has been selected/tapped by the buyer.
* This method sends analytics to help improve the Shopper Insights feature experience.
Expand Down
Loading

0 comments on commit 894fc2d

Please sign in to comment.