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

[EP-256] Card Clicked #1400

Merged
merged 8 commits into from
Mar 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 52 additions & 21 deletions Library/Tracking/KSRAnalytics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ public final class KSRAnalytics {
case addOnsPageViewed = "Add-Ons Page Viewed"
case collectionViewed = "Collection Viewed"
case continueWithAppleButtonClicked = "Continue With Apple Button Clicked"
case editorialCardClicked = "Editorial Card Clicked"
case explorePageViewed = "Explore Page Viewed"
case fbLoginOrSignupButtonClicked = "Facebook Log In or Signup Button Clicked"
case filterClicked = "Filter Clicked"
Expand All @@ -43,7 +42,6 @@ public final class KSRAnalytics {
case onboardingContinueButtonClicked = "Onboarding Continue Button Clicked"
case onboardingGetStartedButtonClicked = "Onboarding Get Started Button Clicked"
case onboardingSkipButtonClicked = "Onboarding Skip Button Clicked"
case projectCardClicked = "Project Card Clicked"
case projectPagePledgeButtonClicked = "Project Page Pledge Button Clicked"
case projectSwiped = "Project Swiped"
case searchPageViewed = "Search Page Viewed"
Expand All @@ -59,6 +57,7 @@ public final class KSRAnalytics {
private enum NewApprovedEvent: String, CaseIterable {
case ctaClicked = "CTA Clicked"
case pageViewed = "Page Viewed"
case cardClicked = "Card Clicked"
}

/// Determines the screen from which the event is sent.
Expand All @@ -79,6 +78,7 @@ public final class KSRAnalytics {
case pledgeAddNewCard = "pledge_add_new_card" // AddNewCardViewController
case pledgeScreen = "pledge" // PledgeViewController
case projectPage = "project" // ProjectPamphletViewController
case profile // BackerDashboardProjectsViewController
case rewards // RewardsViewController
case search // SearchViewController
case settingsAddNewCard = "settings_add_new_card" // AddNewCardViewController
Expand Down Expand Up @@ -320,24 +320,29 @@ public final class KSRAnalytics {

/**
A tab or section within a grouping of content.

- backed: Section of BackerDashboardProjectViewController for backed Projects
- comments: Section of Project overview screen
- campaign: Details when user clicks "Read more"
- overview: Project overview landing screen
- updates: Section of project overview screen.
- watched:Section of BackerDashboardProjectViewController for saved Projects
*/
public enum SectionContext {
case backed
case campaign
case comments
case overview
case updates
case watched

var trackingString: String {
switch self {
case .backed: return "backed"
case .campaign: return "campaign"
case .comments: return "comments"
case .overview: return "overview"
case .updates: return "updates"
case .watched: return "watched"
}
}
}
Expand All @@ -358,6 +363,7 @@ public final class KSRAnalytics {
case location
case percentRaised
case pledge(PledgeContext)
case project
case projectState
case pwl
case recommended
Expand Down Expand Up @@ -414,6 +420,7 @@ public final class KSRAnalytics {
case .location: return "location"
case .percentRaised: return "percent_raised"
case let .pledge(pledgeContext): return pledgeContext.trackingString
case .project: return "project"
case .projectState: return "project_state"
case .pwl: return "pwl"
case .recommended: return "recommended"
Expand All @@ -433,15 +440,19 @@ public final class KSRAnalytics {
A context providing additional details about the location the event occurs.
*/
public enum LocationContext {
case accountMenu
case discoverAdvanced
case discoverOverlay
case globalNav
case recommendations

var trackingString: String {
switch self {
case .accountMenu: return "account_menu"
case .discoverAdvanced: return "discover_advanced"
case .discoverOverlay: return "discover_overlay"
case .globalNav: return "global_nav"
case .recommendations: return "recommendations"
singhhari marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand Down Expand Up @@ -720,14 +731,16 @@ public final class KSRAnalytics {
Call when the user taps the editorial header at the top of Discovery
*/
public func trackEditorialHeaderTapped(params: DiscoveryParams,
refTag: RefTag,
optimizelyProperties: [String: Any] = [:]) {
let props = discoveryProperties(from: params)
.withAllValuesFrom(optimizelyProperties)
refTag: RefTag) {
let props = contextProperties(
page: .discovery,
typeContext: .project,
locationContext: .discoverAdvanced
)
.withAllValuesFrom(discoveryProperties(from: params))

self.track(
event: ApprovedEvent.editorialCardClicked.rawValue,
page: .discovery,
event: NewApprovedEvent.cardClicked.rawValue,
properties: props,
refTag: refTag.stringTag
)
Expand All @@ -748,22 +761,40 @@ public final class KSRAnalytics {

/**
Call when a project card is clicked from a list of projects
- parameter project: the Project corresponding to the card that was clicked
- parameter params: the DiscoveryParams associated with the list of projects
- parameter location: the location context of the event
- parameter page: The `PageContext` representing the specific area the UI is interacted in
- parameter checkoutData: The `CheckoutPropertiesData` associated with this specific checkout instance
- parameter project: The `Project` corresponding to the card that was clicked
- parameter location: The optional `LocationContext` representing additional details of the UI interaction
- parameter params: The optional `DiscoveryParams ` associated with the list of projects
- parameter reward: The optional `Reward ` for the selected `Project`
- parameter section: The optional `SectionContext ` representing the grouping of content
*/

public func trackProjectCardClicked(project: Project,
params: DiscoveryParams,
location: PageContext,
optimizelyProperties: [String: Any] = [:]) {
let props = discoveryProperties(from: params)
.withAllValuesFrom(projectProperties(from: project, loggedInUser: self.loggedInUser))
.withAllValuesFrom(optimizelyProperties)
public func trackProjectCardClicked(page: PageContext,
project: Project,
checkoutData: CheckoutPropertiesData? = nil,
location: LocationContext? = nil,
params: DiscoveryParams? = nil,
reward: Reward? = nil,
section: SectionContext? = nil) {
var props = projectProperties(from: project, loggedInUser: self.loggedInUser)
.withAllValuesFrom(contextProperties(
sectionContext: section,
typeContext: .project,
locationContext: location
))

if let checkoutProps = checkoutData {
props = props.withAllValuesFrom(checkoutProperties(from: checkoutProps, and: reward))
}

if let discoveryParams = params {
props = props.withAllValuesFrom(discoveryProperties(from: discoveryParams))
}

self.track(
event: ApprovedEvent.projectCardClicked.rawValue,
page: location,
event: NewApprovedEvent.cardClicked.rawValue,
page: page,
properties: props
)
}
Expand Down
159 changes: 153 additions & 6 deletions Library/Tracking/KSRAnalyticsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -777,25 +777,170 @@ final class KSRAnalyticsTests: TestCase {
XCTAssertEqual("Apple", callBackProperties?["session_device_manufacturer"] as? String)
}

func testProjectCardClicked() {
func testProjectCardClicked_Page_Discover() {
let dataLakeClient = MockTrackingClient()
let segmentClient = MockTrackingClient()
let ksrAnalytics = KSRAnalytics(dataLakeClient: dataLakeClient, segmentClient: segmentClient)

ksrAnalytics.trackProjectCardClicked(
page: .discovery,
project: .template,
params: DiscoveryParams.recommendedDefaults,
location: .discovery
location: .discoverAdvanced,
params: DiscoveryParams.recommendedDefaults
)

XCTAssertEqual(["Project Card Clicked"], dataLakeClient.events)
XCTAssertEqual(["Card Clicked"], dataLakeClient.events)
XCTAssertEqual("project", dataLakeClient.properties.last?["context_type"] as? String)
XCTAssertEqual("discover", dataLakeClient.properties.last?["context_page"] as? String)
XCTAssertEqual("discover_advanced", dataLakeClient.properties.last?["context_location"] as? String)

self.assertProjectProperties(dataLakeClient.properties.last)
self.assertDiscoveryProperties(dataLakeClient.properties.last)

XCTAssertEqual(["Project Card Clicked"], segmentClient.events)
XCTAssertEqual(["Card Clicked"], segmentClient.events)
XCTAssertEqual("project", segmentClient.properties.last?["context_type"] as? String)
XCTAssertEqual("discover", segmentClient.properties.last?["context_page"] as? String)
XCTAssertEqual("discover_advanced", segmentClient.properties.last?["context_location"] as? String)

self.assertProjectProperties(segmentClient.properties.last)
self.assertDiscoveryProperties(segmentClient.properties.last)
}

func testProjectCardClicked_Page_Activities() {
let dataLakeClient = MockTrackingClient()
let segmentClient = MockTrackingClient()
let ksrAnalytics = KSRAnalytics(dataLakeClient: dataLakeClient, segmentClient: segmentClient)

ksrAnalytics.trackProjectCardClicked(
page: .activities,
project: .template
)

XCTAssertEqual(["Card Clicked"], dataLakeClient.events)
XCTAssertEqual("project", dataLakeClient.properties.last?["context_type"] as? String)
XCTAssertEqual("activity_feed", dataLakeClient.properties.last?["context_page"] as? String)

self.assertProjectProperties(dataLakeClient.properties.last)

XCTAssertEqual(["Card Clicked"], segmentClient.events)
XCTAssertEqual("project", segmentClient.properties.last?["context_type"] as? String)
XCTAssertEqual("activity_feed", segmentClient.properties.last?["context_page"] as? String)

self.assertProjectProperties(segmentClient.properties.last)
}

func testProjectCardClicked_Page_Profile_Section_Backed() {
let dataLakeClient = MockTrackingClient()
let segmentClient = MockTrackingClient()
let ksrAnalytics = KSRAnalytics(dataLakeClient: dataLakeClient, segmentClient: segmentClient)

ksrAnalytics.trackProjectCardClicked(
page: .profile,
project: .template,
location: .accountMenu,
section: .backed
)

XCTAssertEqual(["Card Clicked"], dataLakeClient.events)
XCTAssertEqual("project", dataLakeClient.properties.last?["context_type"] as? String)
XCTAssertEqual("profile", dataLakeClient.properties.last?["context_page"] as? String)
XCTAssertEqual("account_menu", dataLakeClient.properties.last?["context_location"] as? String)
XCTAssertEqual("backed", dataLakeClient.properties.last?["context_section"] as? String)

self.assertProjectProperties(dataLakeClient.properties.last)

XCTAssertEqual(["Card Clicked"], segmentClient.events)
XCTAssertEqual("project", segmentClient.properties.last?["context_type"] as? String)
XCTAssertEqual("profile", segmentClient.properties.last?["context_page"] as? String)
XCTAssertEqual("account_menu", segmentClient.properties.last?["context_location"] as? String)
XCTAssertEqual("backed", segmentClient.properties.last?["context_section"] as? String)

self.assertProjectProperties(segmentClient.properties.last)
}

func testProjectCardClicked_Page_Profile_Section_Watched() {
let dataLakeClient = MockTrackingClient()
let segmentClient = MockTrackingClient()
let ksrAnalytics = KSRAnalytics(dataLakeClient: dataLakeClient, segmentClient: segmentClient)

ksrAnalytics.trackProjectCardClicked(
page: .profile,
project: .template,
location: .accountMenu,
section: .watched
)

XCTAssertEqual(["Card Clicked"], dataLakeClient.events)
XCTAssertEqual("project", dataLakeClient.properties.last?["context_type"] as? String)
XCTAssertEqual("profile", dataLakeClient.properties.last?["context_page"] as? String)
XCTAssertEqual("account_menu", dataLakeClient.properties.last?["context_location"] as? String)
XCTAssertEqual("watched", dataLakeClient.properties.last?["context_section"] as? String)

self.assertProjectProperties(dataLakeClient.properties.last)

XCTAssertEqual(["Card Clicked"], segmentClient.events)
XCTAssertEqual("project", segmentClient.properties.last?["context_type"] as? String)
XCTAssertEqual("profile", segmentClient.properties.last?["context_page"] as? String)
XCTAssertEqual("account_menu", segmentClient.properties.last?["context_location"] as? String)
XCTAssertEqual("watched", segmentClient.properties.last?["context_section"] as? String)

self.assertProjectProperties(segmentClient.properties.last)
}

func testProjectCardClicked_Page_Thanks() {
let dataLakeClient = MockTrackingClient()
let segmentClient = MockTrackingClient()
let ksrAnalytics = KSRAnalytics(dataLakeClient: dataLakeClient, segmentClient: segmentClient)
let reward = Reward.template
|> Reward.lens.shipping.preference .~ .restricted
|> Reward.lens.endsAt .~ MockDate().addingTimeInterval(5).timeIntervalSince1970

ksrAnalytics.trackProjectCardClicked(
page: .thanks,
project: .template,
checkoutData: .template,
location: .recommendations,
reward: reward
)

XCTAssertEqual(["Card Clicked"], dataLakeClient.events)
XCTAssertEqual("project", dataLakeClient.properties.last?["context_type"] as? String)
XCTAssertEqual("thanks", dataLakeClient.properties.last?["context_page"] as? String)
XCTAssertEqual("recommendations", dataLakeClient.properties.last?["context_location"] as? String)

self.assertProjectProperties(dataLakeClient.properties.last)
self.assertCheckoutProperties(dataLakeClient.properties.last)

XCTAssertEqual(["Card Clicked"], segmentClient.events)
XCTAssertEqual("project", segmentClient.properties.last?["context_type"] as? String)
XCTAssertEqual("thanks", segmentClient.properties.last?["context_page"] as? String)
XCTAssertEqual("recommendations", segmentClient.properties.last?["context_location"] as? String)

self.assertProjectProperties(segmentClient.properties.last)
self.assertCheckoutProperties(segmentClient.properties.last)
}

func testProjectCardClicked_Page_Search() {
let dataLakeClient = MockTrackingClient()
let segmentClient = MockTrackingClient()
let ksrAnalytics = KSRAnalytics(dataLakeClient: dataLakeClient, segmentClient: segmentClient)

ksrAnalytics.trackProjectCardClicked(
page: .search,
project: .template,
params: DiscoveryParams.recommendedDefaults
)

XCTAssertEqual(["Card Clicked"], dataLakeClient.events)
XCTAssertEqual("project", dataLakeClient.properties.last?["context_type"] as? String)
XCTAssertEqual("search", dataLakeClient.properties.last?["context_page"] as? String)

self.assertProjectProperties(dataLakeClient.properties.last)
self.assertDiscoveryProperties(dataLakeClient.properties.last)

XCTAssertEqual(["Card Clicked"], segmentClient.events)
XCTAssertEqual("project", segmentClient.properties.last?["context_type"] as? String)
XCTAssertEqual("search", segmentClient.properties.last?["context_page"] as? String)

self.assertProjectProperties(segmentClient.properties.last)
self.assertDiscoveryProperties(segmentClient.properties.last)
Expand Down Expand Up @@ -1844,9 +1989,11 @@ final class KSRAnalyticsTests: TestCase {
}

func testLocationContextTrackingStrings() {
XCTAssertEqual(KSRAnalytics.LocationContext.globalNav.trackingString, "global_nav")
XCTAssertEqual(KSRAnalytics.LocationContext.accountMenu.trackingString, "account_menu")
XCTAssertEqual(KSRAnalytics.LocationContext.discoverAdvanced.trackingString, "discover_advanced")
XCTAssertEqual(KSRAnalytics.LocationContext.discoverOverlay.trackingString, "discover_overlay")
XCTAssertEqual(KSRAnalytics.LocationContext.globalNav.trackingString, "global_nav")
XCTAssertEqual(KSRAnalytics.LocationContext.recommendations.trackingString, "recommendations")
}

/*
Expand Down
9 changes: 9 additions & 0 deletions Library/ViewModels/ActivitiesViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -346,13 +346,22 @@ public final class ActivitiesViewModel: ActivitiesViewModelType, ActitiviesViewM
AppEnvironment.current.ksrAnalytics.trackActivitiesManagePledgeButtonClicked(project: project)
}

// Tracking

Signal.zip(pageCount, paginatedActivities)
.filter { pageCount, _ in
pageCount == 1
} // Track first page only
.map(second)
.map { $0.count }
.observeValues { AppEnvironment.current.ksrAnalytics.trackActivities(count: $0) }

self.goToProject.signal.map(first).observeValues { project in
AppEnvironment.current.ksrAnalytics.trackProjectCardClicked(
page: .activities,
project: project
)
}
}

fileprivate let currentUserUpdatedProperty = MutableProperty(())
Expand Down
Loading