From 7c34d92540940927f4998471335615a726783cb8 Mon Sep 17 00:00:00 2001 From: Isabel Martin Date: Tue, 2 Apr 2024 10:02:05 -0700 Subject: [PATCH] MBL-1278: Analytics on late pledge checkout screen (#2001) --- .../com/kickstarter/libs/AnalyticEvents.kt | 15 ++++ .../libs/utils/EventContextValues.kt | 1 + .../ui/activities/ProjectPageActivity.kt | 18 ++++- .../LatePledgeCheckoutViewModel.kt | 69 ++++++++++++++++++ .../LatePledgeCheckoutViewModelTest.kt | 73 +++++++++++++++++++ 5 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 app/src/test/java/com/kickstarter/viewmodels/LatePledgeCheckoutViewModelTest.kt diff --git a/app/src/main/java/com/kickstarter/libs/AnalyticEvents.kt b/app/src/main/java/com/kickstarter/libs/AnalyticEvents.kt index c4cd8b2974..655d487355 100644 --- a/app/src/main/java/com/kickstarter/libs/AnalyticEvents.kt +++ b/app/src/main/java/com/kickstarter/libs/AnalyticEvents.kt @@ -36,6 +36,7 @@ import com.kickstarter.libs.utils.EventContextValues.CtaContextName.COMMENT_POST import com.kickstarter.libs.utils.EventContextValues.CtaContextName.DISCOVER import com.kickstarter.libs.utils.EventContextValues.CtaContextName.DISCOVER_FILTER import com.kickstarter.libs.utils.EventContextValues.CtaContextName.DISCOVER_SORT +import com.kickstarter.libs.utils.EventContextValues.CtaContextName.LATE_PLEDGE import com.kickstarter.libs.utils.EventContextValues.CtaContextName.LOGIN_INITIATE import com.kickstarter.libs.utils.EventContextValues.CtaContextName.LOGIN_OR_SIGN_UP import com.kickstarter.libs.utils.EventContextValues.CtaContextName.LOGIN_SUBMIT @@ -412,6 +413,20 @@ class AnalyticEvents(trackingClients: List) { client.track(CTA_CLICKED.eventName, props) } + /** + * Sends data associated with the submit CTA click event to the client. + * + * @param checkoutData: The checkout data. + * @param pledgeData: The selected pledge data. + */ + fun trackLatePledgeSubmitCTA(checkoutData: CheckoutData, pledgeData: PledgeData) { + val props: HashMap = hashMapOf(CONTEXT_CTA.contextName to LATE_PLEDGE.contextName) + props[CONTEXT_TYPE.contextName] = CREDIT_CARD.contextName + props[CONTEXT_PAGE.contextName] = CHECKOUT.contextName + props.putAll(AnalyticEventsUtils.checkoutDataProperties(checkoutData, pledgeData, client.loggedInUser())) + client.track(CTA_CLICKED.eventName, props) + } + /** * Sends data associated with page view event to the client. * diff --git a/app/src/main/java/com/kickstarter/libs/utils/EventContextValues.kt b/app/src/main/java/com/kickstarter/libs/utils/EventContextValues.kt index 564b5ab8b1..1cc4db28c1 100644 --- a/app/src/main/java/com/kickstarter/libs/utils/EventContextValues.kt +++ b/app/src/main/java/com/kickstarter/libs/utils/EventContextValues.kt @@ -44,6 +44,7 @@ class EventContextValues { SIGN_UP_INITIATE("sign_up_initiate"), COMMENT_POST("comment_post"), PROJECT_SELECT("project_select"), + LATE_PLEDGE("late_pledge"), } /** diff --git a/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt b/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt index 51e087a304..b1b4674e28 100644 --- a/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt +++ b/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt @@ -608,11 +608,21 @@ class ProjectPageActivity : easing = FastOutSlowInEasing ) ) + + if (currentPage == 3) { + latePledgeCheckoutViewModel.sendPageViewedEvent( + projectData, + addOns, + currentUserShippingRule, + shippingAmount, + totalAmount, + totalBonusSupportAmount + ) + } } } var selectedReward: Reward? = null - ProjectPledgeButtonAndFragmentContainer( expanded = expanded, onContinueClicked = { checkoutFlowViewModel.onBackThisProjectClicked() }, @@ -645,6 +655,7 @@ class ProjectPageActivity : addOnsViewModel.userRewardSelection(reward) rewardsSelectionViewModel.onUserRewardSelection(reward) confirmDetailsViewModel.onUserSelectedReward(reward) + latePledgeCheckoutViewModel.userRewardSelection(reward) }, onAddOnAddedOrRemoved = { updateAddOnRewardCount -> selectedAddOnsMap[updateAddOnRewardCount.keys.first()] = @@ -677,7 +688,10 @@ class ProjectPageActivity : onBonusSupportPlusClicked = { confirmDetailsViewModel.incrementBonusSupport() }, selectedAddOnsMap = selectedAddOnsMap, onPledgeCtaClicked = { selectedCard -> - latePledgeCheckoutViewModel.onPledgeButtonClicked(selectedCard = selectedCard, project = projectData.project(), totalAmount = totalAmount) + selectedCard?.apply { + latePledgeCheckoutViewModel.sendSubmitCTAEvent(projectData, addOns, currentUserShippingRule, shippingAmount, totalAmount, totalBonusSupportAmount) + latePledgeCheckoutViewModel.onPledgeButtonClicked(selectedCard = selectedCard, project = projectData.project(), totalAmount = totalAmount) + } }, onAddPaymentMethodClicked = { latePledgeCheckoutViewModel.onAddNewCardClicked(project = projectData.project(), totalAmount = totalAmount) diff --git a/app/src/main/java/com/kickstarter/viewmodels/projectpage/LatePledgeCheckoutViewModel.kt b/app/src/main/java/com/kickstarter/viewmodels/projectpage/LatePledgeCheckoutViewModel.kt index 61dcdb1096..f8368eebce 100644 --- a/app/src/main/java/com/kickstarter/viewmodels/projectpage/LatePledgeCheckoutViewModel.kt +++ b/app/src/main/java/com/kickstarter/viewmodels/projectpage/LatePledgeCheckoutViewModel.kt @@ -5,9 +5,15 @@ import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope import com.kickstarter.libs.Environment import com.kickstarter.libs.utils.extensions.isNotNull +import com.kickstarter.models.Checkout import com.kickstarter.models.CreatePaymentIntentInput import com.kickstarter.models.Project +import com.kickstarter.models.Reward +import com.kickstarter.models.ShippingRule import com.kickstarter.models.StoredCard +import com.kickstarter.ui.data.CheckoutData +import com.kickstarter.ui.data.PledgeData +import com.kickstarter.ui.data.ProjectData import com.stripe.android.ApiResultCallback import com.stripe.android.Stripe import com.stripe.android.confirmPaymentIntent @@ -29,6 +35,7 @@ import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.coroutines.rx2.asFlow +import type.CreditCardPaymentType data class LatePledgeCheckoutUIState( val storeCards: List = listOf(), @@ -39,6 +46,7 @@ data class LatePledgeCheckoutUIState( class LatePledgeCheckoutViewModel(val environment: Environment) : ViewModel() { private val apolloClient = requireNotNull(environment.apolloClientV2()) + private val analytics = requireNotNull(environment.analytics()) private var storedCards: List = listOf() private var userEmail: String = "" @@ -50,6 +58,7 @@ class LatePledgeCheckoutViewModel(val environment: Environment) : ViewModel() { private var newStoredCard: StoredCard? = null private var errorAction: (message: String?) -> Unit = {} + private var selectedReward: Reward? = null private var mutableLatePledgeCheckoutUIState = MutableStateFlow(LatePledgeCheckoutUIState()) val latePledgeCheckoutUIState: StateFlow get() = mutableLatePledgeCheckoutUIState @@ -263,6 +272,25 @@ class LatePledgeCheckoutViewModel(val environment: Environment) : ViewModel() { }.collect() } + private fun createCheckoutData(shippingAmount: Double, total: Double, bonusAmount: Double?, checkout: Checkout? = null): CheckoutData { + return CheckoutData.builder() + .amount(total) + .id(checkout?.id()) + .paymentType(CreditCardPaymentType.CREDIT_CARD) + .bonusAmount(bonusAmount) + .shippingAmount(shippingAmount) + .build() + } + + private fun createPledgeData(projectData: ProjectData, addOns: List, shippingRule: ShippingRule, reward: Reward): PledgeData { + return PledgeData.builder() + .projectData(projectData) + .addOns(addOns) + .shippingRule(shippingRule) + .reward(reward) + .build() + } + private suspend fun emitCurrentState(isLoading: Boolean = false) { mutableLatePledgeCheckoutUIState.emit( LatePledgeCheckoutUIState( @@ -273,6 +301,47 @@ class LatePledgeCheckoutViewModel(val environment: Environment) : ViewModel() { ) } + fun sendPageViewedEvent( + projectData: ProjectData, + addOns: List, + currentUserShippingRule: ShippingRule, + shippingAmount: Double, + totalAmount: Double, + totalBonusSupportAmount: Double + ) { + this.selectedReward?.let { + val pledgeData = createPledgeData(projectData, addOns, currentUserShippingRule, it) + val checkOutData = + createCheckoutData(shippingAmount, totalAmount, totalBonusSupportAmount) + this@LatePledgeCheckoutViewModel.analytics.trackCheckoutScreenViewed( + checkoutData = checkOutData, + pledgeData = pledgeData + ) + } + } + fun sendSubmitCTAEvent( + projectData: ProjectData, + addOns: List, + currentUserShippingRule: ShippingRule, + shippingAmount: Double, + totalAmount: Double, + totalBonusSupportAmount: Double + ) { + this.selectedReward?.let { + val pledgeData = createPledgeData(projectData, addOns, currentUserShippingRule, it) + val checkOutData = + createCheckoutData(shippingAmount, totalAmount, totalBonusSupportAmount) + this@LatePledgeCheckoutViewModel.analytics.trackLatePledgeSubmitCTA( + checkoutData = checkOutData, + pledgeData = pledgeData + ) + } + } + + fun userRewardSelection(reward: Reward) { + this.selectedReward = reward + } + class Factory(private val environment: Environment) : ViewModelProvider.Factory { override fun create(modelClass: Class): T { diff --git a/app/src/test/java/com/kickstarter/viewmodels/LatePledgeCheckoutViewModelTest.kt b/app/src/test/java/com/kickstarter/viewmodels/LatePledgeCheckoutViewModelTest.kt new file mode 100644 index 0000000000..44a367e7c0 --- /dev/null +++ b/app/src/test/java/com/kickstarter/viewmodels/LatePledgeCheckoutViewModelTest.kt @@ -0,0 +1,73 @@ +package com.kickstarter.viewmodels + +import com.kickstarter.KSRobolectricTestCase +import com.kickstarter.libs.Environment +import com.kickstarter.libs.utils.EventName +import com.kickstarter.mock.factories.ProjectDataFactory +import com.kickstarter.mock.factories.ProjectFactory +import com.kickstarter.mock.factories.RewardFactory +import com.kickstarter.mock.factories.ShippingRuleFactory +import com.kickstarter.viewmodels.projectpage.LatePledgeCheckoutViewModel +import org.junit.Test + +class LatePledgeCheckoutViewModelTest : KSRobolectricTestCase() { + + private lateinit var viewModel: LatePledgeCheckoutViewModel + + private fun setUpEnvironment(environment: Environment) { + viewModel = LatePledgeCheckoutViewModel.Factory(environment).create(LatePledgeCheckoutViewModel::class.java) + } + + @Test + fun `test send PageViewed event`() { + setUpEnvironment(environment()) + + val rw = RewardFactory.rewardWithShipping() + val project = ProjectFactory.project().toBuilder().rewards(listOf(rw)).build() + val addOns = listOf(rw, rw, rw) + val rule = ShippingRuleFactory.germanyShippingRule() + val shipAmount = 3.0 + val totalAmount = 300.0 + val bonusAmount = 5.0 + + val projectData = ProjectDataFactory.project(project = project) + + viewModel.userRewardSelection(rw) + viewModel.sendPageViewedEvent( + projectData, + addOns, + rule, + shipAmount, + totalAmount, + bonusAmount + ) + + this.segmentTrack.assertValue(EventName.PAGE_VIEWED.eventName) + } + + @Test + fun `test send CTAClicked event`() { + setUpEnvironment(environment()) + + val rw = RewardFactory.rewardWithShipping() + val project = ProjectFactory.project().toBuilder().rewards(listOf(rw)).build() + val addOns = listOf(rw, rw, rw) + val rule = ShippingRuleFactory.germanyShippingRule() + val shipAmount = 3.0 + val totalAmount = 300.0 + val bonusAmount = 5.0 + + val projectData = ProjectDataFactory.project(project = project) + viewModel.userRewardSelection(rw) + viewModel.sendSubmitCTAEvent( + projectData, + addOns, + rule, + shipAmount, + totalAmount, + bonusAmount + ) + + this.segmentTrack.assertValue(EventName.CTA_CLICKED.eventName) + } +}