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

[NT-645] Clean discovery properties & events [Part 1] #984

Merged
merged 13 commits into from
Dec 10, 2019
22 changes: 22 additions & 0 deletions Library/RefTag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,25 @@ extension RefTag: Argo.Decodable {
}
}
}

extension RefTag {
public static func fromParams(_ params: DiscoveryParams) -> RefTag {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that this is extracted from the VM we probably want to add a test for it.

if let tagId = params.tagId {
return .projectCollection(tagId)
}

if params.category != nil {
return .categoryWithSort(params.sort ?? .magic)
} else if params.recommended == .some(true) {
return .recsWithSort(params.sort ?? .magic)
} else if params.staffPicks == .some(true) {
return .recommendedWithSort(params.sort ?? .magic)
} else if params.social == .some(true) {
return .socialWithSort(params.sort ?? .magic)
} else if params.starred == .some(true) {
return .starredWithSort(params.sort ?? .magic)
}

return RefTag.discoveryWithSort(params.sort ?? .magic)
}
}
28 changes: 28 additions & 0 deletions Library/RefTagTests.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
@testable import KsApi
@testable import Library
import Prelude
import XCTest

public final class RefTagTests: XCTestCase {
Expand Down Expand Up @@ -173,4 +175,30 @@ public final class RefTagTests: XCTestCase {
XCTAssertEqual(RefTag.update, RefTag(code: RefTag.update.stringTag))
XCTAssertEqual(RefTag.unrecognized("custom"), RefTag(code: RefTag.unrecognized("custom").stringTag))
}

func testRefTagFromDiscoveryParams() {
let discoSort = DiscoveryParams.defaults
|> DiscoveryParams.lens.sort .~ .endingSoon
let discoCategory = DiscoveryParams.defaults
|> DiscoveryParams.lens.sort .~ .endingSoon
|> DiscoveryParams.lens.category .~ Category.documentary
let discoRecommended = DiscoveryParams.defaults
|> DiscoveryParams.lens.recommended .~ true
let discoPWL = DiscoveryParams.defaults
|> DiscoveryParams.lens.staffPicks .~ true
let discoSocial = DiscoveryParams.defaults
|> DiscoveryParams.lens.social .~ true
let discoStarred = DiscoveryParams.defaults
|> DiscoveryParams.lens.starred .~ true
let discoCollection = DiscoveryParams.defaults
|> DiscoveryParams.lens.tagId .~ .goRewardless

XCTAssertEqual("discovery_ending_soon", RefTag.fromParams(discoSort).stringTag)
XCTAssertEqual("category_ending_soon", RefTag.fromParams(discoCategory).stringTag)
XCTAssertEqual("recs_home", RefTag.fromParams(discoRecommended).stringTag)
XCTAssertEqual("recommended_home", RefTag.fromParams(discoPWL).stringTag)
XCTAssertEqual("social_home", RefTag.fromParams(discoSocial).stringTag)
XCTAssertEqual("starred_home", RefTag.fromParams(discoStarred).stringTag)
XCTAssertEqual("ios_project_collection_tag_518", RefTag.fromParams(discoCollection).stringTag)
}
}
195 changes: 56 additions & 139 deletions Library/Tracking/Koala.swift
Original file line number Diff line number Diff line change
Expand Up @@ -400,23 +400,15 @@ public final class Koala {
self.preferredContentSizeCategoryObserver.doIfSome(NotificationCenter.default.removeObserver)
}

// MARK: - Activity

/// Call when the activities screen is shown.
public func trackActivities() {
self.track(event: "Activities", properties: deprecatedProps)
self.track(event: "Viewed Activity")
public func trackActivities(count: Int) {
// TODO: add user properties and session props
self.track(event: "Activity Feed Viewed", properties: ["activities_count": count])
}

/// Call when the activities are refreshed.
public func trackLoadedNewerActivity() {
self.track(event: "Loaded Newer Activity")
}

/// Call when the activities are paginated.
///
/// - parameter page: The number of pages that have been loaded.
public func trackLoadedOlderActivity(page: Int) {
self.track(event: "Loaded Older Activity", properties: ["page": page])
}
// MARK: - Application Lifecycle

/// Call when the app launches or enters foreground.
public func trackAppOpen() {
Expand Down Expand Up @@ -480,122 +472,57 @@ public final class Koala {
// MARK: - Discovery Events

/**
Call when a discovery search is made, including pagination.
Call when a discovery page is viewed and the first page is loaded.

- parameter params: The params used for the discovery search.
- parameter page: The number of pages that have been loaded.
*/
public func trackDiscovery(params: DiscoveryParams, page: Int) {
var props = properties(params: params).withAllValuesFrom(["page": page])

self.track(event: "Loaded Discovery Results", properties: props)

// Deprecated event
self.track(
event: "Discover List View",
properties: props.withAllValuesFrom(deprecatedProps)
)
}

public func trackDiscoveryViewed(params: DiscoveryParams) {
self.track(event: "Viewed Discovery", properties: properties(params: params))
}

public func trackDiscoveryFavoritedCategory(params: DiscoveryParams, isFavorited: Bool) {
let props = params.category.map(properties) ?? [:]
let deprecatedProps = props.withAllValuesFrom(
["toggle_to": isFavorited, Koala.DeprecatedKey: true]
)

self.track(
event: isFavorited ? "Added Favorite Category" : "Removed Favorite Category",
properties: props
)

// Deprecated event
self.track(
event: "Discover Category Favorite",
properties: deprecatedProps
)
}
public func trackDiscovery(params: DiscoveryParams) {
let props = discoveryProperties(from: params)

/// Call when the discovery filters appear
public func trackDiscoveryModal() {
let props: [String: Any] = ["modal_type": "filters"]

self.track(event: "Viewed Discovery Filters", properties: props)

// Deprecated event
self.track(
event: "Discover Switch Modal",
properties: props.withAllValuesFrom(deprecatedProps)
)
self.track(event: "Explore Page Viewed", properties: props)
}

/**
Call when a filter is selected from the discovery modal.
Call when a filter is selected from the Explore modal.

- parameter params: The params selected from the modal.
- parameter isFavorite: Whether the filter is a favorite category or not.
*/
public func trackDiscoveryModalSelectedFilter(params: DiscoveryParams, isFavorite: Bool = false) {
public func trackDiscoveryModalSelectedFilter(params: DiscoveryParams) {
self.track(
event: "Selected Discovery Filter",
properties: properties(params: params).withAllValuesFrom([
"is_favorite": isFavorite ? "1" : "0"
])
event: "Filter Clicked",
properties: discoveryProperties(from: params)
)

// Deprecated event
self.track(
event: "Discover Modal Selected Filter",
properties: properties(params: params).withAllValuesFrom(deprecatedProps)
)
}

/**
Call when closing filter modal without selecting a new filter.

- parameter params: The params selected from the modal.
**/
public func trackDiscoveryModalClosedFilter(params: DiscoveryParams) {
self.track(event: "Closed Discovery Filter", properties: properties(params: params))
}

/**
Call when expanding filter on a parent category tap.

- parameter params: The params selected from the modal.
**/
public func trackDiscoveryModalExpandedFilter(params: DiscoveryParams) {
self.track(event: "Expanded Discovery Filter", properties: properties(params: params))
}

/**
Call when the user swipes between sorts or selects a sort.

- parameter sort: The new sort that was selected.
- parameter gesture: The gesture that was used.
*/
public func trackDiscoverySelectedSort(nextSort sort: DiscoveryParams.Sort, gesture: GestureType) {
self.track(event: "Selected Discovery Sort", properties: [
"discover_sort": sort.rawValue,
"gesture_type": gesture.trackingString
])
public func trackDiscoverySelectedSort(nextSort sort: DiscoveryParams.Sort, params: DiscoveryParams) {
let props = discoveryProperties(from: params)
.withAllValuesFrom([
"discover_sort": sort.rawValue
])

self.track(event: "Explore Sort Clicked", properties: props)
}

/**
Call when the user drags the top of the project list downward to refresh projects.
Call when the user taps the editorial header at the top of Discovery
*/
public func trackDiscoveryPullToRefresh() {
self.track(event: "Triggered Refresh")
public func trackEditorialHeaderTapped(refTag: RefTag) {
self.track(event: "Editorial Card Clicked", properties: ["ref_tag": refTag.stringTag])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this not include Discover Properties? Like:

discoveryProperties(from: params).withAllValuesFrom(["ref_tag": refTag.stringTag])

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think its really useful in this case because the next event should be Collection Viewed which does include discover properties πŸ€·β€β™€

}

/**
Call when the user taps the editorial header at the top of Discovery
Call when a collection is viewed

- parameter params: The DiscoveryParams associated with the collection
*/
public func trackEditorialHeaderTapped(refTag: RefTag) {
self.track(event: "Editorial Card Clicked", properties: ["refTag": refTag.stringTag])
public func trackCollectionViewed(params: DiscoveryParams) {
self.track(event: "Collection Viewed", properties: discoveryProperties(from: params))
}

// MARK: - Checkout Events
Expand Down Expand Up @@ -1320,31 +1247,25 @@ public final class Koala {

/// Call once when the search view is initially shown.
public func trackProjectSearchView() {
self.track(event: "Discover Search", properties: deprecatedProps)

self.track(event: "Viewed Search")
// TODO: pass user properties, session properties
self.track(event: "Search Page Viewed")
}

// Call when projects have been obtained from a search.
public func trackSearchResults(query: String, page: Int, hasResults: Bool) {
let sharedProps: [String: Any] = ["search_term": query]

let deprecatedProps = sharedProps.withAllValuesFrom(["page_count": page, Koala.DeprecatedKey: true])
let props = sharedProps.withAllValuesFrom(["page": page, "has_results": hasResults])

if page == 1 {
self.track(event: "Discover Search Results", properties: deprecatedProps)

self.track(event: "Loaded Search Results", properties: props)
} else {
self.track(event: "Discover Search Results Load More", properties: deprecatedProps)

self.track(event: "Loaded More Search Results", properties: props)
}
}
public func trackSearchResults(
query: String,
params: DiscoveryParams,
refTag: RefTag,
hasResults: Bool
) {
let props = discoveryProperties(from: params)
.withAllValuesFrom([
"discover_ref_tag": refTag.stringTag,
"search_term": query,
"has_results": hasResults
])

public func trackClearedSearchTerm() {
self.track(event: "Cleared Search Term")
self.track(event: "Search Results Loaded", properties: props)
}

// MARK: - Project Events
Expand Down Expand Up @@ -1950,13 +1871,6 @@ public final class Koala {

// MARK: - Empty State Events

public func trackEmptyStateViewed(type: EmptyState) {
self.track(
event: "Viewed Empty State",
properties: ["type": type.rawValue]
)
}

public func trackEmptyStateButtonTapped(type: EmptyState) {
self.track(
event: "Tapped Empty State Button",
Expand Down Expand Up @@ -2254,34 +2168,37 @@ private func properties(userActivity: NSUserActivity) -> [String: Any] {
return props
}

private func properties(params: DiscoveryParams, prefix _: String = "discover_") -> [String: Any] {
// MARK: - Discovery Properties

private func discoveryProperties(
from params: DiscoveryParams,
prefix: String = "discover_"
) -> [String: Any] {
var result: [String: Any] = [:]
var unprefixedResult: [String: Any] = [:]

// NB: All filters should be added here since `result["everything"]` is derived from this.
result["recommended"] = params.recommended
result["social"] = params.social
result["staff_picks"] = params.staffPicks
result["starred"] = params.starred
result["term"] = params.query
result["tag"] = params.tagId?.rawValue
result = result.withAllValuesFrom(params.category.map(properties(category:)) ?? [:])

result["everything"] = result.isEmpty
result["page"] = params.page
result["sort"] = params.sort?.rawValue
result["ref_tag"] = RefTag.fromParams(params).stringTag

return result.prefixedKeys("discover_")
unprefixedResult["search_term"] = params.query

return result.prefixedKeys(prefix).withAllValuesFrom(unprefixedResult)
}

private func properties(category: KsApi.Category) -> [String: Any] {
var result: [String: Any] = [:]

result["category_id"] = category.intID
result["category_name"] = category.name
result["category_projects_count"] = category.totalProjectCount

result["category_is_root"] = category.isRoot
result["category_root_id"] = category.rootId
result["category_root_name"] = category.root?.name

let parentProperties = category.parent.map(properties(category:)) ?? [:]
return result
Expand Down
Loading