From 35cacbc9c0d9a47e237b1c2cc1757a5b201ddf0f Mon Sep 17 00:00:00 2001 From: Leigh Douglas Date: Fri, 6 Sep 2024 21:27:01 -0400 Subject: [PATCH] MBL-1484: PPO Analytics, and string translations ready (#2121) --- app/src/main/graphql/fragments.graphql | 4 + .../pledgedprojectsoverview/data/PPOCard.kt | 14 + .../ui/PledgedProjectsOverviewActivity.kt | 13 +- .../ui/PledgedProjectsOverviewScreen.kt | 30 ++- .../PledgedProjectsOverviewViewModel.kt | 11 +- .../com/kickstarter/libs/AnalyticEvents.kt | 118 +++++++++ .../libs/utils/AnalyticEventsUtils.kt | 26 ++ .../libs/utils/EventContextValues.kt | 10 +- .../transformers/GraphQLTransformers.kt | 2 + .../res/layout/activity_backing_details.xml | 2 +- .../discovery_drawer_logged_in_view.xml | 4 +- app/src/main/res/values/strings.xml | 12 - .../ui/PledgedProjectsOverviewScreenTest.kt | 2 +- .../PledgedProjectsOverviewViewModelTest.kt | 47 +++- .../java/com/kickstarter/libs/SegmentTest.kt | 241 ++++++++++++++++++ 15 files changed, 492 insertions(+), 44 deletions(-) diff --git a/app/src/main/graphql/fragments.graphql b/app/src/main/graphql/fragments.graphql index 83dc2d17be..15675acac5 100644 --- a/app/src/main/graphql/fragments.graphql +++ b/app/src/main/graphql/fragments.graphql @@ -392,9 +392,13 @@ fragment ppoCard on Backing { name id slug + backerSurvey { + id + } ...full creator { name + id } } } diff --git a/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/data/PPOCard.kt b/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/data/PPOCard.kt index 5f0627952b..9d165f818a 100644 --- a/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/data/PPOCard.kt +++ b/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/data/PPOCard.kt @@ -13,6 +13,7 @@ class PPOCard private constructor( val backingId: String?, val backingDetailsUrl: String?, val clientSecret: String?, + val creatorID: String?, val creatorName: String?, val currencyCode: CurrencyCode?, val currencySymbol: String?, @@ -23,6 +24,7 @@ class PPOCard private constructor( val projectName: String?, val projectSlug: String?, val timeNumberForAction: Int, + val surveyID: String?, val viewType: PPOCardViewType? ) : Parcelable { @@ -33,6 +35,8 @@ class PPOCard private constructor( fun backingDetailsUrl() = this.backingDetailsUrl fun backingId() = this.backingId fun clientSecret() = this.clientSecret + fun creatorID() = this.creatorID + fun surveyID() = this.surveyID fun creatorName() = this.creatorName fun currencyCode() = this.currencyCode fun currencySymbol() = this.currencySymbol @@ -53,6 +57,8 @@ class PPOCard private constructor( var backingDetailsUrl: String? = null, var backingId: String? = null, var clientSecret: String? = null, + var creatorID: String? = null, + var surveyID: String? = null, var creatorName: String? = null, var currencyCode: CurrencyCode? = null, var currencySymbol: String? = null, @@ -72,6 +78,8 @@ class PPOCard private constructor( fun backingDetailsUrl(backingDetailsUrl: String?) = apply { this.backingDetailsUrl = backingDetailsUrl } fun backingId(backingId: String?) = apply { this.backingId = backingId } fun clientSecret(clientSecret: String?) = apply { this.clientSecret = clientSecret } + fun creatorID(creatorName: String?) = apply { this.creatorID = creatorID } + fun surveyID(surveyID: String?) = apply { this.surveyID = surveyID } fun creatorName(creatorName: String?) = apply { this.creatorName = creatorName } fun currencyCode(currencyCode: CurrencyCode?) = apply { this.currencyCode = currencyCode } fun currencySymbol(currencySymbol: String?) = apply { this.currencySymbol = currencySymbol } @@ -91,6 +99,8 @@ class PPOCard private constructor( backingDetailsUrl = backingDetailsUrl, backingId = backingId, clientSecret = clientSecret, + creatorID = creatorID, + surveyID = surveyID, creatorName = creatorName, currencyCode = currencyCode, currencySymbol = currencySymbol, @@ -112,6 +122,8 @@ class PPOCard private constructor( backingDetailsUrl = backingDetailsUrl, backingId = backingId, clientSecret = clientSecret, + creatorID = creatorID, + surveyID = surveyID, creatorName = creatorName, currencyCode = currencyCode, currencySymbol = currencySymbol, @@ -144,6 +156,8 @@ class PPOCard private constructor( projectName() == other.projectName() && projectId() == other.projectId() && projectSlug() == other.projectSlug() && + creatorID() == other.creatorID() && + surveyID() == other.surveyID() && creatorName() == other.creatorName() && imageUrl() == other.imageUrl() && imageContentDescription() == other.imageContentDescription() && diff --git a/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewActivity.kt b/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewActivity.kt index c485479402..c017c9a48d 100644 --- a/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewActivity.kt +++ b/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewActivity.kt @@ -99,7 +99,7 @@ class PledgedProjectsOverviewActivity : AppCompatActivity() { ppoCards = ppoCardPagingSource, totalAlerts = totalAlerts, onAddressConfirmed = { addressID, backingID -> viewModel.confirmAddress(backingID = backingID, addressID = addressID) }, - onSendMessageClick = { projectName -> viewModel.onMessageCreatorClicked(projectName) }, + onSendMessageClick = { projectName, projectID, ppoCards, totalAlerts, creatorID -> viewModel.onMessageCreatorClicked(projectName = projectName, projectId = projectID, creatorID = creatorID, ppoCards = ppoCards, totalAlerts = totalAlerts) }, onProjectPledgeSummaryClick = { url -> openBackingDetailsWebView( url = env.webEndpoint() + url, @@ -116,6 +116,7 @@ class PledgedProjectsOverviewActivity : AppCompatActivity() { onPrimaryActionButtonClicked = { PPOCard -> when (PPOCard.viewType()) { PPOCardViewType.AUTHENTICATE_CARD -> { + env.analytics()?.trackPPOFixPaymentCTAClicked(PPOCard.projectId ?: "", ppoCardPagingSource.itemSnapshotList.items, totalAlerts) lifecycleScope.launch { viewModel.showLoadingState(true) } @@ -123,6 +124,7 @@ class PledgedProjectsOverviewActivity : AppCompatActivity() { } PPOCardViewType.FIX_PAYMENT -> { + env.analytics()?.trackPPOFixPaymentCTAClicked(PPOCard.projectId ?: "", ppoCardPagingSource.itemSnapshotList.items, totalAlerts) openManagePledge( PPOCard.projectSlug ?: "", resultLauncher = startForResult @@ -130,6 +132,7 @@ class PledgedProjectsOverviewActivity : AppCompatActivity() { } PPOCardViewType.OPEN_SURVEY -> { + env.analytics()?.trackPPOOpenSurveyCTAClicked(PPOCard.projectId ?: "", ppoCardPagingSource.itemSnapshotList.items, totalAlerts, PPOCard.surveyID ?: "") openBackingDetailsWebView( url = env.webEndpoint() + (PPOCard.backingDetailsUrl ?: ""), resultLauncher = startForResult @@ -137,6 +140,7 @@ class PledgedProjectsOverviewActivity : AppCompatActivity() { } PPOCardViewType.CONFIRM_ADDRESS -> { + env.analytics()?.trackPPOConfirmAddressEditCTAClicked(PPOCard.projectId ?: "", ppoCardPagingSource.itemSnapshotList.items, totalAlerts) openBackingDetailsWebView( url = env.webEndpoint() + (PPOCard.backingDetailsUrl ?: ""), resultLauncher = startForResult @@ -147,8 +151,7 @@ class PledgedProjectsOverviewActivity : AppCompatActivity() { } } }, - onSecondaryActionButtonClicked = { PPOCard -> - }, + onSecondaryActionButtonClicked = { PPOCard -> }, ) } @@ -250,12 +253,12 @@ class PledgedProjectsOverviewActivity : AppCompatActivity() { viewModel.showLoadingState(false) } if (result.outcome == StripeIntentResult.Outcome.SUCCEEDED) { - viewModel.showHeadsUpSnackbar(R.string.youve_been_authenticated_successfully_pull_to_refresh_fpo) + viewModel.showHeadsUpSnackbar(R.string.Youve_been_authenticated_successfully_pull_to_refresh) viewModel.getPledgedProjects() } else if (result.outcome == StripeIntentResult.Outcome.FAILED || result.outcome == StripeIntentResult.Outcome.TIMEDOUT || result.outcome == StripeIntentResult.Outcome.UNKNOWN - ) viewModel.showErrorSnackbar(R.string.authentication_failed_please_try_again_fpo) + ) viewModel.showErrorSnackbar(R.string.Authentication_failed_please_try_again) } override fun onError(e: Exception) { lifecycleScope.launch { diff --git a/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewScreen.kt b/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewScreen.kt index 4e2f98445e..b760b937ec 100644 --- a/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewScreen.kt +++ b/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewScreen.kt @@ -43,6 +43,7 @@ import androidx.paging.compose.collectAsLazyPagingItems import com.kickstarter.R import com.kickstarter.features.pledgedprojectsoverview.data.PPOCard import com.kickstarter.features.pledgedprojectsoverview.data.PPOCardFactory +import com.kickstarter.libs.AnalyticEvents import com.kickstarter.libs.utils.extensions.format import com.kickstarter.libs.utils.extensions.isNullOrZero import com.kickstarter.ui.compose.designsystem.KSAlertDialog @@ -80,7 +81,7 @@ private fun PledgedProjectsOverviewScreenPreview() { onSecondaryActionButtonClicked = {}, onAddressConfirmed = { backingID, addressID -> }, onProjectPledgeSummaryClick = {}, - onSendMessageClick = {}, + onSendMessageClick = { projectName, projectID, ppoCards, totalAlertsm, creatorID -> }, onSeeAllBackedProjectsClick = {}, errorSnackBarHostState = SnackbarHostState(), ) @@ -110,7 +111,7 @@ private fun PledgedProjectsOverviewScreenErrorPreview() { onSecondaryActionButtonClicked = {}, onAddressConfirmed = { backingID, addressID -> }, onProjectPledgeSummaryClick = {}, - onSendMessageClick = {}, + onSendMessageClick = { projectName, projectID, ppoCards, totalAlerts, creatorID -> }, onSeeAllBackedProjectsClick = {}, isErrored = true, errorSnackBarHostState = SnackbarHostState(), @@ -138,9 +139,9 @@ private fun PledgedProjectsOverviewScreenEmptyPreview() { onSecondaryActionButtonClicked = {}, onAddressConfirmed = { backingID, addressID -> }, onProjectPledgeSummaryClick = {}, - onSendMessageClick = {}, + onSendMessageClick = { projectName, projectID, ppoCards, totalAlerts, creatorID -> }, errorSnackBarHostState = SnackbarHostState(), - onSeeAllBackedProjectsClick = {}, + onSeeAllBackedProjectsClick = {} ) } } @@ -157,7 +158,7 @@ fun PledgedProjectsOverviewScreen( ppoCards: LazyPagingItems, totalAlerts: Int = 0, onProjectPledgeSummaryClick: (backingDetailsUrl: String) -> Unit, - onSendMessageClick: (projectName: String) -> Unit, + onSendMessageClick: (projectName: String, projectID: String, ppoCards: List, totalAlerts: Int, creatorID: String) -> Unit, onSeeAllBackedProjectsClick: () -> Unit, onPrimaryActionButtonClicked: (PPOCard) -> Unit, onSecondaryActionButtonClicked: (PPOCard) -> Unit, @@ -165,11 +166,13 @@ fun PledgedProjectsOverviewScreen( isErrored: Boolean = false, showEmptyState: Boolean = false, pullRefreshCallback: () -> Unit = {}, + analyticEvents: AnalyticEvents? = null, ) { val openConfirmAddressAlertDialog = remember { mutableStateOf(false) } var confirmedAddress by remember { mutableStateOf("") } // TODO: This is either the original shipping address or the user-edited address var addressID by remember { mutableStateOf("") } var backingID by remember { mutableStateOf("") } + var projectID by remember { mutableStateOf("") } val pullRefreshState = rememberPullRefreshState( isLoading, pullRefreshCallback, @@ -199,7 +202,7 @@ fun PledgedProjectsOverviewScreen( modifier = modifier, topBar = { TopToolBar( - title = stringResource(id = R.string.project_alerts_fpo), + title = stringResource(id = R.string.Project_alerts), titleColor = colors.textPrimary, leftOnClickAction = onBackPressed, leftIconColor = colors.icon, @@ -229,7 +232,7 @@ fun PledgedProjectsOverviewScreen( item { if (!totalAlerts.isNullOrZero()) { Text( - text = stringResource(id = R.string.alerts_fpo).format("count", totalAlerts.toString()), + text = stringResource(id = R.string.Alerts_count).format("count", totalAlerts.toString()), style = typography.title3Bold, color = colors.textPrimary ) @@ -252,7 +255,7 @@ fun PledgedProjectsOverviewScreen( flags = it.flags, imageContentDescription = it.imageContentDescription(), creatorName = it.creatorName(), - sendAMessageClickAction = { onSendMessageClick(it.projectSlug() ?: "") }, + sendAMessageClickAction = { onSendMessageClick(it.projectSlug() ?: "", it.projectId ?: "", ppoCards.itemSnapshotList.toList(), totalAlerts, it.creatorID() ?: "") }, shippingAddress = it.address() ?: "", // TODO replace with formatted address from PPO response onActionButtonClicked = { onPrimaryActionButtonClicked(it) @@ -260,9 +263,11 @@ fun PledgedProjectsOverviewScreen( onSecondaryActionButtonClicked = { when (it.viewType()) { PPOCardViewType.CONFIRM_ADDRESS -> { + analyticEvents?.trackPPOConfirmAddressInitiateCTAClicked(projectID = it.projectId ?: "", ppoCards.itemSnapshotList.items, totalAlerts) confirmedAddress = it.address() ?: "" addressID = it.addressID ?: "" backingID = it.backingId ?: "" + projectID = it.projectId ?: "" openConfirmAddressAlertDialog.value = true } else -> { @@ -304,6 +309,7 @@ fun PledgedProjectsOverviewScreen( rightButtonText = stringResource(id = R.string.Confirm), rightButtonAction = { openConfirmAddressAlertDialog.value = false + analyticEvents?.trackPPOConfirmAddressSubmitCTAClicked(ppoCards = ppoCards.itemSnapshotList.items, projectID = projectID, totalCount = totalAlerts) onAddressConfirmed(addressID, backingID) } ) @@ -330,7 +336,7 @@ fun PPOScreenEmptyState( ) { Text( color = colors.textPrimary, - text = stringResource(id = R.string.youre_all_caught_up_fpo), + text = stringResource(id = R.string.Youre_all_caught_up), style = typography.title3Bold, ) @@ -338,7 +344,7 @@ fun PPOScreenEmptyState( Text( color = colors.textPrimary, - text = stringResource(id = R.string.when_projects_youve_backed_need_your_attention_youll_see_them_here_fpo), + text = stringResource(id = R.string.When_projects_youve_backed_need_your_attention_youll_see_them_here), style = typography.body, textAlign = TextAlign.Center ) @@ -347,7 +353,7 @@ fun PPOScreenEmptyState( KSPrimaryGreenButton( modifier = Modifier, onClickAction = { onSeeAllBackedProjectsClick.invoke() }, - text = stringResource(id = R.string.see_all_backed__projects_fpo), + text = stringResource(id = R.string.See_all_backed__projects), isEnabled = true ) } @@ -377,7 +383,7 @@ fun PPOScreenErrorState() { Text( color = colors.textPrimary, - text = (stringResource(id = R.string.something_went_wrong_pull_to_refresh_fpo)), + text = (stringResource(id = R.string.Something_went_wrong_pull_to_refresh_no_period)), style = typography.body, textAlign = TextAlign.Center ) diff --git a/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/viewmodel/PledgedProjectsOverviewViewModel.kt b/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/viewmodel/PledgedProjectsOverviewViewModel.kt index fc5f8fdb5e..7dca0e7da8 100644 --- a/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/viewmodel/PledgedProjectsOverviewViewModel.kt +++ b/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/viewmodel/PledgedProjectsOverviewViewModel.kt @@ -11,6 +11,7 @@ import androidx.paging.PagingState import com.kickstarter.R import com.kickstarter.features.pledgedprojectsoverview.data.PPOCard import com.kickstarter.features.pledgedprojectsoverview.data.PledgedProjectsOverviewQueryData +import com.kickstarter.libs.AnalyticEvents import com.kickstarter.libs.Environment import com.kickstarter.libs.utils.extensions.isTrue import com.kickstarter.models.Project @@ -41,6 +42,7 @@ import kotlinx.coroutines.rx2.asFlow private val PAGE_LIMIT = 25 class PledgedProjectsPagingSource( private val apolloClient: ApolloClientTypeV2, + private val analyticEvents: AnalyticEvents, private var totalAlerts: MutableStateFlow, private val limit: Int = PAGE_LIMIT, @@ -65,6 +67,7 @@ class PledgedProjectsPagingSource( } .collect { envelope -> totalAlerts.emit(envelope.totalCount ?: 0) + analyticEvents.trackPledgedProjectsOverviewPageViewed(envelope.pledges() ?: emptyList(), envelope.totalCount() ?: 0) ppoCardsList = envelope.pledges() ?: emptyList() nextPageEnvelope = if (envelope.pageInfoEnvelope?.hasNextPage == true) envelope.pageInfoEnvelope else null result = LoadResult.Page( @@ -93,6 +96,7 @@ class PledgedProjectsOverviewViewModel( private var mutableProjectFlow = MutableSharedFlow() private var snackbarMessage: (stringID: Int, type: String) -> Unit = { _, _ -> } private val apolloClient = requireNotNull(environment.apolloClientV2()) + private val analyticEvents = requireNotNull(environment.analytics()) private val mutableTotalAlerts = MutableStateFlow(0) val totalAlertsState = mutableTotalAlerts.asStateFlow() @@ -104,7 +108,7 @@ class PledgedProjectsOverviewViewModel( val paymentRequiresAction: SharedFlow get() = mutablePaymentRequiresAction.asSharedFlow() - private var pagingSource = PledgedProjectsPagingSource(apolloClient, mutableTotalAlerts, PAGE_LIMIT) + private var pagingSource = PledgedProjectsPagingSource(apolloClient = apolloClient, analyticEvents = analyticEvents, totalAlerts = mutableTotalAlerts, limit = PAGE_LIMIT) val ppoUIState: StateFlow get() = mutablePPOUIState @@ -165,7 +169,7 @@ class PledgedProjectsOverviewViewModel( emitCurrentState(isLoading = true) }.map { if (it.isTrue()) { - showHeadsUpSnackbar(R.string.address_confirmed_snackbar_text_fpo) + showHeadsUpSnackbar(R.string.Address_confirmed_need_to_change_your_address_before_it_locks) getPledgedProjects() } else { showErrorSnackbar(R.string.Something_went_wrong_please_try_again) @@ -178,8 +182,9 @@ class PledgedProjectsOverviewViewModel( } } - fun onMessageCreatorClicked(projectName: String) { + fun onMessageCreatorClicked(projectName: String, projectId: String, creatorID: String, ppoCards: List, totalAlerts: Int) { viewModelScope.launch(ioDispatcher) { + analyticEvents.trackPPOMessageCreatorCTAClicked(projectID = projectId, ppoCards = ppoCards, totalCount = totalAlerts, creatorID = creatorID) apolloClient.getProject( slug = projectName, ) diff --git a/app/src/main/java/com/kickstarter/libs/AnalyticEvents.kt b/app/src/main/java/com/kickstarter/libs/AnalyticEvents.kt index 655d487355..dfd44c4da8 100644 --- a/app/src/main/java/com/kickstarter/libs/AnalyticEvents.kt +++ b/app/src/main/java/com/kickstarter/libs/AnalyticEvents.kt @@ -1,5 +1,6 @@ package com.kickstarter.libs +import com.kickstarter.features.pledgedprojectsoverview.data.PPOCard import com.kickstarter.libs.utils.AnalyticEventsUtils import com.kickstarter.libs.utils.ContextPropertyKeyName.COMMENT_BODY import com.kickstarter.libs.utils.ContextPropertyKeyName.COMMENT_CHARACTER_COUNT @@ -20,11 +21,13 @@ import com.kickstarter.libs.utils.EventContextValues.ContextPageName.LOGIN import com.kickstarter.libs.utils.EventContextValues.ContextPageName.LOGIN_SIGN_UP import com.kickstarter.libs.utils.EventContextValues.ContextPageName.MANAGE_PLEDGE import com.kickstarter.libs.utils.EventContextValues.ContextPageName.PROJECT +import com.kickstarter.libs.utils.EventContextValues.ContextPageName.PROJECT_ALERTS import com.kickstarter.libs.utils.EventContextValues.ContextPageName.REWARDS import com.kickstarter.libs.utils.EventContextValues.ContextPageName.SIGN_UP import com.kickstarter.libs.utils.EventContextValues.ContextPageName.THANKS import com.kickstarter.libs.utils.EventContextValues.ContextPageName.TWO_FACTOR_AUTH import com.kickstarter.libs.utils.EventContextValues.ContextPageName.UPDATE_PLEDGE +import com.kickstarter.libs.utils.EventContextValues.ContextTypeName.ADDRESS import com.kickstarter.libs.utils.EventContextValues.ContextTypeName.CREDIT_CARD import com.kickstarter.libs.utils.EventContextValues.ContextTypeName.REPLY import com.kickstarter.libs.utils.EventContextValues.ContextTypeName.ROOT @@ -33,13 +36,18 @@ import com.kickstarter.libs.utils.EventContextValues.ContextTypeName.WATCH import com.kickstarter.libs.utils.EventContextValues.CtaContextName.ADD_ONS_CONTINUE import com.kickstarter.libs.utils.EventContextValues.CtaContextName.CAMPAIGN_DETAILS import com.kickstarter.libs.utils.EventContextValues.CtaContextName.COMMENT_POST +import com.kickstarter.libs.utils.EventContextValues.CtaContextName.CONFIRM_INITIATE +import com.kickstarter.libs.utils.EventContextValues.CtaContextName.CONFIRM_SUBMIT 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.EDIT +import com.kickstarter.libs.utils.EventContextValues.CtaContextName.FIX_PLEDGE_INITIATE 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 +import com.kickstarter.libs.utils.EventContextValues.CtaContextName.MESSAGE_CREATOR_INITIATE import com.kickstarter.libs.utils.EventContextValues.CtaContextName.PLEDGE_CONFIRM import com.kickstarter.libs.utils.EventContextValues.CtaContextName.PLEDGE_INITIATE import com.kickstarter.libs.utils.EventContextValues.CtaContextName.PLEDGE_SUBMIT @@ -47,6 +55,7 @@ import com.kickstarter.libs.utils.EventContextValues.CtaContextName.REWARD_CONTI import com.kickstarter.libs.utils.EventContextValues.CtaContextName.SEARCH import com.kickstarter.libs.utils.EventContextValues.CtaContextName.SIGN_UP_INITIATE import com.kickstarter.libs.utils.EventContextValues.CtaContextName.SIGN_UP_SUBMIT +import com.kickstarter.libs.utils.EventContextValues.CtaContextName.SURVEY_RESPONSE_INITIATE import com.kickstarter.libs.utils.EventContextValues.CtaContextName.WATCH_PROJECT import com.kickstarter.libs.utils.EventContextValues.DiscoveryContextType.ALL import com.kickstarter.libs.utils.EventContextValues.DiscoveryContextType.CATEGORY_NAME @@ -258,6 +267,115 @@ class AnalyticEvents(trackingClients: List) { client.track(PAGE_VIEWED.eventName, props) } + /** + * Sends data to the client when pledged project overview screen is viewed + * + * @param ppoCards: The list of alerts. + * @param totalCount: The total number of alerts. + */ + fun trackPledgedProjectsOverviewPageViewed(ppoCards: List, totalCount: Int) { + val props = AnalyticEventsUtils.notificationProperties(ppoCards, totalCount).toMutableMap() + props[CONTEXT_PAGE.contextName] = PROJECT_ALERTS.contextName + client.track(PAGE_VIEWED.eventName, props) + } + + /** + * Sends data to the client when message creator is tapped on a ppo card + * + * @param projectID: The id of the project. + * @param creatorID: The id of the creator. + * @param ppoCards: The list of alerts. + * @param totalCount: The total number of alerts. + */ + fun trackPPOMessageCreatorCTAClicked(projectID: String, ppoCards: List, totalCount: Int, creatorID: String) { + val props = AnalyticEventsUtils.notificationProperties(ppoCards, totalCount).toMutableMap() + props["interaction_target_id"] = creatorID + props["project_pid"] = projectID + props[CONTEXT_PAGE.contextName] = PROJECT_ALERTS.contextName + props[CONTEXT_CTA.contextName] = MESSAGE_CREATOR_INITIATE.contextName + client.track(CTA_CLICKED.eventName, props) + } + + /** + * Sends data to the client when fix payment is tapped on a fix payment ppo card + * + * @param projectID: The id of the project. + * @param ppoCards: The list of alerts. + * @param totalCount: The total number of alerts. + */ + fun trackPPOFixPaymentCTAClicked(projectID: String, ppoCards: List, totalCount: Int) { + val props = AnalyticEventsUtils.notificationProperties(ppoCards, totalCount).toMutableMap() + props["project_pid"] = projectID + props[CONTEXT_PAGE.contextName] = PROJECT_ALERTS.contextName + props[CONTEXT_CTA.contextName] = FIX_PLEDGE_INITIATE.contextName + client.track(CTA_CLICKED.eventName, props) + } + + /** + * Sends data to the client when open survey is tapped on open survey ppo card + * + * @param projectID: The id of the project. + * @param ppoCards: The list of alerts. + * @param totalCount: The total number of alerts. + * @param surveyID: The id of the survey. + */ + fun trackPPOOpenSurveyCTAClicked(projectID: String, ppoCards: List, totalCount: Int, surveyID: String) { + val props = AnalyticEventsUtils.notificationProperties(ppoCards, totalCount).toMutableMap() + props["project_pid"] = projectID + props["survey_id"] = surveyID + props[CONTEXT_PAGE.contextName] = PROJECT_ALERTS.contextName + props[CONTEXT_CTA.contextName] = SURVEY_RESPONSE_INITIATE.contextName + client.track(CTA_CLICKED.eventName, props) + } + + /** + * Sends data to the client when confirm address is initiated on a confirm address ppo card + * + * @param projectID: The id of the project. + * @param ppoCards: The list of alerts. + * @param totalCount: The total number of alerts. + */ + fun trackPPOConfirmAddressInitiateCTAClicked(projectID: String, ppoCards: List, totalCount: Int) { + val props = AnalyticEventsUtils.notificationProperties(ppoCards, totalCount).toMutableMap() + props["project_pid"] = projectID + props[CONTEXT_PAGE.contextName] = PROJECT_ALERTS.contextName + props[CONTEXT_CTA.contextName] = CONFIRM_INITIATE.contextName + props[CONTEXT_TYPE.contextName] = ADDRESS.contextName + client.track(CTA_CLICKED.eventName, props) + } + + /** + * Sends data to the client when confirm address is submitted on a confirm address ppo card dialog box + * + * @param projectID: The id of the project. + * @param ppoCards: The list of alerts. + * @param totalCount: The total number of alerts. + */ + fun trackPPOConfirmAddressSubmitCTAClicked(projectID: String, ppoCards: List, totalCount: Int) { + val props = AnalyticEventsUtils.notificationProperties(ppoCards, totalCount).toMutableMap() + props["project_pid"] = projectID + props[CONTEXT_PAGE.contextName] = PROJECT_ALERTS.contextName + props[CONTEXT_CTA.contextName] = CONFIRM_SUBMIT.contextName + props[CONTEXT_TYPE.contextName] = ADDRESS.contextName + client.track(CTA_CLICKED.eventName, props) + } + + /** + * Sends data to the client when edit on confirm address card is tapped + * + * @param projectID: The id of the project. + * @param ppoCards: The list of alerts. + * @param totalCount: The total number of alerts. + */ + fun trackPPOConfirmAddressEditCTAClicked(projectID: String, ppoCards: List, totalCount: Int) { + val props = AnalyticEventsUtils.notificationProperties(ppoCards, totalCount).toMutableMap() + props["project_pid"] = projectID + props[CONTEXT_PAGE.contextName] = PROJECT_ALERTS.contextName + props[CONTEXT_CTA.contextName] = EDIT.contextName + props[CONTEXT_TYPE.contextName] = ADDRESS.contextName + client.track(CTA_CLICKED.eventName, props) + } + /** * Sends data to the client when items in the discovery overflow menu are tapped. * diff --git a/app/src/main/java/com/kickstarter/libs/utils/AnalyticEventsUtils.kt b/app/src/main/java/com/kickstarter/libs/utils/AnalyticEventsUtils.kt index d5b599d6f7..4a583345a7 100644 --- a/app/src/main/java/com/kickstarter/libs/utils/AnalyticEventsUtils.kt +++ b/app/src/main/java/com/kickstarter/libs/utils/AnalyticEventsUtils.kt @@ -1,5 +1,7 @@ package com.kickstarter.libs.utils +import com.kickstarter.features.pledgedprojectsoverview.data.PPOCard +import com.kickstarter.features.pledgedprojectsoverview.ui.PPOCardViewType import com.kickstarter.libs.RefTag import com.kickstarter.libs.utils.EventContextValues.VideoContextName.LENGTH import com.kickstarter.libs.utils.EventContextValues.VideoContextName.POSITION @@ -321,4 +323,28 @@ object AnalyticEventsUtils { properties.putAll(projectProperties(project, loggedInUser)) return properties } + + @JvmOverloads + fun notificationProperties(ppoCards: List, totalCount: Int, prefix: String = "notification_count_"): Map { + val props = HashMap().apply { + put("address_locks_soon", 0) + put("survey_available", 0) + put("card_auth_required", 0) + put("payment_failed", 0) + put("total", totalCount) + } + + for (card in ppoCards) { + when (card?.viewType()) { + PPOCardViewType.FIX_PAYMENT -> props["payment_failed"] = (props["payment_failed"] ?: 0).plus(1) + PPOCardViewType.AUTHENTICATE_CARD -> props["card_auth_required"] = (props["card_auth_required"] ?: 0).plus(1) + PPOCardViewType.OPEN_SURVEY -> props["survey_available"] = (props["survey_available"] ?: 0).plus(1) + PPOCardViewType.CONFIRM_ADDRESS -> props["address_locks_soon"] = (props["address_locks_soon"] ?: 0).plus(1) + else -> {} + } + } + + val properties = MapUtils.prefixKeys(props, prefix) + return properties + } } 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 1cc4db28c1..3150b59370 100644 --- a/app/src/main/java/com/kickstarter/libs/utils/EventContextValues.kt +++ b/app/src/main/java/com/kickstarter/libs/utils/EventContextValues.kt @@ -36,6 +36,11 @@ class EventContextValues { DISCOVER("discover"), WATCH_PROJECT("watch_project"), LOGIN_INITIATE("log_in_initiate"), + MESSAGE_CREATOR_INITIATE("message_creator_initiate"), + FIX_PLEDGE_INITIATE("fix_pledge_initiate"), + SURVEY_RESPONSE_INITIATE("survey_response_initiate"), + CONFIRM_INITIATE("confirm_initiate"), + CONFIRM_SUBMIT("confirm_submit"), CAMPAIGN_DETAILS("campaign_details"), CREATOR_DETAILS("creator_details"), LOGIN_OR_SIGN_UP("log_in_or_sign_up"), @@ -45,6 +50,7 @@ class EventContextValues { COMMENT_POST("comment_post"), PROJECT_SELECT("project_select"), LATE_PLEDGE("late_pledge"), + EDIT("edit"), } /** @@ -83,6 +89,7 @@ class EventContextValues { UPDATE_PLEDGE("update_pledge"), LOGIN("log_in"), MANAGE_PLEDGE("manage_pledge"), + PROJECT_ALERTS("project_alerts"), TWO_FACTOR_AUTH("two_factor_auth") } @@ -170,7 +177,8 @@ class EventContextValues { FACEBOOK("facebook"), RESULTS("results"), ROOT("root"), - REPLY("reply") + REPLY("reply"), + ADDRESS("address") } /** diff --git a/app/src/main/java/com/kickstarter/services/transformers/GraphQLTransformers.kt b/app/src/main/java/com/kickstarter/services/transformers/GraphQLTransformers.kt index 2b26d8fc81..a49a06420d 100644 --- a/app/src/main/java/com/kickstarter/services/transformers/GraphQLTransformers.kt +++ b/app/src/main/java/com/kickstarter/services/transformers/GraphQLTransformers.kt @@ -948,7 +948,9 @@ fun pledgedProjectsOverviewEnvelopeTransformer(ppoResponse: PledgedProjectsOverv .projectSlug(ppoBackingData?.project()?.slug()) .imageUrl(ppoBackingData?.project()?.fragments()?.full()?.image()?.url()) .creatorName(ppoBackingData?.project()?.creator()?.name()) + .creatorID(ppoBackingData?.project()?.creator()?.id()) .viewType(getTierType(it.node()?.tierType())) + .surveyID(ppoBackingData?.project()?.backerSurvey()?.id()) .flags(flags) .addressID(ppoBackingData?.deliveryAddress()?.id()) .build() diff --git a/app/src/main/res/layout/activity_backing_details.xml b/app/src/main/res/layout/activity_backing_details.xml index ffe4f438f9..5f53e79a9b 100644 --- a/app/src/main/res/layout/activity_backing_details.xml +++ b/app/src/main/res/layout/activity_backing_details.xml @@ -28,7 +28,7 @@ + android:text="@string/Backing_details" /> diff --git a/app/src/main/res/layout/discovery_drawer_logged_in_view.xml b/app/src/main/res/layout/discovery_drawer_logged_in_view.xml index 1801590459..9356851cf8 100644 --- a/app/src/main/res/layout/discovery_drawer_logged_in_view.xml +++ b/app/src/main/res/layout/discovery_drawer_logged_in_view.xml @@ -95,7 +95,7 @@ style="@style/DrawerTextViewWithCount" android:layout_width="0dp" android:layout_height="wrap_content" - android:text="@string/project_alerts_fpo" + android:text="@string/Project_alerts" android:layout_weight="1" app:drawableStartCompat="@drawable/ic_notification_bell" /> @@ -106,7 +106,7 @@ android:layout_gravity="center" android:layout_width="@dimen/grid_1" android:layout_height="@dimen/grid_1" - android:contentDescription="@string/project_alerts_fpo" + android:contentDescription="@string/Project_alerts" android:visibility="gone"/> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 65687f29a3..585cdf36f2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -99,16 +99,4 @@ This project was successfully funded on %{deadline}, but you can still pledge for available rewards. - - See all backed projects - You\'re all caught up! - When projects you\'ve backed need your attention, you\'ll see them here. - Project Alerts - Alerts (%{count}) - Address confirmed! Need to change your address before it locks? Visit your backing details on our website. - Backing details - Something went wrong - Pull to refresh - You\'ve been authenticated successfully! Pull to refresh. - Authentication success. Please pull to refresh. - Authentication failed. Please try again. diff --git a/app/src/test/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewScreenTest.kt b/app/src/test/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewScreenTest.kt index c75ac148f0..7dabb47732 100644 --- a/app/src/test/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewScreenTest.kt +++ b/app/src/test/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewScreenTest.kt @@ -34,7 +34,7 @@ PledgedProjectsOverviewScreenTest : KSRobolectricTestCase() { lazyColumnListState = rememberLazyListState(), ppoCards = ppoCardPagingList, errorSnackBarHostState = SnackbarHostState(), - onSendMessageClick = {}, + onSendMessageClick = { projectName, projectID, ppoCards, totalAlerts, creatorID -> }, onAddressConfirmed = { backingID, addressID -> }, onProjectPledgeSummaryClick = {}, onSeeAllBackedProjectsClick = {}, diff --git a/app/src/test/java/com/kickstarter/features/pledgedprojectsoverview/viewmodel/PledgedProjectsOverviewViewModelTest.kt b/app/src/test/java/com/kickstarter/features/pledgedprojectsoverview/viewmodel/PledgedProjectsOverviewViewModelTest.kt index 7958718a95..6a064efc74 100644 --- a/app/src/test/java/com/kickstarter/features/pledgedprojectsoverview/viewmodel/PledgedProjectsOverviewViewModelTest.kt +++ b/app/src/test/java/com/kickstarter/features/pledgedprojectsoverview/viewmodel/PledgedProjectsOverviewViewModelTest.kt @@ -8,7 +8,15 @@ import com.kickstarter.R import com.kickstarter.features.pledgedprojectsoverview.data.PPOCardFactory import com.kickstarter.features.pledgedprojectsoverview.data.PledgedProjectsOverviewEnvelope import com.kickstarter.features.pledgedprojectsoverview.data.PledgedProjectsOverviewQueryData +import com.kickstarter.libs.AnalyticEvents +import com.kickstarter.libs.MockCurrentUser +import com.kickstarter.libs.MockTrackingClient +import com.kickstarter.libs.TrackingClientType +import com.kickstarter.libs.utils.EventName +import com.kickstarter.mock.MockCurrentConfig +import com.kickstarter.mock.MockFeatureFlagClient import com.kickstarter.mock.factories.ProjectFactory +import com.kickstarter.mock.factories.UserFactory import com.kickstarter.mock.services.MockApolloClientV2 import com.kickstarter.models.Project import com.kickstarter.services.mutations.CreateOrUpdateBackingAddressData @@ -20,6 +28,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Test +import rx.observers.TestSubscriber @OptIn(ExperimentalCoroutinesApi::class) class PledgedProjectsOverviewViewModelTest : KSRobolectricTestCase() { @@ -28,7 +37,6 @@ class PledgedProjectsOverviewViewModelTest : KSRobolectricTestCase() { fun `emits project when message creator called`() = runTest { val projectState = mutableListOf() - val project = ProjectFactory.successfulProject() val viewModel = PledgedProjectsOverviewViewModel.Factory( ioDispatcher = UnconfinedTestDispatcher(testScheduler), @@ -37,18 +45,22 @@ class PledgedProjectsOverviewViewModelTest : KSRobolectricTestCase() { override fun getProject(slug: String): Observable { return Observable.just(project) } - }).build() + }) + .build() ).create(PledgedProjectsOverviewViewModel::class.java) backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) { viewModel.projectFlow.toList(projectState) } - viewModel.onMessageCreatorClicked("test_project_slug") + + viewModel.onMessageCreatorClicked("test_project_slug", "projectID", "creatorID", listOf(PPOCardFactory.confirmAddressCard()), 10) assertEquals( projectState.last(), project ) + + segmentTrack.assertValue(EventName.CTA_CLICKED.eventName) } @Test @@ -66,7 +78,7 @@ class PledgedProjectsOverviewViewModelTest : KSRobolectricTestCase() { ).create(PledgedProjectsOverviewViewModel::class.java) viewModel.provideSnackbarMessage { message, _ -> snackbarAction = message } - viewModel.onMessageCreatorClicked("test_project_slug") + viewModel.onMessageCreatorClicked("test_project_slug", "projectID", "creatorID", listOf(PPOCardFactory.confirmAddressCard()), 10) // Should equal error string id assertEquals( @@ -171,7 +183,7 @@ class PledgedProjectsOverviewViewModelTest : KSRobolectricTestCase() { assertEquals( snackbarAction, - R.string.address_confirmed_snackbar_text_fpo + R.string.Address_confirmed_need_to_change_your_address_before_it_locks ) assertEquals( @@ -190,6 +202,13 @@ class PledgedProjectsOverviewViewModelTest : KSRobolectricTestCase() { fun `pager result is errored when network response is errored`() { runTest { val mutableTotalAlerts = MutableStateFlow(0) + val user = UserFactory.user() + val trackingClient = MockTrackingClient( + MockCurrentUser(user), + MockCurrentConfig(), + TrackingClientType.Type.SEGMENT, + MockFeatureFlagClient() + ) val mockApolloClientV2 = object : MockApolloClientV2() { @@ -199,6 +218,7 @@ class PledgedProjectsOverviewViewModelTest : KSRobolectricTestCase() { } val pagingSource = PledgedProjectsPagingSource( mockApolloClientV2, + AnalyticEvents(listOf(trackingClient)), mutableTotalAlerts ) @@ -224,7 +244,13 @@ class PledgedProjectsOverviewViewModelTest : KSRobolectricTestCase() { runTest { val mutableTotalAlerts = MutableStateFlow(0) val totalAlertsList = mutableListOf() - + val user = UserFactory.user() + val trackingClient = MockTrackingClient( + MockCurrentUser(user), + MockCurrentConfig(), + TrackingClientType.Type.SEGMENT, + MockFeatureFlagClient() + ) val mockApolloClientV2 = object : MockApolloClientV2() { override fun getPledgedProjectsOverviewPledges(inputData: PledgedProjectsOverviewQueryData): Observable { @@ -234,9 +260,14 @@ class PledgedProjectsOverviewViewModelTest : KSRobolectricTestCase() { ) } } + + val segmentTrack: TestSubscriber = TestSubscriber() + trackingClient.eventNames.subscribe(segmentTrack) + val pagingSource = PledgedProjectsPagingSource( mockApolloClientV2, - mutableTotalAlerts + AnalyticEvents(listOf(trackingClient)), + mutableTotalAlerts, ) var viewModel = PledgedProjectsOverviewViewModel.Factory( @@ -269,6 +300,8 @@ class PledgedProjectsOverviewViewModelTest : KSRobolectricTestCase() { totalAlertsList, listOf(0, 10) ) + + segmentTrack.assertValue(EventName.PAGE_VIEWED.eventName) } } diff --git a/app/src/test/java/com/kickstarter/libs/SegmentTest.kt b/app/src/test/java/com/kickstarter/libs/SegmentTest.kt index d847db3a85..ee495fef33 100644 --- a/app/src/test/java/com/kickstarter/libs/SegmentTest.kt +++ b/app/src/test/java/com/kickstarter/libs/SegmentTest.kt @@ -3,6 +3,7 @@ package com.kickstarter.libs import android.content.Context import android.content.SharedPreferences import com.kickstarter.KSRobolectricTestCase +import com.kickstarter.features.pledgedprojectsoverview.data.PPOCardFactory import com.kickstarter.libs.featureflag.FeatureFlagClientType import com.kickstarter.libs.featureflag.FlagKey import com.kickstarter.libs.utils.ContextPropertyKeyName @@ -19,14 +20,22 @@ import com.kickstarter.libs.utils.EventContextValues.ContextPageName.LOGIN import com.kickstarter.libs.utils.EventContextValues.ContextPageName.LOGIN_SIGN_UP import com.kickstarter.libs.utils.EventContextValues.ContextPageName.MANAGE_PLEDGE import com.kickstarter.libs.utils.EventContextValues.ContextPageName.PROJECT +import com.kickstarter.libs.utils.EventContextValues.ContextPageName.PROJECT_ALERTS import com.kickstarter.libs.utils.EventContextValues.ContextPageName.SIGN_UP import com.kickstarter.libs.utils.EventContextValues.ContextPageName.THANKS import com.kickstarter.libs.utils.EventContextValues.ContextPageName.TWO_FACTOR_AUTH +import com.kickstarter.libs.utils.EventContextValues.ContextTypeName.ADDRESS +import com.kickstarter.libs.utils.EventContextValues.CtaContextName.CONFIRM_INITIATE +import com.kickstarter.libs.utils.EventContextValues.CtaContextName.CONFIRM_SUBMIT 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.EDIT +import com.kickstarter.libs.utils.EventContextValues.CtaContextName.FIX_PLEDGE_INITIATE +import com.kickstarter.libs.utils.EventContextValues.CtaContextName.MESSAGE_CREATOR_INITIATE import com.kickstarter.libs.utils.EventContextValues.CtaContextName.SEARCH import com.kickstarter.libs.utils.EventContextValues.CtaContextName.SIGN_UP_INITIATE +import com.kickstarter.libs.utils.EventContextValues.CtaContextName.SURVEY_RESPONSE_INITIATE import com.kickstarter.libs.utils.EventContextValues.DiscoveryContextType.ALL import com.kickstarter.libs.utils.EventContextValues.DiscoveryContextType.PWL import com.kickstarter.libs.utils.EventContextValues.DiscoveryContextType.RECOMMENDED @@ -1509,6 +1518,233 @@ class SegmentTest : KSRobolectricTestCase() { this.segmentTrack.assertValue(PAGE_VIEWED.eventName) } + @Test + fun `test ppo page viewed event`() { + val user = user() + val client = client(user) + + val ppoCards = listOf(PPOCardFactory.confirmAddressCard(), PPOCardFactory.confirmAddressCard(), PPOCardFactory.fixPaymentCard()) + client.eventNames.subscribe(this.segmentTrack) + client.eventProperties.subscribe(this.propertiesTest) + + val segment = AnalyticEvents(listOf(client)) + + segment.trackPledgedProjectsOverviewPageViewed(ppoCards, 10) + + val properties = this.propertiesTest.value + + assertContextProperties() + assertUserProperties(false) + assertSessionProperties(user) + val expectedProperties = this.propertiesTest.value + + this.segmentTrack.assertValue(PAGE_VIEWED.eventName) + + assertEquals(PROJECT_ALERTS.contextName, properties[CONTEXT_PAGE.contextName]) + assertEquals(2, expectedProperties["notification_count_address_locks_soon"]) + assertEquals(1, expectedProperties["notification_count_payment_failed"]) + assertEquals(0, expectedProperties["notification_count_card_auth_required"]) + assertEquals(0, expectedProperties["notification_count_survey_available"]) + assertEquals(10, expectedProperties["notification_count_total"]) + } + + @Test + fun `test ppo message creator click event`() { + val user = user() + val client = client(user) + + val ppoCards = listOf(PPOCardFactory.confirmAddressCard(), PPOCardFactory.confirmAddressCard(), PPOCardFactory.fixPaymentCard()) + client.eventNames.subscribe(this.segmentTrack) + client.eventProperties.subscribe(this.propertiesTest) + + val segment = AnalyticEvents(listOf(client)) + + segment.trackPPOMessageCreatorCTAClicked("123123", ppoCards, 11, "09231") + + val properties = this.propertiesTest.value + + assertContextProperties() + assertUserProperties(false) + assertSessionProperties(user) + val expectedProperties = this.propertiesTest.value + + this.segmentTrack.assertValue(CTA_CLICKED.eventName) + + assertEquals(PROJECT_ALERTS.contextName, properties[CONTEXT_PAGE.contextName]) + assertEquals(MESSAGE_CREATOR_INITIATE.contextName, properties[CONTEXT_CTA.contextName]) + assertEquals("123123", expectedProperties["project_pid"]) + assertEquals("09231", expectedProperties["interaction_target_id"]) + assertEquals(2, expectedProperties["notification_count_address_locks_soon"]) + assertEquals(1, expectedProperties["notification_count_payment_failed"]) + assertEquals(0, expectedProperties["notification_count_card_auth_required"]) + assertEquals(0, expectedProperties["notification_count_survey_available"]) + assertEquals(11, expectedProperties["notification_count_total"]) + } + + @Test + fun `test ppo fix payment click event`() { + val user = user() + val client = client(user) + + val ppoCards = listOf(PPOCardFactory.confirmAddressCard(), PPOCardFactory.confirmAddressCard(), PPOCardFactory.fixPaymentCard()) + client.eventNames.subscribe(this.segmentTrack) + client.eventProperties.subscribe(this.propertiesTest) + + val segment = AnalyticEvents(listOf(client)) + + segment.trackPPOFixPaymentCTAClicked("123123", ppoCards, 11) + + val properties = this.propertiesTest.value + + assertContextProperties() + assertUserProperties(false) + assertSessionProperties(user) + val expectedProperties = this.propertiesTest.value + + this.segmentTrack.assertValue(CTA_CLICKED.eventName) + + assertEquals(PROJECT_ALERTS.contextName, properties[CONTEXT_PAGE.contextName]) + assertEquals(FIX_PLEDGE_INITIATE.contextName, properties[CONTEXT_CTA.contextName]) + assertEquals("123123", expectedProperties["project_pid"]) + assertEquals(2, expectedProperties["notification_count_address_locks_soon"]) + assertEquals(1, expectedProperties["notification_count_payment_failed"]) + assertEquals(0, expectedProperties["notification_count_card_auth_required"]) + assertEquals(0, expectedProperties["notification_count_survey_available"]) + assertEquals(11, expectedProperties["notification_count_total"]) + } + + @Test + fun `test ppo open survey click event`() { + val user = user() + val client = client(user) + + val ppoCards = listOf(PPOCardFactory.confirmAddressCard(), PPOCardFactory.confirmAddressCard(), PPOCardFactory.fixPaymentCard()) + client.eventNames.subscribe(this.segmentTrack) + client.eventProperties.subscribe(this.propertiesTest) + + val segment = AnalyticEvents(listOf(client)) + + segment.trackPPOOpenSurveyCTAClicked("123123", ppoCards, 11, "9023234") + + val properties = this.propertiesTest.value + + assertContextProperties() + assertUserProperties(false) + assertSessionProperties(user) + val expectedProperties = this.propertiesTest.value + + this.segmentTrack.assertValue(CTA_CLICKED.eventName) + + assertEquals(PROJECT_ALERTS.contextName, properties[CONTEXT_PAGE.contextName]) + assertEquals(SURVEY_RESPONSE_INITIATE.contextName, properties[CONTEXT_CTA.contextName]) + assertEquals("123123", expectedProperties["project_pid"]) + assertEquals("9023234", expectedProperties["survey_id"]) + assertEquals(2, expectedProperties["notification_count_address_locks_soon"]) + assertEquals(1, expectedProperties["notification_count_payment_failed"]) + assertEquals(0, expectedProperties["notification_count_card_auth_required"]) + assertEquals(0, expectedProperties["notification_count_survey_available"]) + assertEquals(11, expectedProperties["notification_count_total"]) + } + + @Test + fun `test ppo confirm address initiate click event`() { + val user = user() + val client = client(user) + + val ppoCards = listOf(PPOCardFactory.confirmAddressCard(), PPOCardFactory.confirmAddressCard(), PPOCardFactory.fixPaymentCard()) + client.eventNames.subscribe(this.segmentTrack) + client.eventProperties.subscribe(this.propertiesTest) + + val segment = AnalyticEvents(listOf(client)) + + segment.trackPPOConfirmAddressInitiateCTAClicked("123123", ppoCards, 11) + + val properties = this.propertiesTest.value + + assertContextProperties() + assertUserProperties(false) + assertSessionProperties(user) + val expectedProperties = this.propertiesTest.value + + this.segmentTrack.assertValue(CTA_CLICKED.eventName) + + assertEquals(PROJECT_ALERTS.contextName, properties[CONTEXT_PAGE.contextName]) + assertEquals(CONFIRM_INITIATE.contextName, properties[CONTEXT_CTA.contextName]) + assertEquals(ADDRESS.contextName, properties[CONTEXT_TYPE.contextName]) + assertEquals("123123", expectedProperties["project_pid"]) + assertEquals(2, expectedProperties["notification_count_address_locks_soon"]) + assertEquals(1, expectedProperties["notification_count_payment_failed"]) + assertEquals(0, expectedProperties["notification_count_card_auth_required"]) + assertEquals(0, expectedProperties["notification_count_survey_available"]) + assertEquals(11, expectedProperties["notification_count_total"]) + } + + @Test + fun `test ppo confirm address submit click event`() { + val user = user() + val client = client(user) + + val ppoCards = listOf(PPOCardFactory.confirmAddressCard(), PPOCardFactory.confirmAddressCard(), PPOCardFactory.fixPaymentCard()) + client.eventNames.subscribe(this.segmentTrack) + client.eventProperties.subscribe(this.propertiesTest) + + val segment = AnalyticEvents(listOf(client)) + + segment.trackPPOConfirmAddressSubmitCTAClicked("123123", ppoCards, 11) + + val properties = this.propertiesTest.value + + assertContextProperties() + assertUserProperties(false) + assertSessionProperties(user) + val expectedProperties = this.propertiesTest.value + + this.segmentTrack.assertValue(CTA_CLICKED.eventName) + + assertEquals(PROJECT_ALERTS.contextName, properties[CONTEXT_PAGE.contextName]) + assertEquals(CONFIRM_SUBMIT.contextName, properties[CONTEXT_CTA.contextName]) + assertEquals(ADDRESS.contextName, properties[CONTEXT_TYPE.contextName]) + assertEquals("123123", expectedProperties["project_pid"]) + assertEquals(2, expectedProperties["notification_count_address_locks_soon"]) + assertEquals(1, expectedProperties["notification_count_payment_failed"]) + assertEquals(0, expectedProperties["notification_count_card_auth_required"]) + assertEquals(0, expectedProperties["notification_count_survey_available"]) + assertEquals(11, expectedProperties["notification_count_total"]) + } + + @Test + fun `test ppo confirm address edit click event`() { + val user = user() + val client = client(user) + + val ppoCards = listOf(PPOCardFactory.confirmAddressCard(), PPOCardFactory.confirmAddressCard(), PPOCardFactory.fixPaymentCard()) + client.eventNames.subscribe(this.segmentTrack) + client.eventProperties.subscribe(this.propertiesTest) + + val segment = AnalyticEvents(listOf(client)) + + segment.trackPPOConfirmAddressEditCTAClicked("123123", ppoCards, 11) + + val properties = this.propertiesTest.value + + assertContextProperties() + assertUserProperties(false) + assertSessionProperties(user) + val expectedProperties = this.propertiesTest.value + + this.segmentTrack.assertValue(CTA_CLICKED.eventName) + + assertEquals(PROJECT_ALERTS.contextName, properties[CONTEXT_PAGE.contextName]) + assertEquals(EDIT.contextName, properties[CONTEXT_CTA.contextName]) + assertEquals(ADDRESS.contextName, properties[CONTEXT_TYPE.contextName]) + assertEquals("123123", expectedProperties["project_pid"]) + assertEquals(2, expectedProperties["notification_count_address_locks_soon"]) + assertEquals(1, expectedProperties["notification_count_payment_failed"]) + assertEquals(0, expectedProperties["notification_count_card_auth_required"]) + assertEquals(0, expectedProperties["notification_count_survey_available"]) + assertEquals(11, expectedProperties["notification_count_total"]) + } + @Test fun trackDiscoverFilterCTA_whenFilterPresent_returnsCorrectFilter() { val user = user() @@ -1646,6 +1882,11 @@ class SegmentTest : KSRobolectricTestCase() { assertEquals(110.71, expectedProperties["checkout_add_ons_minimum_usd"]) } + private fun assertNotificationProperties() { + val expectedProperties = this.propertiesTest.value + assertEquals(1, expectedProperties["notification_count_address_locks_soon"]) + } + private fun assertProjectProperties(project: Project) { val expectedProperties = this.propertiesTest.value assertEquals(100, expectedProperties["project_backers_count"])