Skip to content

feat(components): Stripe ACH payment method (ORC-7701)#402

Open
OnurVar wants to merge 5 commits into
ov/feat/componentsfrom
ov/feat/ORC-7701-stripe-ach
Open

feat(components): Stripe ACH payment method (ORC-7701)#402
OnurVar wants to merge 5 commits into
ov/feat/componentsfrom
ov/feat/ORC-7701-stripe-ach

Conversation

@OnurVar

@OnurVar OnurVar commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds the stripeAch kind on Checkout Components: user-details form → native Stripe bank collector → mandate → pending outcome (iOS + Android).
  • New screens: StripeAchUserDetailsScreen (first/last name + email, native per-keystroke validation, keyboard-aware footer + content-fit sheet), StripeAchMandateScreen (accept/decline), PendingScreen (authorized, awaiting settlement).
  • Provider drives the ACH lifecycle (startAch / setAch* / submitAchDetails / acceptAchMandate / declineAchMandate / stopAch); the mandate arrives flow-level via AchMandateTransitioner.
  • Adds the 'pending' payment outcome (ACH authorizes now, settles later) routed to PendingScreen; other methods keep mapping non-FAILED → success.
  • iOS: present the Stripe collector on the top-most VC — the CC sheet is itself a presented modal, so presenting on root failed with "already presenting" and stranded the loader.
  • Shared unwrapNativeError helper normalizes the native { errors: [...] } / { error } envelopes — also applied to the Klarna and bank-redirect managers, which were forwarding bank errors to merchants shapeless.
  • Robustness: startup/submit/mandate failures → error screen (never a stuck spinner); stopAch defers while native work is in flight so a global back can't tear down mid-submit.

Jira

ORC-7701

Test plan

  • yarn typecheck / yarn lint / yarn test green (376 tests)
  • iOS sim: happy path (details → collector → mandate → PENDING → pending screen); vaulted ACH pay completes; decline → returns to list, no error screen; forced startup failure → error screen
  • Android device — not yet verified

Shared native-error unwrap also applied to Klarna and bank-redirect managers.
@OnurVar
OnurVar requested a review from a team as a code owner July 14, 2026 16:02
@github-actions

github-actions Bot commented Jul 14, 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 446be83

@OnurVar OnurVar self-assigned this Jul 14, 2026
@github-actions

github-actions Bot commented Jul 14, 2026

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

Generated by 🚫 Danger Kotlin against 446be83

@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 Outdated
@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown

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

@github-actions

Copy link
Copy Markdown

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

OnurVar added 4 commits July 14, 2026 19:15
Type had a singular error the wire never sends (it sends errors: [...]); read like onInvalid.
Also correct decline/isValid docs and add coverage for the mandate
transitioner, pending outcome routing, and submit-rejection recovery.
@github-actions

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 446be83

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
70.3% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

info.collectorViewController, animated: true, completion: nil)
// Present over the top-most VC — root is already presenting the CC sheet modal.
var presenter = rootViewController
while let presented = presenter.presentedViewController {

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, why while here and not if?

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.

We don't know how many view controllers are presented, or which level our CC sheet itself is mounted at, so instead of assuming one level with if we just walk to the top-most one and present there. Presenting on a VC that's already presenting no-ops anyway.

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