Skip to content

Commit

Permalink
[MBL-1223] Track attribution event (#1961)
Browse files Browse the repository at this point in the history
* Track attribution event

* Return nil instead of force unwrapping
  • Loading branch information
ifosli committed Mar 6, 2024
1 parent 83e9ddf commit 2c8286c
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Kickstarter.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,8 @@
3959A62C2B69B9CD00FE8055 /* CombineTestObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1FDB1E72AEAAC6100285F93 /* CombineTestObserver.swift */; };
3959A62E2B69BBA600FE8055 /* CombineTestObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1FDB1E72AEAAC6100285F93 /* CombineTestObserver.swift */; };
3959A62F2B69BC6D00FE8055 /* CombineTestObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1FDB1E72AEAAC6100285F93 /* CombineTestObserver.swift */; };
395A3BC22B8E54C90091A379 /* AttributionTracking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 395A3BC12B8E54C90091A379 /* AttributionTracking.swift */; };
395A3BC42B8E56800091A379 /* AttributionTrackingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 395A3BC32B8E56800091A379 /* AttributionTrackingTests.swift */; };
399DAD882ACD15D000238BA1 /* UpdateUserAccount.graphql in Resources */ = {isa = PBXBuildFile; fileRef = 06643F3926A5FF1C002C5997 /* UpdateUserAccount.graphql */; };
399DAD892ACD162C00238BA1 /* FetchProjectFriendsById.graphql in Resources */ = {isa = PBXBuildFile; fileRef = 06BD057526F15CFB00C44E36 /* FetchProjectFriendsById.graphql */; };
399DAD8A2ACD163400238BA1 /* UnwatchProject.graphql in Resources */ = {isa = PBXBuildFile; fileRef = 478E31C026C1C4C6004BF898 /* UnwatchProject.graphql */; };
Expand Down Expand Up @@ -1922,6 +1924,8 @@
37FDAF702273B7FF00662CC8 /* UIStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIStackView.swift; sourceTree = "<group>"; };
37FDAFAA2273B86800662CC8 /* UIStackView+Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIStackView+Tests.swift"; sourceTree = "<group>"; };
37FEFBC7222F1E4F00FCA608 /* ProcessInfoType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProcessInfoType.swift; sourceTree = "<group>"; };
395A3BC12B8E54C90091A379 /* AttributionTracking.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttributionTracking.swift; sourceTree = "<group>"; };
395A3BC32B8E56800091A379 /* AttributionTrackingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttributionTrackingTests.swift; sourceTree = "<group>"; };
39B5E10D2B86C56600FFB720 /* RefInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RefInfo.swift; sourceTree = "<group>"; };
39B5E10F2B86C56E00FFB720 /* RefInfoTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RefInfoTests.swift; sourceTree = "<group>"; };
39B5E1112B89120E00FFB720 /* CreateAttributionEvent.graphql */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CreateAttributionEvent.graphql; sourceTree = "<group>"; };
Expand Down Expand Up @@ -5742,6 +5746,8 @@
children = (
8A788F25263C80C500A89DAE /* Vendor */,
6018626529A9194600EA2842 /* AppTrackingTransparency.swift */,
395A3BC12B8E54C90091A379 /* AttributionTracking.swift */,
395A3BC32B8E56800091A379 /* AttributionTrackingTests.swift */,
6018626729A91B8C00EA2842 /* ThirdPartyEventInputName.swift */,
8A23203025B0ECF700B940C3 /* IdentifyingTrackingClient.swift */,
8A213CE8239EAEA400BBB4C7 /* KSRAnalytics.swift */,
Expand Down Expand Up @@ -7791,6 +7797,7 @@
8A6C979024BFCDED00C4FA71 /* RewardAddOnSelectionContinueCTAViewModel.swift in Sources */,
A7F441B71D005A9400FE6FC5 /* BackingCellViewModel.swift in Sources */,
777C60A82420154100820C59 /* PersonalizationCellViewModel.swift in Sources */,
395A3BC22B8E54C90091A379 /* AttributionTracking.swift in Sources */,
A7CC13DB1D00E6CF00035C52 /* FindFriendsViewModel.swift in Sources */,
9DD1E3881D50035E00D4829E /* ProjectActivityData.swift in Sources */,
7061848D29BE577B008F9941 /* MessageBannerViewViewModel.swift in Sources */,
Expand Down Expand Up @@ -8065,6 +8072,7 @@
778CCCDA2285BF8900FB8D35 /* UIView+AutoLayoutTests.swift in Sources */,
373AB25F222A0DAC00769FC2 /* PasswordValidationTests.swift in Sources */,
D6C9A20E1F755FE200981E64 /* GraphSchemaTests.swift in Sources */,
395A3BC42B8E56800091A379 /* AttributionTrackingTests.swift in Sources */,
D6600790241A7C0000AC1EDB /* CuratedProjectsViewModelTests.swift in Sources */,
A7ED1F4A1E831BA200BFFA01 /* MockBundle.swift in Sources */,
D04AACA5218BB72100CF713E /* BetaToolsViewModelTests.swift in Sources */,
Expand Down
22 changes: 22 additions & 0 deletions Library/Tracking/AttributionTracking.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Foundation

struct AttributionTracking {
public enum AttributionEvent: String {
case projectPageViewed = "Project Page Viewed"
}

static func eventParametersString(refInfo: RefInfo?) -> String? {
let sessionRefTag = refInfo?.refTag?.stringTag
let contextPageUrl = refInfo?.deeplinkUrl
var props = [String: String]()
if let sessionRefTag {
props["session_ref_tag"] = sessionRefTag
}
props["context_page_url"] = contextPageUrl ?? ""

guard let propsData = try? JSONSerialization.data(withJSONObject: props) else {
return nil
}
return String(data: propsData, encoding: .utf8)
}
}
33 changes: 33 additions & 0 deletions Library/Tracking/AttributionTrackingTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
@testable import Library
import XCTest

final class AttributionTrackingTests: TestCase {
func testParametersString() {
let ref = "test-tag"
let url = "test-url"
let refInfo = RefInfo(RefTag(code: ref), deeplinkUrl: url)

let string = AttributionTracking.eventParametersString(refInfo: refInfo)
let json = self.jsonDict(string!)

XCTAssertEqual(json["session_ref_tag"], ref)
XCTAssertEqual(json["context_page_url"], url)
}

func testParametersString_emptyRefInfo() {
let refInfo = RefInfo(nil)

let string = AttributionTracking.eventParametersString(refInfo: refInfo)
let json = self.jsonDict(string!)

XCTAssertEqual(json["context_page_url"], "")
XCTAssertEqual(json.count, 1) // Json shouldn't contain any other fields.
}

// MARK: - Helpers

private func jsonDict(_ jsonString: String) -> [String: String] {
let data = jsonString.data(using: .utf8)
return try! JSONDecoder().decode([String: String].self, from: data!)
}
}
26 changes: 26 additions & 0 deletions Library/ViewModels/ProjectPageViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,32 @@ public final class ProjectPageViewModel: ProjectPageViewModelType, ProjectPageVi
)
}

// Event attribution tracking
self.configDataProperty.signal
.skipNil()
.combineLatest(with: freshProjectAndRefTag)
.map { projectAndRefInfo, freshProjectAndRefTag in
let (_, refInfo) = projectAndRefInfo
let (project, _) = freshProjectAndRefTag
return (project.graphID, refInfo)
}
.take(first: 1)
.flatMap { graphId, refInfo in
let eventName = AttributionTracking.AttributionEvent.projectPageViewed.rawValue
let propsString = AttributionTracking.eventParametersString(refInfo: refInfo)
let input = GraphAPI.CreateAttributionEventInput(
eventName: eventName,
eventProperties: propsString,
projectId: graphId
)
return AppEnvironment.current.apiService.createAttributionEvent(input: input)
.ksr_delay(AppEnvironment.current.apiDelayInterval, on: AppEnvironment.current.scheduler)
.materialize()
}
.observeCompleted {
// GraphQL mutation only runs if it is observed.
}

Signal.combineLatest(cookieRefTag.skipNil(), freshProjectAndRefTag.map(first))
.take(first: 1)
.map(cookieFrom(refTag:project:))
Expand Down

0 comments on commit 2c8286c

Please sign in to comment.