Skip to content

feat(components): wire checkout analytics events and logging#397

Merged
OnurVar merged 3 commits into
ov/feat/componentsfrom
ov/feat/ORC-6501-cc-analytics
Jul 3, 2026
Merged

feat(components): wire checkout analytics events and logging#397
OnurVar merged 3 commits into
ov/feat/componentsfrom
ov/feat/ORC-6501-cc-analytics

Conversation

@OnurVar

@OnurVar OnurVar commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

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 existing components-analytics bridge, which enriches + sends them tagged sdkType = RN_IOS/RN_ANDROID.

What fires when

  • On checkout ready: setup()SDK_INIT_STARTSDK_INIT_ENDcheckout-initialized info log (with init_duration_ms, measured in TS) → CHECKOUT_FLOW_STARTED.
  • Method pick: PAYMENT_METHOD_SELECTION (once per method per session).
  • Card form: PAYMENT_DETAILS_ENTERED once, on the first invalid→valid transition.
  • Card / vault submit: PAYMENT_SUBMITTEDPAYMENT_PROCESSING_STARTED.
  • Wallet / native-UI handoff: PAYMENT_PROCESSING_STARTED (no SUBMITTED — matches Web's wallet sequence).
  • Terminal outcome (single choke point): PAYMENT_SUCCESS (+paymentId) or PAYMENT_FAILURE, emitted exactly once per attempt on the null→terminal paymentOutcome transition.
  • Retry after failure: PAYMENT_REATTEMPTED before the next submit.
  • Session ends without a completed payment: PAYMENT_FLOW_EXITED.
  • Error logs: init failure (checkout-init-failed), payment failure (failed-payment), native-UI present failure (unable-to-present-payment-method).

Bridge additions (TS → Kotlin → Swift/ObjC)

  • New sendErrorLog(message, event?, errorMessage?, stack?) across the whole chain; sendLog gains an optional initDurationMs.
  • AnalyticsEventMapper: PaymentReattempted now carries paymentMethod; unknown event names are debug-logged instead of dropped silently.
  • Jest: global react-native TurboModule mock hardened so new spec methods can't crash suites; new providerAnalytics.test.tsx contract suite (8 tests) pins the sequences above. 289 tests green, typecheck + lint clean.

Notes for review

  • No card data in telemetry: every event value is a payment-method type, an opaque paymentId/vaultedMethodId, or a count; every log string is a static message + an SDK-level error description/errorId or a JS stack. No PAN/CVV/expiry/cardholder path. Emission is fire-and-forget — it never blocks or fails checkout.
  • Native dependency: builds locally against the sibling SDKs; the version bumps land when the native betas cut from primer-io/primer-sdk-android#1283 and feat: Add vault analytics events and error logging (CheckoutComponents) primer-sdk-ios#1825 publish. Do not merge before those.
  • Heads-up (rebase): the open stacked PRs feat(components): bank-selection redirect methods (ORC-6514) #393feat(components): Klarna payment component (ORC-6515) #396 and umbrella feat: Checkout Components #331 also touch PrimerCheckoutProvider.tsx — expect a rebase.
  • Deferred: PAYMENT_THREEDS / PAYMENT_REDIRECT_TO_THIRD_PARTY need 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 — the VAULT_* events already emitted in TS start flowing there, not here.
  • Minor design note: native setup() is non-idempotent (overwrites the bridge); harmless as wired (one call per session), flagging for awareness.

@OnurVar
OnurVar requested a review from a team as a code owner July 2, 2026 13:38
@OnurVar OnurVar self-assigned this Jul 2, 2026
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Warnings
⚠️ This PR doesn't seem to contain any updated Unit Test for Swift 🤔. Please consider double checking it 🙏
Messages
📖 ✅ No SwiftLint violations found.

Generated by 🚫 Danger Swift against 47ead7c

@unblocked unblocked Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Comment thread src/Components/PrimerCheckoutProvider.tsx
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Messages
📖 ✅ No detekt violations found.

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)
Comment thread __mocks__/react-native.js
NativeModules: {},
Platform,
StyleSheet,
TurboModuleRegistry: { get: () => null, getEnforcing: () => ({}) },

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

curious what drives this change?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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?,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

is initDuratin sent on every log? wondering why its not part of the event?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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 nquinn-primer left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Generally ok, just a couple of questions

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Warnings
⚠️ Pull Request size seems relatively large. If this Pull Request contains multiple changes, please split each into separate PRs for a faster, easier review.
Messages
📖 ✅ No ESLint violations found.

Generated by 🚫 dangerJS against 47ead7c

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown

Appetize Android link: https://appetize.io/app/zxhaokn2u2t6idctuzn6jqhqmm

@sonarqubecloud

sonarqubecloud Bot commented Jul 3, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown

Appetize iOS link: https://appetize.io/app/nwly7bbssbd5q32tpmdntmdsbe

@OnurVar
OnurVar merged commit c2c5ce5 into ov/feat/components Jul 3, 2026
28 of 30 checks passed
@OnurVar
OnurVar deleted the ov/feat/ORC-6501-cc-analytics branch July 3, 2026 12:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants