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

Checkout event improvements #813

Merged
merged 10 commits into from
Aug 22, 2019
Merged
Show file tree
Hide file tree
Changes from 9 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
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ public final class ProjectPamphletViewController: UIViewController {
.compactMap { $0 as? ProjectPamphletContentViewController }.first
self.contentController.delegate = self

self.pledgeCTAContainerView.delegate = self

self.viewModel.inputs.initial(topConstraint: self.initialTopConstraint)

self.viewModel.inputs.viewDidLoad()
Expand Down Expand Up @@ -90,10 +92,6 @@ public final class ProjectPamphletViewController: UIViewController {
_ = (self.pledgeCTAContainerView, self.view)
|> ksr_addSubviewToParent()

self.pledgeCTAContainerView.pledgeCTAButton.addTarget(
self, action: #selector(ProjectPamphletViewController.backThisProjectTapped), for: .touchUpInside
)

self.pledgeCTAContainerView.pledgeRetryButton.addTarget(
self, action: #selector(ProjectPamphletViewController.pledgeRetryButtonTapped), for: .touchUpInside
)
Expand Down Expand Up @@ -199,15 +197,17 @@ public final class ProjectPamphletViewController: UIViewController {

// MARK: - Selectors

@objc func backThisProjectTapped() {
self.viewModel.inputs.backThisProjectTapped()
}

@objc func pledgeRetryButtonTapped() {
self.viewModel.inputs.pledgeRetryButtonTapped()
}
}

extension ProjectPamphletViewController: PledgeCTAContainerViewDelegate {
func pledgeCTAButtonTapped() {
self.viewModel.inputs.backThisProjectTapped()
}
}

extension ProjectPamphletViewController: ProjectPamphletContentViewControllerDelegate {
public func projectPamphletContent(
_: ProjectPamphletContentViewController,
Expand Down
20 changes: 20 additions & 0 deletions Kickstarter-iOS/Views/PledgeCTAContainerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import Library
import Prelude
import UIKit

protocol PledgeCTAContainerViewDelegate: AnyObject {
func pledgeCTAButtonTapped()
}

private enum Layout {
enum Button {
static let minHeight: CGFloat = 48.0
Expand Down Expand Up @@ -58,6 +62,8 @@ final class PledgeCTAContainerView: UIView {

private lazy var titleLabel: UILabel = { UILabel(frame: .zero) }()

weak var delegate: PledgeCTAContainerViewDelegate?

private let viewModel: PledgeCTAContainerViewViewModelType = PledgeCTAContainerViewViewModel()

// MARK: - Lifecycle
Expand Down Expand Up @@ -105,6 +111,12 @@ final class PledgeCTAContainerView: UIView {
override func bindViewModel() {
super.bindViewModel()

self.viewModel.outputs.notifyDelegateCTATapped
.observeForUI()
.observeValues { [weak self] in
self?.delegate?.pledgeCTAButtonTapped()
}

self.viewModel.outputs.buttonStyleType
.observeForUI()
.observeValues { [weak self] buttonStyleType in
Expand Down Expand Up @@ -158,6 +170,10 @@ final class PledgeCTAContainerView: UIView {
self.rootStackView
)
|> ksr_addArrangedSubviewsToStackView()

self.pledgeCTAButton.addTarget(
self, action: #selector(self.pledgeCTAButtonTapped), for: .touchUpInside
)
}

private func setupConstraints() {
Expand All @@ -179,6 +195,10 @@ final class PledgeCTAContainerView: UIView {
?|> \.alpha .~ alpha
})
}

@objc func pledgeCTAButtonTapped() {
self.viewModel.inputs.pledgeCTAButtonTapped()
}
}

// MARK: - Styles
Expand Down
22 changes: 18 additions & 4 deletions Library/Koala/Koala.swift
Original file line number Diff line number Diff line change
Expand Up @@ -578,11 +578,25 @@ public final class Koala {

// MARK: - Checkout Events

public func trackBackThisButtonClicked(project: Project, screen: CheckoutContext) {
public func trackBackThisButtonClicked(
stateType: PledgeStateCTAType,
project: Project, screen: CheckoutContext
) {
let props = properties(project: project)
.withAllValuesFrom(["screen": screen.trackingString])

self.track(event: "Back this Project Button Clicked", properties: props)
switch stateType {
case .fix:
self.track(event: "Fix Pledge Button Clicked", properties: props)
case .pledge:
self.track(event: "Back this Project Button Clicked", properties: props)
case .manage:
self.track(event: "Manage Pledge Button Clicked", properties: props)
case .viewBacking:
self.track(event: "View Your Pledge Button Clicked", properties: props)
case .viewRewards:
self.track(event: "View Rewards Button Clicked", properties: props)
}
}

public func trackSelectRewardButtonClicked(
Expand Down Expand Up @@ -1287,7 +1301,7 @@ public final class Koala {

// Deprecated event
self.track(
event: "Project Page",
event: "Project Page Viewed",
properties: props.withAllValuesFrom(deprecatedProps)
)

Expand All @@ -1296,7 +1310,7 @@ public final class Koala {
properties: props.withAllValuesFrom(deprecatedProps)
)

self.track(event: "Project Page Viewed", properties: props)
self.track(event: "Project Page", properties: props)
}

public func trackSwipedProject(_ project: Project, refTag: RefTag?, type: SwipeType) {
Expand Down
4 changes: 2 additions & 2 deletions Library/Koala/KoalaTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ final class KoalaTests: TestCase {

let properties = client.properties.last

XCTAssertEqual("Project Page Viewed", client.events.last)
XCTAssertEqual("Project Page", client.events.last)
XCTAssertEqual(project.stats.backersCount, properties?["project_backers_count"] as? Int)
XCTAssertEqual(project.country.countryCode, properties?["project_country"] as? String)
XCTAssertEqual(project.country.currencyCode, properties?["project_currency"] as? String)
Expand Down Expand Up @@ -475,7 +475,7 @@ final class KoalaTests: TestCase {

let koala = Koala(client: client, loggedInUser: loggedInUser)

koala.trackBackThisButtonClicked(project: project, screen: .projectPage)
koala.trackBackThisButtonClicked(stateType: .pledge, project: project, screen: .projectPage)
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we add tests for the other cases of PledgeStateCTAType?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, will do!


let properties = client.properties.last

Expand Down
23 changes: 23 additions & 0 deletions Library/ViewModels/PledgeCTAContainerViewViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import ReactiveSwift

public protocol PledgeCTAContainerViewViewModelInputs {
func configureWith(value: (projectOrError: Either<Project, ErrorEnvelope>, isLoading: Bool))
func pledgeCTAButtonTapped()
}

public protocol PledgeCTAContainerViewViewModelOutputs {
var activityIndicatorIsHidden: Signal<Bool, Never> { get }
var buttonStyleType: Signal<ButtonStyleType, Never> { get }
var buttonTitleText: Signal<String, Never> { get }
var notifyDelegateCTATapped: Signal<(), Never> { get }
var pledgeCTAButtonIsHidden: Signal<Bool, Never> { get }
var pledgeRetryButtonIsHidden: Signal<Bool, Never> { get }
var spacerIsHidden: Signal<Bool, Never> { get }
Expand Down Expand Up @@ -61,6 +63,8 @@ public final class PledgeCTAContainerViewViewModel: PledgeCTAContainerViewViewMo
isLoading.filter(isFalse).ignoreValues()
)

self.notifyDelegateCTATapped = self.pledgeCTAButtonTappedProperty.signal

self.pledgeRetryButtonIsHidden = inError
.map(isFalse)
.takeWhen(updateButtonStates)
Expand All @@ -81,6 +85,19 @@ public final class PledgeCTAContainerViewViewModel: PledgeCTAContainerViewViewMo
self.titleText = pledgeState.map { $0.titleLabel }.skipNil()
self.subtitleText = Signal.combineLatest(project, pledgeState)
.map(subtitle(project:pledgeState:))

let pledgeTypeAndProject = Signal.combineLatest(pledgeState, project)

// Tracking
pledgeTypeAndProject
.takeWhen(self.pledgeCTAButtonTappedProperty.signal)
.observeValues {
AppEnvironment.current.koala.trackBackThisButtonClicked(
stateType: $0,
project: $1,
screen: .projectPage
)
}
}

fileprivate let projectOrErrorProperty =
Expand All @@ -89,12 +106,18 @@ public final class PledgeCTAContainerViewViewModel: PledgeCTAContainerViewViewMo
self.projectOrErrorProperty.value = value
}

fileprivate let pledgeCTAButtonTappedProperty = MutableProperty(())
public func pledgeCTAButtonTapped() {
self.pledgeCTAButtonTappedProperty.value = ()
}

public var inputs: PledgeCTAContainerViewViewModelInputs { return self }
public var outputs: PledgeCTAContainerViewViewModelOutputs { return self }

public let activityIndicatorIsHidden: Signal<Bool, Never>
public let buttonStyleType: Signal<ButtonStyleType, Never>
public let buttonTitleText: Signal<String, Never>
public let notifyDelegateCTATapped: Signal<Void, Never>
public let pledgeCTAButtonIsHidden: Signal<Bool, Never>
public let pledgeRetryButtonIsHidden: Signal<Bool, Never>
public let spacerIsHidden: Signal<Bool, Never>
Expand Down
17 changes: 17 additions & 0 deletions Library/ViewModels/PledgeCTAContainerViewViewModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ internal final class PledgeCTAContainerViewViewModelTests: TestCase {
let activityIndicatorIsHidden = TestObserver<Bool, Never>()
let buttonStyleType = TestObserver<ButtonStyleType, Never>()
let buttonTitleText = TestObserver<String, Never>()
let notifyDelegateCTATapped = TestObserver<Void, Never>()
let pledgeCTAButtonIsHidden = TestObserver<Bool, Never>()
let pledgeRetryButtonIsHidden = TestObserver<Bool, Never>()
let spacerIsHidden = TestObserver<Bool, Never>()
Expand All @@ -25,6 +26,7 @@ internal final class PledgeCTAContainerViewViewModelTests: TestCase {
self.vm.outputs.activityIndicatorIsHidden.observe(self.activityIndicatorIsHidden.observer)
self.vm.outputs.buttonStyleType.observe(self.buttonStyleType.observer)
self.vm.outputs.buttonTitleText.observe(self.buttonTitleText.observer)
self.vm.outputs.notifyDelegateCTATapped.observe(self.notifyDelegateCTATapped.observer)
self.vm.outputs.pledgeCTAButtonIsHidden.observe(self.pledgeCTAButtonIsHidden.observer)
self.vm.outputs.pledgeRetryButtonIsHidden.observe(self.pledgeRetryButtonIsHidden.observer)
self.vm.outputs.spacerIsHidden.observe(self.spacerIsHidden.observer)
Expand Down Expand Up @@ -167,4 +169,19 @@ internal final class PledgeCTAContainerViewViewModelTests: TestCase {
self.vm.inputs.configureWith(value: (.right(.couldNotParseJSON), false))
self.pledgeRetryButtonIsHidden.assertValues([true, false])
}

func testNotifyDelegateCTATapped() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we add a test to verify that tapping the button triggers the events in Koala?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yup, will do!

let project = Project.template
|> Project.lens.personalization.backing .~ nil
|> Project.lens.personalization.isBacking .~ false

self.notifyDelegateCTATapped.assertDidNotEmitValue()

self.vm.inputs.configureWith(value: (.left(project), false))
self.buttonStyleType.assertValues([ButtonStyleType.green])
self.buttonTitleText.assertValues([Strings.Back_this_project()])

self.vm.inputs.pledgeCTAButtonTapped()
self.notifyDelegateCTATapped.assertValueCount(1)
}
}
7 changes: 0 additions & 7 deletions Library/ViewModels/ProjectPamphletViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,6 @@ public final class ProjectPamphletViewModel: ProjectPamphletViewModelType, Proje
.map(cookieFrom(refTag:project:))
.skipNil()
.observeValues { AppEnvironment.current.cookieStorage.setCookie($0) }

// Tracking
project
.takeWhen(self.backThisProjectTappedProperty.signal)
.observeValues {
AppEnvironment.current.koala.trackBackThisButtonClicked(project: $0, screen: .projectPage)
}
}

private let backThisProjectTappedProperty = MutableProperty(())
Expand Down
14 changes: 7 additions & 7 deletions Library/ViewModels/ProjectPamphletViewModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ final class ProjectPamphletViewModelTests: TestCase {
self.scheduler.advance()

XCTAssertEqual(
["Project Page", "Viewed Project Page", "Project Page Viewed"],
["Project Page Viewed", "Viewed Project Page", "Project Page"],
self.trackingClient.events, "A project page koala event is tracked."
)
XCTAssertEqual(
Expand Down Expand Up @@ -169,8 +169,8 @@ final class ProjectPamphletViewModelTests: TestCase {

XCTAssertEqual(
[
"Project Page", "Viewed Project Page", "Project Page Viewed", "Project Page",
"Viewed Project Page", "Project Page Viewed"
"Project Page Viewed", "Viewed Project Page", "Project Page", "Project Page Viewed",
"Viewed Project Page", "Project Page"
],
self.trackingClient.events, "A project page koala event is tracked."
)
Expand Down Expand Up @@ -279,7 +279,7 @@ final class ProjectPamphletViewModelTests: TestCase {
self.scheduler.advance()

XCTAssertEqual(
["Project Page", "Viewed Project Page", "Project Page Viewed"],
["Project Page Viewed", "Viewed Project Page", "Project Page"],
self.trackingClient.events, "A project page koala event is tracked."
)
XCTAssertEqual(
Expand Down Expand Up @@ -317,8 +317,8 @@ final class ProjectPamphletViewModelTests: TestCase {

XCTAssertEqual(
[
"Project Page", "Viewed Project Page", "Project Page Viewed", "Project Page",
"Viewed Project Page", "Project Page Viewed"
"Project Page Viewed", "Viewed Project Page", "Project Page", "Project Page Viewed",
"Viewed Project Page", "Project Page"
],
self.trackingClient.events, "A project page koala event is tracked."
)
Expand Down Expand Up @@ -688,7 +688,7 @@ final class ProjectPamphletViewModelTests: TestCase {

self.vm.inputs.backThisProjectTapped()
XCTAssertEqual(
["Project Page", "Viewed Project Page", "Project Page Viewed", "Back this Project Button Clicked"],
["Project Page Viewed", "Viewed Project Page", "Project Page"],
client.events
)
}
Expand Down