Skip to content

Commit 50806e6

Browse files
committed
feat(ramp): add Headless Host + quote-first startHeadlessBuy (Phase 5)
Introduces the Headless Host screen as the stable stack base for the Unified Buy v2 headless flow and switches `startHeadlessBuy` to a quote-first signature so external consumers drive the flow without seeding the RampsController. - New `Routes.RAMP.HEADLESS_HOST` registered inside the Unified Buy v2 inner stack (`TokenListRoutes`) so `useTransakRouting` resets land on the Host instead of BuildQuote. - `useHeadlessBuy.startHeadlessBuy({ quote, ... })` derives the `ContinueWithQuoteContext` from the supplied quote, creates a session in the registry, and navigates into the v2 stack via the proper nested-screen descriptor (TOKEN_SELECTION → MainRoutes → HEADLESS_HOST). - Single-active-session policy: starting a new session auto-`closeSession`s the previous one with `consumer_cancelled`. - `HeadlessHost` orchestrates: on focus it picks up the session, calls `continueWithQuote` exactly once (guarded by `hasContinuedRef` + `session.status` so the OTP/auth loop's re-focuses don't re-trigger), and surfaces `nativeFlowError` from `OtpCode` as `onError({ code: 'AUTH_FAILED' })`. - Native flow screens (`EnterEmail`, `OtpCode`, `VerifyIdentity`) now thread `headlessSessionId` so `useTransakRouting` can be parameterized with `baseRoute = HEADLESS_HOST`. - Playground UI: per-quote "Start headless buy" buttons (standalone start button removed); tapping replaces any active session. - BuildQuote `headlessSessionId` param marked `@deprecated` — the headless flow no longer routes through BuildQuote. Tests: 64 passing across `useHeadlessBuy`, `useContinueWithQuote`, `useTransakRouting`, `HeadlessHost`, and `HeadlessPlayground`.
1 parent eec13f3 commit 50806e6

23 files changed

Lines changed: 1650 additions & 319 deletions

app/components/UI/Ramp/Views/BuildQuote/BuildQuote.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,13 @@ export interface BuildQuoteParams {
9797
/** Pre-fill the amount input (e.g. when restoring state after a navigation reset). */
9898
amount?: number;
9999
/**
100-
* Active headless buy session id, if the screen was opened via
101-
* `useHeadlessBuy().startHeadlessBuy(...)`. Threaded through navigation so
102-
* downstream routing helpers can look up the session in
103-
* `sessionRegistry` and fire the consumer's lifecycle callbacks instead of
104-
* navigating to the order-processing screen.
100+
* Legacy param from Phase 3. The headless flow now navigates straight
101+
* to `Routes.RAMP.HEADLESS_HOST` and never lands on BuildQuote, so the
102+
* field is unused. Kept as `optional` for backward compatibility with
103+
* any in-flight deeplinks; safe to remove once we're sure no callers
104+
* pass it.
105105
*
106-
* Phase 3 only plumbs this param — the screen itself does not branch on
107-
* it yet.
106+
* @deprecated Use `Routes.RAMP.HEADLESS_HOST` instead.
108107
*/
109108
headlessSessionId?: string;
110109
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { StyleSheet } from 'react-native';
2+
import { Theme } from '../../../../../util/theme/models';
3+
4+
const styleSheet = (params: { theme: Theme }) => {
5+
const { theme } = params;
6+
return StyleSheet.create({
7+
container: {
8+
flex: 1,
9+
backgroundColor: theme.colors.background.default,
10+
},
11+
body: {
12+
flex: 1,
13+
alignItems: 'center',
14+
justifyContent: 'center',
15+
paddingHorizontal: 24,
16+
gap: 16,
17+
},
18+
spinner: {
19+
marginBottom: 8,
20+
},
21+
text: {
22+
textAlign: 'center',
23+
},
24+
cancelRow: {
25+
paddingTop: 12,
26+
},
27+
});
28+
};
29+
30+
export default styleSheet;

0 commit comments

Comments
 (0)