Skip to content

Commit

Permalink
[WEB-935] Creator Dashboard Analytics (#1780)
Browse files Browse the repository at this point in the history
* creator_dashboard page viewed event

* switch project cta

* call trackCreatorDasboardPageViewed on viewWillAppear so that its called every time the tab is tapped

* update tests

* add CTA event on post update tap

* add event description comments

* PR Feedback
* syntax improvements
* switch project tests improvements
* make sure to get most recent value for 'self.project' via takePairWhen

* some pr corrections

* update test for readability

Co-authored-by: Mubarak Sadoon <msadoon@gmail.com>
  • Loading branch information
scottkicks and msadoon committed Jan 27, 2023
1 parent 684e856 commit 9e67046
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 0 deletions.
Expand Up @@ -218,6 +218,8 @@ internal final class DashboardViewController: UITableViewController {
}

fileprivate func goToPostUpdate(_ project: Project) {
self.viewModel.inputs.trackPostUpdateClicked()

let vc = UpdateDraftViewController.configuredWith(project: project)
vc.delegate = self

Expand Down
68 changes: 68 additions & 0 deletions Library/Tracking/KSRAnalytics.swift
Expand Up @@ -34,6 +34,7 @@ public final class KSRAnalytics {
case campaign // ProjectDescriptionViewController
case changePayment = "change_payment" // PledgeViewController
case checkout // // PledgeViewController
case creatorDashboard = "creator_dashboard" // DashboardViewController
case discovery = "discover" // DiscoveryViewController
case forgotPassword = "forgot_password" // ResetPasswordViewController
case landingPage = "landing_page" // LandingViewController
Expand Down Expand Up @@ -139,6 +140,7 @@ public final class KSRAnalytics {
public enum CTAContext {
case addOnsContinue
case campaignDetails
case creatorDashboard
case creatorDetails
case discover
case discoverFilter
Expand All @@ -151,6 +153,8 @@ public final class KSRAnalytics {
case pledgeInitiate
case pledgeSubmit
case project
case projectSelect
case projectUpdateCreateDraft
case rewardContinue
case search
case signUpInitiate
Expand All @@ -161,6 +165,7 @@ public final class KSRAnalytics {
switch self {
case .addOnsContinue: return "add_ons_continue"
case .campaignDetails: return "campaign_details"
case .creatorDashboard: return "creator_dashboard"
case .creatorDetails: return "creator_details"
case .discover: return "discover"
case .discoverFilter: return "discover_filter"
Expand All @@ -170,6 +175,8 @@ public final class KSRAnalytics {
case .pledgeConfirm: return "pledge_confirm"
case .pledgeSubmit: return "pledge_submit"
case .project: return "project"
case .projectSelect: return "creator_project_select"
case .projectUpdateCreateDraft: return "creator_project_update_create_draft"
case .logInInitiate: return "log_in_initiate"
case .logInOrSignUp: return "log_in_or_sign_up"
case .logInSubmit: return "log_in_submit"
Expand Down Expand Up @@ -267,6 +274,7 @@ public final class KSRAnalytics {
case backed
case campaign
case comments
case dashboard
case overview
case updates
case watched
Expand All @@ -277,6 +285,7 @@ public final class KSRAnalytics {
case .backed: return "backed"
case .campaign: return "campaign"
case .comments: return "comments"
case .dashboard: return "dashboard"
case .overview: return "overview"
case .updates: return "updates"
case .watched: return "watched"
Expand Down Expand Up @@ -756,6 +765,65 @@ public final class KSRAnalytics {
)
}

// MARK: - Creator Dashboard Events

/**
Call when the creator dashboard page is viewed and the first page is loaded.
*/

public func trackCreatorDashboardPageViewed() {
let props = contextProperties(
ctaContext: .creatorDashboard,
page: .creatorDashboard,
sectionContext: .dashboard
)
self.track(event: SegmentEvent.pageViewed.rawValue, properties: props)
}

/**
Call when a project is switched via dropdown at the top of the creator dashboard
- parameter project: The `Project` that the creator switched to.
- parameter refTag: The ref tag used when switching projects.
*/

public func trackCreatorDashboardSwitchProjectClicked(project: Project, refTag: RefTag?) {
let props = projectProperties(from: project, loggedInUser: self.loggedInUser)
.withAllValuesFrom(contextProperties(
ctaContext: .projectSelect,
page: .creatorDashboard,
sectionContext: .dashboard
))

self.track(
event: SegmentEvent.ctaClicked.rawValue,
properties: props,
refTag: refTag?.stringTag
)
}

/**
Call when 'Post Update' is tapped in the creator dashboard
- parameter project: The `Project` corresponding to the update.
- parameter refTag: The ref tag used when switching projects.
*/

public func trackCreatorDashboardPostUpdateClicked(project: Project, refTag: RefTag?) {
let props = projectProperties(from: project, loggedInUser: self.loggedInUser)
.withAllValuesFrom(contextProperties(
ctaContext: .projectUpdateCreateDraft,
page: .creatorDashboard,
sectionContext: .dashboard
))

self.track(
event: SegmentEvent.ctaClicked.rawValue,
properties: props,
refTag: refTag?.stringTag
)
}

// MARK: - Pledge Events

public func trackAddOnsContinueButtonClicked(
Expand Down
42 changes: 42 additions & 0 deletions Library/Tracking/KSRAnalyticsTests.swift
Expand Up @@ -499,6 +499,48 @@ final class KSRAnalyticsTests: TestCase {
XCTAssertEqual("Art", segmentClientProperties?["project_category"] as? String)
}

// MARK: - Creator Dashboard Properties Tests

func testCreatorDashboardPageViewed() {
let segmentClient = MockTrackingClient()
let loggedInUser = User.template |> \.id .~ 23
let ksrAnalytics = KSRAnalytics(
loggedInUser: loggedInUser,
segmentClient: segmentClient
)

ksrAnalytics.trackCreatorDashboardPageViewed()

XCTAssertEqual(["Page Viewed"], segmentClient.events)
XCTAssertEqual(["creator_dashboard"], segmentClient.properties(forKey: "context_page"))
XCTAssertEqual(["dashboard"], segmentClient.properties(forKey: "context_section"))
}

func testCreatorDashboardSwitchProjectClicked() {
let segmentClient = MockTrackingClient()
let ksrAnalytics = KSRAnalytics(segmentClient: segmentClient)

ksrAnalytics.trackCreatorDashboardSwitchProjectClicked(project: .template, refTag: RefTag.dashboard)

XCTAssertEqual(["CTA Clicked"], segmentClient.events)
XCTAssertEqual(["creator_project_select"], segmentClient.properties(forKey: "context_cta"))
XCTAssertEqual(["creator_dashboard"], segmentClient.properties(forKey: "context_page"))
XCTAssertEqual(["dashboard"], segmentClient.properties(forKey: "context_section"))
XCTAssertEqual(["The Project"], segmentClient.properties(forKey: "project_name"))
}

func testCreatorDashboardPostUpdateClicked() {
let segmentClient = MockTrackingClient()
let ksrAnalytics = KSRAnalytics(segmentClient: segmentClient)

ksrAnalytics.trackCreatorDashboardPostUpdateClicked(project: .template, refTag: RefTag.dashboard)

XCTAssertEqual(["CTA Clicked"], segmentClient.events)
XCTAssertEqual(["creator_project_update_create_draft"], segmentClient.properties(forKey: "context_cta"))
XCTAssertEqual(["creator_dashboard"], segmentClient.properties(forKey: "context_page"))
XCTAssertEqual(["dashboard"], segmentClient.properties(forKey: "context_section"))
}

// MARK: - Discovery Properties Tests

func testDiscoveryProperties() {
Expand Down
34 changes: 34 additions & 0 deletions Library/ViewModels/DashboardViewModel.swift
Expand Up @@ -46,6 +46,9 @@ public protocol DashboardViewModelInputs {
/// Call when to show or hide the projects drawer.
func showHideProjectsDrawer()

/// Call when Post Update is clicked
func trackPostUpdateClicked()

/// Call when the view loads.
func viewDidLoad()

Expand Down Expand Up @@ -290,6 +293,32 @@ public final class DashboardViewModel: DashboardViewModelInputs, DashboardViewMo

self.focusScreenReaderOnTitleView = self.viewWillAppearAnimatedProperty.signal.ignoreValues()
.filter { AppEnvironment.current.isVoiceOverRunning() }

// MARK: - Tracking

self.viewWillAppearAnimatedProperty.signal.observeValues { _ in
AppEnvironment.current.ksrAnalytics.trackCreatorDashboardPageViewed()
}

_ = projects
.takePairWhen(self.switchToProjectProperty.signal)
.map { allProjects, param -> Project? in
param.flatMap { find(projectForParam: $0, in: allProjects) }
}
.skipNil()
.observeValues { switchedToProject in
AppEnvironment.current.ksrAnalytics
.trackCreatorDashboardSwitchProjectClicked(project: switchedToProject, refTag: RefTag.dashboard)
}

_ = self.project
.takePairWhen(self.trackPostUpdateClickedProperty.signal)
.observeValues { project, _ in
AppEnvironment.current.ksrAnalytics.trackCreatorDashboardPostUpdateClicked(
project: project,
refTag: RefTag.dashboard
)
}
}

fileprivate let showHideProjectsDrawerProperty = MutableProperty(())
Expand Down Expand Up @@ -322,6 +351,11 @@ public final class DashboardViewModel: DashboardViewModelInputs, DashboardViewMo
self.projectsDrawerDidAnimateOutProperty.value = ()
}

fileprivate let trackPostUpdateClickedProperty = MutableProperty(())
public func trackPostUpdateClicked() {
self.trackPostUpdateClickedProperty.value = ()
}

fileprivate let viewDidLoadProperty = MutableProperty(())
public func viewDidLoad() {
self.viewDidLoadProperty.value = ()
Expand Down
64 changes: 64 additions & 0 deletions Library/ViewModels/DashboardViewModelTests.swift
Expand Up @@ -335,4 +335,68 @@ internal final class DashboardViewModelTests: TestCase {
self.vm.inputs.showHideProjectsDrawer()
}
}

func testTrackingEvents_CreatorDashboardViewed() {
let projects = (0...4).map { .template |> Project.lens.id .~ $0 }

withEnvironment(apiService: MockService(fetchProjectsResponse: projects)) {
XCTAssertEqual([], self.segmentTrackingClient.events)

self.vm.inputs.viewWillAppear(animated: false)

XCTAssertEqual(["Page Viewed"], self.segmentTrackingClient.events)

self.vm.inputs.viewWillDisappear()

XCTAssertEqual(["Page Viewed"], self.segmentTrackingClient.events)

self.vm.inputs.viewWillAppear(animated: false)

XCTAssertEqual(["Page Viewed", "Page Viewed"], self.segmentTrackingClient.events)
}
}

func testTrackingEvents_CreatorDashboardSwitchProjectClicked() {
let project1 = Project.template
let project2 = .template |> Project.lens.id .~ 4
let projects = [project1, project2]

withEnvironment(apiService: MockService(fetchProjectsResponse: projects)) {
XCTAssertEqual([], self.segmentTrackingClient.events)

self.vm.inputs.viewWillAppear(animated: false)

self.scheduler.advance()

self.project.assertValues([project1])
XCTAssertEqual(["Page Viewed"], self.segmentTrackingClient.events)

self.vm.inputs.switch(toProject: .id(project2.id))

self.project.assertValues([project1, project2])
XCTAssertEqual(["Page Viewed", "CTA Clicked"], self.segmentTrackingClient.events)

self.vm.inputs.switch(toProject: .id(project1.id))

self.project
.assertValues([project1, project2, project1])
XCTAssertEqual(["Page Viewed", "CTA Clicked", "CTA Clicked"], self.segmentTrackingClient.events)
}
}

func testTrackingEvents_CreatorDashboardPostUpdateClicked() {
withEnvironment(apiService: MockService(fetchProjectsResponse: [Project.template])) {
XCTAssertEqual([], self.segmentTrackingClient.events)

self.vm.inputs.viewWillAppear(animated: false)

self.scheduler.advance()

XCTAssertEqual(["Page Viewed"], self.segmentTrackingClient.events)

self.vm.inputs.trackPostUpdateClicked()

XCTAssertEqual(["Page Viewed", "CTA Clicked"], self.segmentTrackingClient.events)
}
}
}

0 comments on commit 9e67046

Please sign in to comment.