feat(components): wire checkout analytics events and logging#397
Conversation
Generated by 🚫 Danger Swift against 47ead7c |
There was a problem hiding this comment.
1 issue found.
About Unblocked
Unblocked has been set up to automatically review your team's pull requests to identify genuine bugs and issues.
📖 Documentation — Learn more in our docs.
💬 Ask questions — Mention @unblocked to request a review or summary, or ask follow-up questions.
👍 Give feedback — React to comments with 👍 or 👎 to help us improve.
⚙️ Customize — Adjust settings in your preferences.
Generated by 🚫 Danger Kotlin against 47ead7c |
- guard the outcome effect so a PENDING status is not counted as success - suppress SwiftLint param-count on the sendErrorLog RN bridge method - keep the Android event mapper pure (drop android.util.Log)
| NativeModules: {}, | ||
| Platform, | ||
| StyleSheet, | ||
| TurboModuleRegistry: { get: () => null, getEnforcing: () => ({}) }, |
There was a problem hiding this comment.
Analytics now calls the TurboModule during tests that mount the provider, and the old {} mock left those methods undefined → "not a function". The proxy just makes them no-op promises so a new spec method can't break unrelated suites.
| fun sendLog( | ||
| message: String, | ||
| event: String, | ||
| initDurationMs: Double?, |
There was a problem hiding this comment.
is initDuratin sent on every log? wondering why its not part of the event?
There was a problem hiding this comment.
Agreed — it shouldn't be a dedicated param. I'll move it into a generic log payload so the signature stays clean, but as a follow-up PR since I don't want to hold up the release.
nquinn-primer
left a comment
There was a problem hiding this comment.
Generally ok, just a couple of questions
|
Appetize Android link: https://appetize.io/app/zxhaokn2u2t6idctuzn6jqhqmm |
|
|
Appetize iOS link: https://appetize.io/app/nwly7bbssbd5q32tpmdntmdsbe |




ORC-6501
Wires the core Checkout Components analytics funnel + SDK logs from the RN layer. Calls
PrimerAnalytics.setup()once native init resolves (the bridge was never turned on before — every prior analytics call was a silent no-op), then emits the lifecycle events from the provider/hook layer through the existingcomponents-analyticsbridge, which enriches + sends them taggedsdkType = RN_IOS/RN_ANDROID.What fires when
setup()→SDK_INIT_START→SDK_INIT_END→checkout-initializedinfo log (withinit_duration_ms, measured in TS) →CHECKOUT_FLOW_STARTED.PAYMENT_METHOD_SELECTION(once per method per session).PAYMENT_DETAILS_ENTEREDonce, on the first invalid→valid transition.PAYMENT_SUBMITTED→PAYMENT_PROCESSING_STARTED.PAYMENT_PROCESSING_STARTED(noSUBMITTED— matches Web's wallet sequence).PAYMENT_SUCCESS(+paymentId) orPAYMENT_FAILURE, emitted exactly once per attempt on the null→terminalpaymentOutcometransition.PAYMENT_REATTEMPTEDbefore the next submit.PAYMENT_FLOW_EXITED.checkout-init-failed), payment failure (failed-payment), native-UI present failure (unable-to-present-payment-method).Bridge additions (TS → Kotlin → Swift/ObjC)
sendErrorLog(message, event?, errorMessage?, stack?)across the whole chain;sendLoggains an optionalinitDurationMs.AnalyticsEventMapper:PaymentReattemptednow carriespaymentMethod; unknown event names are debug-logged instead of dropped silently.react-nativeTurboModule mock hardened so new spec methods can't crash suites; newproviderAnalytics.test.tsxcontract suite (8 tests) pins the sequences above. 289 tests green, typecheck + lint clean.Notes for review
paymentId/vaultedMethodId, or a count; every log string is a static message + an SDK-level error description/errorIdor a JS stack. No PAN/CVV/expiry/cardholder path. Emission is fire-and-forget — it never blocks or fails checkout.PrimerCheckoutProvider.tsx— expect a rebase.PAYMENT_THREEDS/PAYMENT_REDIRECT_TO_THIRD_PARTYneed a native→RN flow signal that doesn't exist yet (no mobile SDK emits them). Vault event mappings are the stacked follow-up ORC-6512 — theVAULT_*events already emitted in TS start flowing there, not here.setup()is non-idempotent (overwrites the bridge); harmless as wired (one call per session), flagging for awareness.