-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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-727] Send checkout_id with checkout properties for tracking #1053
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to add the id
field to the UpdateBackingMutation
response query - otherwise this change will break all update backing requests because we won't be able to deserialize the response.
Library/StripeTypes.swift
Outdated
@@ -2,11 +2,16 @@ import Foundation | |||
import KsApi | |||
|
|||
public protocol StripeSCARequiring { | |||
var checkoutId: String? { get } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What was the motivation for adding checkoutId
in the StripeSCARequiring
protocol? From my understanding, checkoutId
is not actually required to determine SCA eligibility, so it's a bit misleading to add it in here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd added there to reuse the existing login on the viewModel, but I guess you're right. I will change that.
|
||
return (data.project, data.reward, checkoutPropsData) | ||
} | ||
|
||
self.goToThanks = thanksPageData | ||
.takeWhen(createBackingCompletionEvents) | ||
self.goToThanks = createBackingCompletionEvents |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why was this change needed? From what I can see the way it was before should still work, and is one line of code shorter 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forgot to mention here... using takeWhen
broke some other test and this solution was the one that made all of them pass 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we might want to be pretty specific that this should only fire when the createBackingCompletionEvents
emit 🤔 Do you know what broke/why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed that in some tests, thanksPageData
emits before createBackingCompletionEvents
and in others, like the one I've mentioned, the order changes and the test fails.
Using combineLatest
we don't depend on the order that the signals emit and it avoids a race condition
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's just that combineLatest
will also emit regardless of the order, in this case we just want to be sure that we only goToThanks
when createBackingCompletionEvents
emits. Given that this is tricky to do regression testing on I would try to avoid this change. Let's rather dig into why the tests break with your change? I can take a look with you too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I see what's happening - previously the thanksPageData
had all of the necessary data before the completion events emit. This changes that because now we want the checkoutId
in the ThanksPageData
which causes a bit of a race condition. I would move the creation of the thanksPageData
to be a a signal that is takePairWhen
createBackingCompletionEvents
and retrieve the checkoutId
right at the end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^ +1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another option would be using zip
instead of combineLatest
. This guarantees that goToThanks
only emits after both signals emit. But just for curiosity, what are the disadvantages of using .combineLatest
in this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the concern is that goToThanks
could fire before createBackingCompletionEvents
during a retry flow, causing us to send the user to thanks page before we've confirmed that we're clear to do so, particularly during the SCA flow. We might be prematurely sending users to the thanks page before they've completed the SCA auth flow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what are the disadvantages of using .combineLatest in this case?
I think the main concern is just that it doesn't accurately represent what we want to happen. Previously this was a takeWhen
because that accurately describes the event, "take this data when this other thing happens". This has changed because we now require some data from the thing that has happened, but takePairWhen
accurately describes that - "take some data from this other event, combine it with what we have, but only when that other thing happens". combineLatest
on the other hand blurs this by saying "combine all this data when either of these things happen".
@@ -7,6 +7,7 @@ final class UpdateBackingEnvelopeTests: XCTestCase { | |||
{ | |||
"updateBacking": { | |||
"checkout": { | |||
"id": "2020", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the UpdateBackingEnvelope
now requires a checkoutId
to be present for deserialization, you'll need to also add it to the UpdateBackingMutation
as well so that deserialization doesn't break for update backing.
…StripeSCARequiring protocol
…ithub.com/kickstarter/ios-oss into NT-727_createBacking_mutation_checkout_id
@@ -352,7 +352,7 @@ public class PledgeViewModel: PledgeViewModelType, PledgeViewModelInputs, Pledge | |||
.switchMap { input in | |||
AppEnvironment.current.apiService.updateBacking(input: input) | |||
.ksr_delay(AppEnvironment.current.apiDelayInterval, on: AppEnvironment.current.scheduler) | |||
.map { $0 as StripeSCARequiring } | |||
.map { ($0.updateBacking.checkout.id, $0 as StripeSCARequiring) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to map out the checkout id in the updateBacking
case? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because createOrUpdateEvent
requires that createBackingEvents
and updateBackingEvents
have the same type (<(String, StripeSCARequiring), GraphError>.Event>) . So I saw some options here:
1- map out checkout id even if we won't use it
2- make the string of the tuple optional in both createBackingEvents
and updateBackingEvents
signals
Tried other solutions but wasn't able to make the compiler happy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I think just mapping the value in createOrUpdateEvent
seems to work and doesn't require mapping out the checkoutId
in the update events:
let createOrUpdateEvent = Signal.merge(
createBackingEvents.map { $0.map(second) },
updateBackingEvents
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know why I didn't think of that 🤦🏻♂️ Thanks, @ifbarrera !
|
||
return (data.project, data.reward, checkoutPropsData) | ||
} | ||
|
||
self.goToThanks = thanksPageData | ||
.takeWhen(createBackingCompletionEvents) | ||
self.goToThanks = createBackingCompletionEvents |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^ +1
@@ -352,7 +352,7 @@ public class PledgeViewModel: PledgeViewModelType, PledgeViewModelInputs, Pledge | |||
.switchMap { input in | |||
AppEnvironment.current.apiService.updateBacking(input: input) | |||
.ksr_delay(AppEnvironment.current.apiDelayInterval, on: AppEnvironment.current.scheduler) | |||
.map { $0 as StripeSCARequiring } | |||
.map { ($0.updateBacking.checkout.id, $0 as StripeSCARequiring) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I think just mapping the value in createOrUpdateEvent
seems to work and doesn't require mapping out the checkoutId
in the update events:
let createOrUpdateEvent = Signal.merge(
createBackingEvents.map { $0.map(second) },
updateBackingEvents
)
@@ -867,6 +882,7 @@ private func checkoutPropertiesData(from createBackingData: CreateBackingData, i | |||
|
|||
return Koala.CheckoutPropertiesData( | |||
amount: amount, | |||
checkoutId: checkoutId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While testing this I noticed that the checkoutId
that's returned from Graph is the relayId
. I think for tracking we actually want to send the Int
value of the checkoutId
🤔
.map { data, isApplePay -> ThanksPageData in | ||
let checkoutPropsData = checkoutPropertiesData(from: data, isApplePay: isApplePay) | ||
.takeWhen(createBackingCompletionEvents) | ||
.combineLatest(with: checkoutId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this change is actually the same thing as before, although we've moved things around this still combines the latest emissions from the two signals. Basically it reads like this "emit createBackingDataAndIsApplePay
when createBackingCompletionEvents
emits and combine its emission with checkoutId
" which means that whenever checkoutId
or createBackingCompletionEvents
emit then this will emit. We just want to be explicit that this should only emit at all when createBackingCompletionEvents
emits.
This is actually achievable just by moving things around slightly and carrying the checkoutId
all the way through to createBackingCompletionEvents
which will require a few changes higher up in the chain:
let thanksPageData = createBackingDataAndIsApplePay
.takePairWhen(createBackingCompletionEvents)
.map(unpack)
.map { data, isApplePay, checkoutId -> ThanksPageData in
let checkoutPropsData = checkoutPropertiesData(
from: data,
checkoutId: checkoutId,
isApplePay: isApplePay
)
return (data.project, data.reward, checkoutPropsData)
}
📲 What
checkout_id
property to the checkout properties group.🤔 Why
For details: JIRA ticket
Note: Even though the ticket determines that all tracking events that require the checkout properties should contain this property, this is not applicable, since some of them will fire before the backing is created.
🛠 How
createBacking
mutation to return checkout_idcheckoutId
property on Checkout modelcheckoutPropertiesData
function now receives an optionalcheckoutId
as argument✅ Acceptance criteria
Thanks Page Viewed
event should contain thecheckout_id
property.