@12-apps/payments-frontend 3.23.1 → 3.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@12-apps/payments-frontend",
3
- "version": "3.23.1",
3
+ "version": "3.24.1",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Browser half of the vendor-agnostic payments platform: plug-and-play MUI components for the per-provider settings page (credential form from each provider's schema, masked hints, verify/enable) and the checkout page (PIX QR + polling, card tokenization, hosted-checkout redirect), plus the headless hooks and fetch clients they build on. Talks only to the host's payments HTTP surface — never to a provider directly. Microfrontend-ready: no app coupling, host injects theme and auth.",
@@ -3,9 +3,7 @@ import { useCallback, useEffect, useState, type Dispatch, type SetStateAction }
3
3
  import { buyerGateError } from "./buyer-gate";
4
4
  import type { ConfirmationWait } from "./confirmation-wait";
5
5
  import type { CheckoutDecline } from "./decline";
6
- import { forgetHostedOrder, rememberHostedOrder } from "./hosted-return";
7
- import { parkedBasket, type CheckoutBasketIdentity } from "./basket";
8
- import type { CheckoutNavigate } from "./navigate-context";
6
+ import { forgetHostedOrder } from "./hosted-return";
9
7
  import type { CheckoutScreensCopy } from "./screens-copy";
10
8
  import type {
11
9
  BuyerContact,
@@ -13,8 +11,6 @@ import type {
13
11
  BuyerInfo,
14
12
  CheckoutCustomerField,
15
13
  CheckoutOrder,
16
- CreateOrderRequest,
17
- CreateOrderResult,
18
14
  OrderStatus,
19
15
  PaymentMethod,
20
16
  } from "./types";
@@ -282,106 +278,3 @@ export function useRetryAction(input: {
282
278
  clearError, decline, order, setDecline, setFinalStatus, setFreshInstrument, setOrder, setStep,
283
279
  ]);
284
280
  }
285
-
286
- /**
287
- * Hand the buyer to a redirect provider's own page, if that is where this
288
- * charge settles (FUT-556).
289
- *
290
- * Called BEFORE the order is stored: storing it first would render the PIX or
291
- * card step for a provider that returned neither, which is the dead end this
292
- * fixes.
293
- *
294
- * A full navigation rather than the host's router, because the destination is
295
- * another origin. The return trip comes back to this same checkout route
296
- * carrying `transaction_nsu` + `slug`, which the status poll already reads.
297
- *
298
- * @returns true when the buyer is on their way and the caller must stop.
299
- */
300
- function handOverToProvider(
301
- order: CheckoutOrder,
302
- navigate: CheckoutNavigate,
303
- tenantSlug?: string,
304
- basket?: CheckoutBasketIdentity,
305
- ): boolean {
306
- if (!order.hostedCheckoutUrl) return false;
307
- // PARK FIRST, navigate second. The order is the only thing the return trip
308
- // has to rehydrate from, and the navigation may tear this SPA down before
309
- // any later write lands.
310
- //
311
- // The STORE goes with it: one tab holds one slot, and on a multi-tenant
312
- // storefront every store shares an origin. Without the slug, abandoning this
313
- // hand-off and opening another store's checkout resumed THIS order there.
314
- //
315
- // So does the BASKET (FUT-1213): a hand-off nobody completed must not resume
316
- // itself over the shopper's next basket, and the only way to tell the two
317
- // apart later is to record which basket this one was raised from.
318
- rememberHostedOrder(order, {
319
- tenantSlug,
320
- basket: parkedBasket(basket),
321
- handoff: true,
322
- });
323
- navigate(order.hostedCheckoutUrl);
324
- return true;
325
- }
326
-
327
- /**
328
- * Raise the order for a chosen method, and decide what happens to it.
329
- *
330
- * Three outcomes, in order: a refusal the step renders, a HAND-OFF that leaves
331
- * this page for the provider's own, and an order raised here.
332
- */
333
- export function useStartPayment(input: {
334
- buyer: BuyerInfo;
335
- saveProfile: boolean;
336
- createOrder: (request: CreateOrderRequest) => Promise<CreateOrderResult>;
337
- navigate: CheckoutNavigate;
338
- tenantSlug: string | undefined;
339
- basket: CheckoutBasketIdentity | undefined;
340
- failure: { clear: () => void; fail: (next: { message: string; field?: BuyerField | null; code?: string }) => void };
341
- setCreating: Dispatch<SetStateAction<boolean>>;
342
- setDecline: Dispatch<SetStateAction<CheckoutDecline | null>>;
343
- setOrder: Dispatch<SetStateAction<CheckoutOrder | null>>;
344
- setFinalStatus: Dispatch<SetStateAction<OrderStatus | null>>;
345
- }): (chosen: PaymentMethod, override?: BuyerInfo) => Promise<void> {
346
- const { buyer, saveProfile, createOrder, navigate, tenantSlug, basket, failure } = input;
347
- const { setCreating, setDecline, setOrder, setFinalStatus } = input;
348
- return useCallback(
349
- async (chosen: PaymentMethod, override?: BuyerInfo) => {
350
- failure.clear();
351
- setDecline(null);
352
- // THE CHARGE BEING REPLACED IS DROPPED FIRST (FUT-1170), before the raise
353
- // rather than after it. Raising a payment means whatever was on screen is
354
- // no longer the one being paid, and a provider round trip is long enough
355
- // for the difference to matter: "Gerar novo código" left the expired
356
- // charge mounted, so its own view polled it, got the terminal EXPIRED it
357
- // was always going to get, and bounced the flow to the confirmation
358
- // screen — where the new charge then landed with nothing polling it.
359
- //
360
- // A no-op on every other caller (the auto-raise, the alternate e-mail and
361
- // the retry all run with no order held), which is the point: the clear
362
- // belongs to what raising a payment MEANS, not to the one path that
363
- // noticed.
364
- setOrder(null);
365
- setFinalStatus(null);
366
- setCreating(true);
367
- const result = await createOrder({ method: chosen, buyer: override ?? buyer, saveProfile });
368
- setCreating(false);
369
- if (!result.ok) {
370
- failure.fail(result.error);
371
- return;
372
- }
373
- if (handOverToProvider(result.data, navigate, tenantSlug, basket)) return;
374
- // PARKED EVEN THOUGH NOBODY IS LEAVING (FUT-1140). A low-memory phone
375
- // discards this tab while the shopper is in their bank app, and the SPA
376
- // that comes back has never heard of the order it raised — so the buyer
377
- // meets an empty cart and a retry button instead of the confirmation for
378
- // the payment they just made.
379
- rememberHostedOrder(result.data, { tenantSlug, basket: parkedBasket(basket) });
380
- setOrder(result.data);
381
- },
382
- [
383
- buyer, saveProfile, createOrder, failure, navigate, tenantSlug, basket,
384
- setCreating, setDecline, setOrder, setFinalStatus,
385
- ],
386
- );
387
- }
@@ -7,6 +7,7 @@ import { EmptyCart, PaymentStep } from "./checkout-steps";
7
7
  import { DadosStep } from "./dados-step";
8
8
  import { ArrowBackIcon } from "./icons";
9
9
  import { PaymentStatus } from "./payment-status";
10
+ import type { BackActionEmphasis } from "./payment-status-parts";
10
11
  import type { BuyerInfo, CheckoutProviderConfig, SettlementCheckout } from "./types";
11
12
  import { CheckoutCopyProvider } from "./copy-context";
12
13
  import { OneClickProvider, useOneClick } from "./one-click";
@@ -94,6 +95,10 @@ export interface CheckoutFlowProps extends CheckoutHostPorts {
94
95
  validateApplePayMerchant?: (validationURL: string) => Promise<unknown>;
95
96
  /** Host content shown on the paid confirmation (the storefront's install invite). */
96
97
  confirmationExtra?: ReactNode;
98
+ /** Host content shown AFTER the confirmation's actions — `PaymentStatusProps.paidFooter`. */
99
+ confirmationFooter?: ReactNode;
100
+ /** Whether the way out leads the paid screen — see {@link BackActionEmphasis}. */
101
+ backActionEmphasis?: BackActionEmphasis;
97
102
  /** Design-system slots; unfilled slots render the raw-MUI defaults. */
98
103
  components?: Partial<CheckoutComponents>;
99
104
  }
@@ -180,12 +185,16 @@ function StatusStep({
180
185
  settlement,
181
186
  cart,
182
187
  confirmationExtra,
188
+ confirmationFooter,
189
+ backActionEmphasis,
183
190
  }: {
184
191
  copy: CheckoutViewCopy;
185
192
  c: ReturnType<typeof useCheckoutController>;
186
193
  settlement: SettlementCheckout | null | undefined;
187
194
  cart: CheckoutCartView;
188
195
  confirmationExtra: ReactNode;
196
+ confirmationFooter: ReactNode;
197
+ backActionEmphasis: BackActionEmphasis | undefined;
189
198
  }): JSX.Element {
190
199
  return (
191
200
  <PaymentStatus
@@ -197,6 +206,8 @@ function StatusStep({
197
206
  onRegenerate={() => { c.setStep("payment"); void c.startPayment("PIX"); }}
198
207
  onBackToMenu={c.goToMenu}
199
208
  paidExtra={confirmationExtra}
209
+ paidFooter={confirmationFooter}
210
+ backActionEmphasis={backActionEmphasis}
200
211
  awaitingTimedOut={c.awaitingTimedOut}
201
212
  // How the wait behind this screen is going, and the way out of it
202
213
  // (FUT-1144). It is the resumed leg's wait for a checkout that came back
@@ -297,7 +308,7 @@ function PagamentoStep({
297
308
  }
298
309
 
299
310
  function CheckoutFlowBody(props: Omit<CheckoutFlowProps, "components">): JSX.Element {
300
- const { copy, cart, defaultBuyer, settlement, taxIdOnFile = false, providerConfig, tenantSlug, confirmationExtra, validateApplePayMerchant, oneClick = false, ...ports } = props;
311
+ const { copy, cart, defaultBuyer, settlement, taxIdOnFile = false, providerConfig, tenantSlug, confirmationExtra, confirmationFooter, backActionEmphasis, validateApplePayMerchant, oneClick = false, ...ports } = props;
301
312
  // Resolved for NO method on purpose (FUT-595): the Dados step opens before
302
313
  // the picker, and the form is filled once — so it asks for the union of what
303
314
  // any chain member may need rather than re-opening after the choice. A chain
@@ -354,7 +365,7 @@ function CheckoutFlowBody(props: Omit<CheckoutFlowProps, "components">): JSX.Ele
354
365
  ) : null}
355
366
 
356
367
  {c.step === "status" ? (
357
- <StatusStep copy={copy} c={c} settlement={settlement} cart={cart} confirmationExtra={confirmationExtra} />
368
+ <StatusStep copy={copy} c={c} settlement={settlement} cart={cart} confirmationExtra={confirmationExtra} confirmationFooter={confirmationFooter} backActionEmphasis={backActionEmphasis} />
358
369
  ) : null}
359
370
  </Box>
360
371
  );
@@ -234,6 +234,38 @@ function retryable(decline: CheckoutDecline | null): boolean {
234
234
  return decline?.retriable !== false;
235
235
  }
236
236
 
237
+ /**
238
+ * How much of the eye the way out asks for on a PAID confirmation.
239
+ *
240
+ * `"primary"` is the default and the historical look: back-to-menu is the only
241
+ * control a settled screen carries, so it wears the solid fill. A host that
242
+ * renders an action of its OWN in {@link PaymentStatusProps.paidExtra} — a
243
+ * route to the order it just raised, say — has two controls on one screen, and
244
+ * only one of them may lead. `"secondary"` is how such a host says which.
245
+ *
246
+ * A prop rather than a guess, because the package cannot make it: whether the
247
+ * buyer's next move is "look at the pedido" or "buy something else" is a fact
248
+ * about the way this shop serves people, and nothing in a payment knows it.
249
+ * Every other status is unaffected — an unsettled screen already paints this
250
+ * button as the quiet way out, and the retry beside it is the lead.
251
+ */
252
+ export type BackActionEmphasis = "primary" | "secondary";
253
+
254
+ /**
255
+ * The back-to-menu button's look, from the outcome and the host's emphasis.
256
+ *
257
+ * Its own function so the two attributes cannot disagree: they moved together
258
+ * as a pair of inline ternaries, and a third condition would have made that
259
+ * four places to keep in step.
260
+ */
261
+ function backLook(
262
+ status: OrderStatus,
263
+ emphasis: BackActionEmphasis,
264
+ ): { variant: "solid" | "outline"; color: "primary" | "neutral" } {
265
+ const leads = status === "PAID" && emphasis === "primary";
266
+ return leads ? { variant: "solid", color: "primary" } : { variant: "outline", color: "neutral" };
267
+ }
268
+
237
269
  /** The next-action row: retry / regenerate / check-again, always back-to-menu. */
238
270
  export function StatusActions({
239
271
  copy,
@@ -244,6 +276,7 @@ export function StatusActions({
244
276
  onCheckAgain,
245
277
  onNotPaid,
246
278
  onBackToMenu,
279
+ backActionEmphasis = "primary",
247
280
  }: {
248
281
  copy: PaymentStatusCopy;
249
282
  status: OrderStatus;
@@ -259,8 +292,11 @@ export function StatusActions({
259
292
  /** The buyer's "I did not pay" (FUT-1146) — present only while it applies. */
260
293
  onNotPaid?: () => void;
261
294
  onBackToMenu: () => void;
295
+ /** Whether back-to-menu leads a PAID screen. See {@link BackActionEmphasis}. */
296
+ backActionEmphasis?: BackActionEmphasis;
262
297
  }): JSX.Element {
263
298
  const { Button } = useCheckoutComponents();
299
+ const back = backLook(status, backActionEmphasis);
264
300
  return (
265
301
  <Box sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
266
302
  {onCheckAgain ? (
@@ -298,8 +334,8 @@ export function StatusActions({
298
334
  <Button
299
335
  // Full width and last, so the thumb lands on the same place in every
300
336
  // outcome instead of hunting a button that moves with the state.
301
- variant={status === "PAID" ? "solid" : "outline"}
302
- color={status === "PAID" ? "primary" : "neutral"}
337
+ variant={back.variant}
338
+ color={back.color}
303
339
  size="lg"
304
340
  onClick={onBackToMenu}
305
341
  dataTestId="payment-back-to-menu"
@@ -2,7 +2,13 @@ import { Box } from "@mui/material";
2
2
  import type { JSX, ReactNode } from "react";
3
3
 
4
4
  import type { CheckoutDecline } from "./decline";
5
- import { OutcomeHero, PaidFacts, StatusActions, type WaitState } from "./payment-status-parts";
5
+ import {
6
+ OutcomeHero,
7
+ PaidFacts,
8
+ StatusActions,
9
+ type BackActionEmphasis,
10
+ type WaitState,
11
+ } from "./payment-status-parts";
6
12
  import type { OrderStatus } from "./types";
7
13
  import { useCheckoutComponents } from "./ui";
8
14
  import type { PaymentStatusCopy } from "./view-copy";
@@ -50,6 +56,23 @@ interface PaymentStatusProps {
50
56
  * is the difference between an offer and an interruption.
51
57
  */
52
58
  paidExtra?: ReactNode;
59
+ /**
60
+ * Host content rendered AFTER the action row, and ONLY on PAID.
61
+ *
62
+ * The other half of {@link paidExtra}, and the difference between them is the
63
+ * actions. What a buyer has to DO next belongs beside the way out, in one
64
+ * block: a panel dropped between two controls splits the only decision on the
65
+ * screen in half. What is merely OFFERED — an install invite, an ask to turn
66
+ * on alerts — belongs after that block, because it is about everything that
67
+ * happens once this screen is closed and must not come between a shopper and
68
+ * the order they just paid for.
69
+ */
70
+ paidFooter?: ReactNode;
71
+ /**
72
+ * Whether back-to-menu leads a PAID screen (default) or stands down for an
73
+ * action the host renders in {@link paidExtra}. See {@link BackActionEmphasis}.
74
+ */
75
+ backActionEmphasis?: BackActionEmphasis;
53
76
  /**
54
77
  * The wait has been given up on. Only meaningful while AWAITING_PAYMENT;
55
78
  * every other status has already resolved, so a stale flag cannot change what
@@ -180,7 +203,10 @@ export function PaymentStatus(props: PaymentStatusProps): JSX.Element {
180
203
  onCheckAgain={view.checkAgain}
181
204
  onNotPaid={view.notPaid}
182
205
  onBackToMenu={onBackToMenu}
206
+ backActionEmphasis={props.backActionEmphasis}
183
207
  />
208
+
209
+ {view.paid ? props.paidFooter : null}
184
210
  </Box>
185
211
  );
186
212
  }
@@ -0,0 +1,151 @@
1
+ import { useCallback, type Dispatch, type SetStateAction } from "react";
2
+
3
+ import { parkedBasket, type CheckoutBasketIdentity } from "./basket";
4
+ import type { Step } from "./checkout-actions";
5
+ import type { CheckoutDecline } from "./decline";
6
+ import { rememberHostedOrder } from "./hosted-return";
7
+ import type { CheckoutNavigate } from "./navigate-context";
8
+ import type {
9
+ BuyerField,
10
+ BuyerInfo,
11
+ CheckoutOrder,
12
+ CreateOrderRequest,
13
+ CreateOrderResult,
14
+ OrderStatus,
15
+ PaymentMethod,
16
+ } from "./types";
17
+
18
+ /**
19
+ * RAISING the order, and what becomes of it.
20
+ *
21
+ * Split out of `./checkout-actions.ts` when that file reached its 400-line gate
22
+ * — the same seam it was itself split along. What is here is the one moment the
23
+ * flow asks the host for an order and then has to decide, from the answer
24
+ * alone, which of four things is true: it was refused, it is already finished,
25
+ * it is payable somewhere else, or it is payable here.
26
+ */
27
+
28
+ /**
29
+ * Hand the buyer to a redirect provider's own page, if that is where this
30
+ * charge settles (FUT-556).
31
+ *
32
+ * Called BEFORE the order is stored: storing it first would render the PIX or
33
+ * card step for a provider that returned neither, which is the dead end this
34
+ * fixes.
35
+ *
36
+ * A full navigation rather than the host's router, because the destination is
37
+ * another origin. The return trip comes back to this same checkout route
38
+ * carrying `transaction_nsu` + `slug`, which the status poll already reads.
39
+ *
40
+ * @returns true when the buyer is on their way and the caller must stop.
41
+ */
42
+ function handOverToProvider(
43
+ order: CheckoutOrder,
44
+ navigate: CheckoutNavigate,
45
+ tenantSlug?: string,
46
+ basket?: CheckoutBasketIdentity,
47
+ ): boolean {
48
+ if (!order.hostedCheckoutUrl) return false;
49
+ // PARK FIRST, navigate second. The order is the only thing the return trip
50
+ // has to rehydrate from, and the navigation may tear this SPA down before
51
+ // any later write lands.
52
+ //
53
+ // The STORE goes with it: one tab holds one slot, and on a multi-tenant
54
+ // storefront every store shares an origin. Without the slug, abandoning this
55
+ // hand-off and opening another store's checkout resumed THIS order there.
56
+ //
57
+ // So does the BASKET (FUT-1213): a hand-off nobody completed must not resume
58
+ // itself over the shopper's next basket, and the only way to tell the two
59
+ // apart later is to record which basket this one was raised from.
60
+ rememberHostedOrder(order, {
61
+ tenantSlug,
62
+ basket: parkedBasket(basket),
63
+ handoff: true,
64
+ });
65
+ navigate(order.hostedCheckoutUrl);
66
+ return true;
67
+ }
68
+
69
+ /**
70
+ * Raise the order for a chosen method, and decide what happens to it.
71
+ *
72
+ * FOUR outcomes, in order: a refusal the step renders, an order that came back
73
+ * ALREADY RESOLVED, a HAND-OFF to the provider's own page, and an order raised
74
+ * here to be paid on this one.
75
+ *
76
+ * The resolved case is first because a raise does not always leave something to
77
+ * pay: a host whose buyer spends a stored balance settles a fully covered
78
+ * pedido server-side and answers PAID with no payable at all. That used to fall
79
+ * through and merely `setOrder`, leaving the flow on Pagamento holding a paid
80
+ * pedido — invisible on the PIX/card screen, which polls and resolves itself,
81
+ * and a dead end on the hand-off screen, which polls nothing and so offered a
82
+ * provider a charge that no longer existed. Reading `status` rather than the
83
+ * absence of a payable is what tells that apart from a failed raise.
84
+ */
85
+ export function useStartPayment(input: {
86
+ buyer: BuyerInfo;
87
+ saveProfile: boolean;
88
+ createOrder: (request: CreateOrderRequest) => Promise<CreateOrderResult>;
89
+ navigate: CheckoutNavigate;
90
+ tenantSlug: string | undefined;
91
+ basket: CheckoutBasketIdentity | undefined;
92
+ failure: { clear: () => void; fail: (next: { message: string; field?: BuyerField | null; code?: string }) => void };
93
+ setCreating: Dispatch<SetStateAction<boolean>>;
94
+ setDecline: Dispatch<SetStateAction<CheckoutDecline | null>>;
95
+ setOrder: Dispatch<SetStateAction<CheckoutOrder | null>>;
96
+ setFinalStatus: Dispatch<SetStateAction<OrderStatus | null>>;
97
+ /** Moves the flow to Confirmação for an order that needs no payment. */
98
+ setStep: Dispatch<SetStateAction<Step>>;
99
+ }): (chosen: PaymentMethod, override?: BuyerInfo) => Promise<void> {
100
+ const { buyer, saveProfile, createOrder, navigate, tenantSlug, basket, failure } = input;
101
+ const { setCreating, setDecline, setOrder, setFinalStatus, setStep } = input;
102
+ return useCallback(
103
+ async (chosen: PaymentMethod, override?: BuyerInfo) => {
104
+ failure.clear();
105
+ setDecline(null);
106
+ // THE CHARGE BEING REPLACED IS DROPPED FIRST (FUT-1170), before the raise
107
+ // rather than after it. Raising a payment means whatever was on screen is
108
+ // no longer the one being paid, and a provider round trip is long enough
109
+ // for the difference to matter: "Gerar novo código" left the expired
110
+ // charge mounted, so its own view polled it, got the terminal EXPIRED it
111
+ // was always going to get, and bounced the flow to the confirmation
112
+ // screen — where the new charge then landed with nothing polling it.
113
+ //
114
+ // A no-op on every other caller (the auto-raise, the alternate e-mail and
115
+ // the retry all run with no order held), which is the point: the clear
116
+ // belongs to what raising a payment MEANS, not to the one path that
117
+ // noticed.
118
+ setOrder(null);
119
+ setFinalStatus(null);
120
+ setCreating(true);
121
+ const result = await createOrder({ method: chosen, buyer: override ?? buyer, saveProfile });
122
+ setCreating(false);
123
+ if (!result.ok) {
124
+ failure.fail(result.error);
125
+ return;
126
+ }
127
+ // NOTHING LEFT TO PAY — see the docblock. Parked first for the same
128
+ // reason every other raised order is: the confirmation this is about to
129
+ // show has to survive a tab the phone discards on the way to it.
130
+ if (result.data.status !== "AWAITING_PAYMENT") {
131
+ rememberHostedOrder(result.data, { tenantSlug, basket: parkedBasket(basket) });
132
+ setOrder(result.data);
133
+ setFinalStatus(result.data.status);
134
+ setStep("status");
135
+ return;
136
+ }
137
+ if (handOverToProvider(result.data, navigate, tenantSlug, basket)) return;
138
+ // PARKED EVEN THOUGH NOBODY IS LEAVING (FUT-1140). A low-memory phone
139
+ // discards this tab while the shopper is in their bank app, and the SPA
140
+ // that comes back has never heard of the order it raised — so the buyer
141
+ // meets an empty cart and a retry button instead of the confirmation for
142
+ // the payment they just made.
143
+ rememberHostedOrder(result.data, { tenantSlug, basket: parkedBasket(basket) });
144
+ setOrder(result.data);
145
+ },
146
+ [
147
+ buyer, saveProfile, createOrder, failure, navigate, tenantSlug, basket,
148
+ setCreating, setDecline, setOrder, setFinalStatus, setStep,
149
+ ],
150
+ );
151
+ }
@@ -9,9 +9,9 @@ import {
9
9
  useResumedCheckout,
10
10
  useRetryAction,
11
11
  useSettledPort,
12
- useStartPayment,
13
12
  type Step,
14
13
  } from "./checkout-actions";
14
+ import { useStartPayment } from "./start-payment";
15
15
  import { useConfirmationWait } from "./confirmation-wait";
16
16
  import { useCheckoutCopy } from "./copy-context";
17
17
 
@@ -139,7 +139,7 @@ export function useCheckoutController(
139
139
  });
140
140
  const startPayment = useStartPayment({
141
141
  buyer, saveProfile, createOrder, navigate, tenantSlug, basket, failure,
142
- setCreating, setDecline, setOrder, setFinalStatus,
142
+ setCreating, setDecline, setOrder, setFinalStatus, setStep,
143
143
  });
144
144
  const { payWithEmail, handleResolved } = useResolutionActions({
145
145
  buyer, method, startPayment, setBuyerState, setDecline, setFinalStatus, setStep,
package/src/index.ts CHANGED
@@ -59,6 +59,7 @@ export {
59
59
  type CheckoutCartView,
60
60
  type CheckoutFlowProps,
61
61
  } from './components/checkout/checkout-flow';
62
+ export type { BackActionEmphasis } from './components/checkout/payment-status-parts';
62
63
 
63
64
  // ---------------------------------------------------------------------------
64
65
  // The MOUNTED buyer checkout (FUT-741) and the checkout PIPELINE (FUT-1240).