@12-apps/payments-frontend 3.37.0 → 3.38.0

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.
Files changed (33) hide show
  1. package/package.json +1 -1
  2. package/src/components/checkout/card-sources.ts +131 -0
  3. package/src/components/checkout/card-view.tsx +6 -2
  4. package/src/components/checkout/cart-changed.tsx +26 -15
  5. package/src/components/checkout/checkout-actions.ts +18 -0
  6. package/src/components/checkout/checkout-flow.tsx +24 -77
  7. package/src/components/checkout/google-pay-button.tsx +4 -4
  8. package/src/components/checkout/list/buyer-inline.tsx +125 -0
  9. package/src/components/checkout/list/charge-runners.tsx +156 -0
  10. package/src/components/checkout/list/choice-list.tsx +156 -0
  11. package/src/components/checkout/list/choice.ts +193 -0
  12. package/src/components/checkout/list/context.tsx +55 -0
  13. package/src/components/checkout/list/en-US.ts +61 -0
  14. package/src/components/checkout/list/list-bar.tsx +186 -0
  15. package/src/components/checkout/list/list-face.tsx +315 -0
  16. package/src/components/checkout/list/list-pix.tsx +206 -0
  17. package/src/components/checkout/list/online-content.tsx +137 -0
  18. package/src/components/checkout/list/option-row.tsx +123 -0
  19. package/src/components/checkout/list/payment-list-step.tsx +166 -0
  20. package/src/components/checkout/list/pt-BR.ts +77 -0
  21. package/src/components/checkout/list/types.ts +187 -0
  22. package/src/components/checkout/list/use-capability.ts +53 -0
  23. package/src/components/checkout/list/use-list-charge.ts +161 -0
  24. package/src/components/checkout/list/use-list-state.ts +152 -0
  25. package/src/components/checkout/payment-phase.tsx +119 -0
  26. package/src/components/checkout/pix-parts.tsx +3 -0
  27. package/src/components/checkout/pix-view.tsx +53 -20
  28. package/src/components/checkout/use-card-checkout.ts +11 -78
  29. package/src/components/checkout/use-checkout-controller.ts +3 -1
  30. package/src/flows/create-payment-flows.tsx +7 -0
  31. package/src/flows/types.ts +7 -0
  32. package/src/index.ts +4 -5
  33. package/src/locales.ts +13 -0
@@ -0,0 +1,119 @@
1
+ import type { JSX } from "react";
2
+
3
+ import type { CheckoutCartView, CheckoutFlowProps } from "./checkout-flow";
4
+ import { PaymentStep } from "./checkout-steps";
5
+ import { PaymentListStep } from "./list/payment-list-step";
6
+ import { OneClickProvider } from "./one-click";
7
+ import type { CheckoutProviderConfig, SettlementCheckout } from "./types";
8
+ import type { useCheckoutController } from "./use-checkout-controller";
9
+
10
+ /**
11
+ * Step 2 of `<CheckoutFlow>`, moved out of `./checkout-flow.tsx` at its size
12
+ * gate when the Pagamento step gained a second shape (FUT-3591): the method
13
+ * tabs it always had, or the one list a host opts into.
14
+ */
15
+
16
+ /** The pay-bar total override when settling a settlement (else the cart's own totals). */
17
+ export function settlementTotalOverride(
18
+ settlement: SettlementCheckout | null | undefined,
19
+ ): { label: string; items: number } | undefined {
20
+ return settlement ? { label: settlement.totalLabel, items: settlement.totalItems } : undefined;
21
+ }
22
+
23
+ /** Step 2, with the controller's facts and the host's money mapped onto it. */
24
+ function PagamentoStep({
25
+ c,
26
+ cart,
27
+ settlement,
28
+ providerConfig,
29
+ tenantSlug,
30
+ validateApplePayMerchant,
31
+ }: {
32
+ c: ReturnType<typeof useCheckoutController>;
33
+ cart: CheckoutCartView;
34
+ settlement: SettlementCheckout | null | undefined;
35
+ providerConfig: CheckoutProviderConfig | null | undefined;
36
+ tenantSlug: string | undefined;
37
+ validateApplePayMerchant: ((validationURL: string) => Promise<unknown>) | undefined;
38
+ }): JSX.Element {
39
+ return (
40
+ <PaymentStep
41
+ method={c.method}
42
+ onMethodChange={c.setMethod}
43
+ order={c.order}
44
+ buyer={c.buyer}
45
+ creating={c.creating}
46
+ createError={c.createError}
47
+ errorField={c.errorField}
48
+ errorCode={c.errorCode}
49
+ onGenerate={(chosen) => void c.startPayment(chosen)}
50
+ refresh={c.refresh}
51
+ onUseEmail={c.payWithEmail}
52
+ // Set only for a skipped-Dados flow (the controller decides); the payer
53
+ // block hides itself when it is absent.
54
+ onEditBuyer={c.editBuyer}
55
+ providerConfig={providerConfig}
56
+ tenantSlug={tenantSlug}
57
+ // The amount, on the step that asks for it (FUT-1179).
58
+ cartTotals={cart}
59
+ totalOverride={settlementTotalOverride(settlement)}
60
+ discountLines={cart.discountLines}
61
+ // The order around the payment, for the summary (FUT-3525).
62
+ lines={cart.lines}
63
+ delivery={cart.delivery}
64
+ orderNote={cart.orderNote}
65
+ // Retrying a refused card: the failed saved card is not chosen again (FUT-1145).
66
+ freshInstrument={c.freshInstrument}
67
+ // The card path parks an order of its own for a 3-D Secure challenge, so
68
+ // it needs the same basket the flow was mounted for (FUT-1213).
69
+ basket={cart.identity}
70
+ validateApplePayMerchant={validateApplePayMerchant}
71
+ onResolved={c.handleResolved}
72
+ />
73
+ );
74
+ }
75
+
76
+ /**
77
+ * Step 2, in whichever shape the host asked for: the one list, or the tabs.
78
+ * The list never arms one-click — it raises nothing on its own, which is the
79
+ * one-click request's ordinary degraded outcome anyway.
80
+ */
81
+ export function PaymentPhase({
82
+ props,
83
+ c,
84
+ armed,
85
+ }: {
86
+ props: Omit<CheckoutFlowProps, "components">;
87
+ c: ReturnType<typeof useCheckoutController>;
88
+ armed: boolean;
89
+ }): JSX.Element {
90
+ const { cart, settlement, providerConfig, tenantSlug, validateApplePayMerchant, paymentList } = props;
91
+ if (paymentList) {
92
+ return (
93
+ <PaymentListStep
94
+ c={c}
95
+ list={paymentList}
96
+ cart={cart}
97
+ totalOverride={settlementTotalOverride(settlement)}
98
+ providerConfig={providerConfig}
99
+ tenantSlug={tenantSlug}
100
+ taxIdOnFile={props.taxIdOnFile ?? false}
101
+ defaultBuyer={props.defaultBuyer}
102
+ saveBuyerContact={props.saveBuyerContact}
103
+ consentLabel={props.copy.dados.saveProfile}
104
+ />
105
+ );
106
+ }
107
+ return (
108
+ <OneClickProvider armed={armed}>
109
+ <PagamentoStep
110
+ c={c}
111
+ cart={cart}
112
+ settlement={settlement}
113
+ providerConfig={providerConfig}
114
+ tenantSlug={tenantSlug}
115
+ validateApplePayMerchant={validateApplePayMerchant}
116
+ />
117
+ </OneClickProvider>
118
+ );
119
+ }
@@ -105,6 +105,9 @@ export function StaleVeil({ stale, children }: { stale: boolean; children: React
105
105
  >
106
106
  <Box
107
107
  component="p"
108
+ // An opaque overlay over the blurred code (ADR 0121): it covers
109
+ // what is under it on purpose, so the review probe reads it so.
110
+ data-ui-overlay=""
108
111
  sx={{
109
112
  m: 0,
110
113
  px: 1.5,
@@ -2,6 +2,8 @@ import { Box } from "@mui/material";
2
2
  import { useEffect, useMemo, useRef, type JSX } from "react";
3
3
 
4
4
  import { useCheckoutCopy } from "./copy-context";
5
+ import { usePaymentListMode } from "./list/context";
6
+ import { ListPixFace } from "./list/list-pix";
5
7
  import { PixAfterCopy } from "./pix-after-copy";
6
8
  import { PixPane } from "./pix-pane";
7
9
  import { useCheckoutLayout } from "./payment-step-layout";
@@ -221,15 +223,19 @@ function PixTitle(): JSX.Element | null {
221
223
  );
222
224
  }
223
225
 
224
- function PixBody({ order, pix, poll }: { order: CheckoutOrder; pix: PixCharge; poll: ReturnType<typeof usePixPolling> }): JSX.Element {
225
- const copy = useCheckoutCopy().screens.pix;
226
- const stage = usePixStage();
227
- const { copy: writeClipboard, justCopied } = useClipboardCopy(pix.copyPaste);
228
- // Leaving the payment step (a method switch, a terminal status) ends the
229
- // after-copy face with it: the next pane starts on the code.
230
- const { setAfterCopy } = stage;
231
- // A clipboard write that settles after the pane is gone must not reopen the
232
- // after-copy face over whatever replaced it (it would hide the picker).
226
+ /**
227
+ * The clipboard, and the copy that moves the pane on to its after-copy face.
228
+ *
229
+ * Leaving the payment step (a method switch, a terminal status) ends the
230
+ * after-copy face with it: the next pane starts on the code. And a clipboard
231
+ * write that settles after the pane is gone must not reopen the after-copy
232
+ * face over whatever replaced it (it would hide the picker).
233
+ */
234
+ function useCopyThenWait(
235
+ payload: string,
236
+ setAfterCopy: (afterCopy: boolean) => void,
237
+ ): { writeClipboard: () => Promise<boolean>; justCopied: boolean; copyThenWait: () => void } {
238
+ const { copy: writeClipboard, justCopied } = useClipboardCopy(payload);
233
239
  const mounted = useRef(true);
234
240
  useEffect(() => {
235
241
  mounted.current = true;
@@ -238,6 +244,22 @@ function PixBody({ order, pix, poll }: { order: CheckoutOrder; pix: PixCharge; p
238
244
  setAfterCopy(false);
239
245
  };
240
246
  }, [setAfterCopy]);
247
+ // Only a copy the clipboard TOOK moves on: the next face opens on "Código
248
+ // Pix copiado", and a failed write leaves the code on screen to select by hand.
249
+ const copyThenWait = (): void => {
250
+ void writeClipboard().then((ok) => {
251
+ if (ok && mounted.current) setAfterCopy(true);
252
+ });
253
+ };
254
+ return { writeClipboard, justCopied, copyThenWait };
255
+ }
256
+
257
+ function PixBody({ order, pix, poll }: { order: CheckoutOrder; pix: PixCharge; poll: ReturnType<typeof usePixPolling> }): JSX.Element {
258
+ const copy = useCheckoutCopy().screens.pix;
259
+ const stage = usePixStage();
260
+ const listMode = usePaymentListMode();
261
+ const { writeClipboard, justCopied, copyThenWait } = useCopyThenWait(pix.copyPaste, stage.setAfterCopy);
262
+ const { setAfterCopy } = stage;
241
263
 
242
264
  // The locale is the HOST's (FUT-760): it decides what a buyer reads off the
243
265
  // clock, so it travels with the sentence it feeds rather than being frozen
@@ -247,6 +269,27 @@ function PixBody({ order, pix, poll }: { order: CheckoutOrder; pix: PixCharge; p
247
269
  const footerLine = (awaiting: string): JSX.Element => (
248
270
  <PixPollFooter error={poll.error} timedOut={poll.timedOut} onCheckAgain={poll.checkAgain} awaiting={awaiting} />
249
271
  );
272
+ // Inside the one list (FUT-3592), the code itself is the pane and the bar
273
+ // carries the copy; the wait is said by the bar, so only a STALLED poll
274
+ // draws here.
275
+ if (listMode) {
276
+ return (
277
+ <ListPixFace
278
+ mode={listMode}
279
+ order={order}
280
+ pix={pix}
281
+ time={time}
282
+ afterCopy={stage.afterCopy}
283
+ words={sentences.afterCopy}
284
+ justCopied={justCopied}
285
+ onCopy={copyThenWait}
286
+ onCopyAgain={() => void writeClipboard()}
287
+ onShowQr={() => setAfterCopy(false)}
288
+ onPreferCard={stage.preferCard}
289
+ footer={poll.error || poll.timedOut ? footerLine(copy.verifying) : null}
290
+ />
291
+ );
292
+ }
250
293
 
251
294
  if (stage.afterCopy) {
252
295
  return (
@@ -267,17 +310,7 @@ function PixBody({ order, pix, poll }: { order: CheckoutOrder; pix: PixCharge; p
267
310
  return (
268
311
  <>
269
312
  <PixTitle />
270
- <PixPane
271
- pix={pix}
272
- onCopy={() => {
273
- // Only a copy the clipboard TOOK moves on: the next face opens on
274
- // "Código Pix copiado", and a failed write leaves the code on screen
275
- // to select by hand.
276
- void writeClipboard().then((ok) => {
277
- if (ok && mounted.current) setAfterCopy(true);
278
- });
279
- }}
280
- />
313
+ <PixPane pix={pix} onCopy={copyThenWait} />
281
314
  <PixFooter deadline={sentences.validUntil(time)}>{footerLine(sentences.awaiting)}</PixFooter>
282
315
  </>
283
316
  );
@@ -4,7 +4,6 @@ import {
4
4
  NEW_CARD,
5
5
  detectBrand,
6
6
  onlyDigits,
7
- tokenizerFor,
8
7
  validateCardNumber,
9
8
  validateCvv,
10
9
  validateExpiry,
@@ -23,6 +22,7 @@ import {
23
22
  type RefreshBrowserKey,
24
23
  } from "./card-instruments";
25
24
  import { handOverToChallenge, reportResolved, type ChallengeScope } from "./card-outcome";
25
+ import { useCardPublicKey, useSavedCards } from "./card-sources";
26
26
  import { useCheckoutClientApi } from "./client-context";
27
27
  import { useCheckoutNavigate } from "./navigate-context";
28
28
  import type { CardChainLink } from "./method-capability";
@@ -34,80 +34,6 @@ import { useCheckoutCopy } from "./copy-context";
34
34
 
35
35
  const EMPTY_CARD: CardDetails = { number: "", holder: "", expiry: "", cvv: "" };
36
36
 
37
- /**
38
- * Saved-card list + current selection, loaded once on mount — scoped to the
39
- * current store (FUT-697), so only cards the store's active provider can
40
- * actually charge are offered. The slug arrives as an argument (the host's
41
- * routing owns it); absent, the list is unscoped, exactly as before FUT-697.
42
- */
43
- function useSavedCards(
44
- tenantSlug: string | undefined,
45
- /**
46
- * The buyer is here because a card was REFUSED (FUT-1145), so the saved card
47
- * this would otherwise preselect is the one that just failed. The list is
48
- * still offered — another saved card may well work — but nothing is chosen
49
- * for them, which puts the form in front of a buyer whose only untried
50
- * instrument is a new one.
51
- */
52
- freshInstrument: boolean,
53
- ): {
54
- savedCards: SavedCard[];
55
- selection: string;
56
- setSelection: (id: string) => void;
57
- } {
58
- const [savedCards, setSavedCards] = useState<SavedCard[]>([]);
59
- const [selection, setSelection] = useState<string>(NEW_CARD);
60
- const client = useCheckoutClientApi();
61
-
62
- useEffect(() => {
63
- let active = true;
64
- void client.listInstruments(tenantSlug).then((cards) => {
65
- if (!active) return;
66
- setSavedCards(cards);
67
- const first = cards[0];
68
- if (first && !freshInstrument) setSelection(first.id);
69
- });
70
- return () => {
71
- active = false;
72
- };
73
- }, [tenantSlug, client, freshInstrument]);
74
-
75
- return { savedCards, selection, setSelection };
76
- }
77
-
78
- /**
79
- * The store's card public key for this order. The checkout config resolved the
80
- * initial key server-side (`GET /api/checkout/config`, FUT-697); the SPA
81
- * fetches through the order-scoped refresh route only when the ACTIVE provider
82
- * is PagBank — the sole provider that can mint a key on demand — and the
83
- * config arrived without one. A `null` key never means "mock": stub permission
84
- * travels separately as `mockTokenization`.
85
- */
86
- function useCardPublicKey(
87
- orderId: string,
88
- config: CardTokenizationConfig,
89
- ): {
90
- publicKey: string | null;
91
- setPublicKey: (key: string) => void;
92
- } {
93
- const [publicKey, setPublicKey] = useState<string | null>(config.publicKey);
94
- const client = useCheckoutClientApi();
95
- const refreshable =
96
- config.provider !== null && tokenizerFor(config.provider) === "pagbank-sdk";
97
-
98
- useEffect(() => {
99
- if (config.publicKey !== null || !refreshable) return undefined;
100
- let active = true;
101
- void client.refreshBrowserKey({ orderId }).then((result) => {
102
- if (active && result.ok && result.data.publicKey) setPublicKey(result.data.publicKey);
103
- });
104
- return () => {
105
- active = false;
106
- };
107
- }, [orderId, config.publicKey, refreshable, client]);
108
-
109
- return { publicKey, setPublicKey };
110
- }
111
37
 
112
38
  /** Everything the card view renders — all checkout state + the submit handler. */
113
39
  export interface CardCheckout {
@@ -137,6 +63,12 @@ export interface CardCheckout {
137
63
  pollTimedOut: boolean;
138
64
  /** Ask now and restart the wait — the buyer's "verificar de novo". */
139
65
  pollCheckAgain: () => void;
66
+ /**
67
+ * The order-scoped key refresh has not answered yet (`./card-sources.ts`): a
68
+ * charge started now would tokenize a new card with no key. A screen that
69
+ * starts the charge itself waits for this to clear.
70
+ */
71
+ keyPending: boolean;
140
72
  handlePay: () => Promise<void>;
141
73
  }
142
74
 
@@ -160,6 +92,7 @@ type CardSubmit = Pick<
160
92
  | "pollError"
161
93
  | "pollTimedOut"
162
94
  | "pollCheckAgain"
95
+ | "keyPending"
163
96
  | "handlePay"
164
97
  >;
165
98
 
@@ -246,7 +179,7 @@ function useCardWait(
246
179
  * poll for the async confirmation, bubbling the terminal status up via
247
180
  * {@link onResolved}.
248
181
  */
249
- function useCardSubmit(
182
+ export function useCardSubmit(
250
183
  order: CheckoutOrder,
251
184
  buyer: BuyerInfo,
252
185
  providerConfig: CardTokenizationConfig,
@@ -264,7 +197,7 @@ function useCardSubmit(
264
197
  const [errorCode, setErrorCode] = useState<string | null>(null);
265
198
  // The active key: resolved by the checkout config, overridden by the
266
199
  // rotated-key self-heal for the rest of the session.
267
- const { publicKey, setPublicKey } = useCardPublicKey(order.orderId, providerConfig);
200
+ const { publicKey, setPublicKey, keyPending } = useCardPublicKey(order.orderId, providerConfig);
268
201
  const client = useCheckoutClientApi();
269
202
  const navigate = useCheckoutNavigate();
270
203
  const cardCopy = useCheckoutCopy().card;
@@ -323,7 +256,7 @@ function useCardSubmit(
323
256
  else setSubmitted(true);
324
257
  };
325
258
 
326
- return { submitting, submitted, error, errorCode, ...wait, handlePay };
259
+ return { submitting, submitted, error, errorCode, ...wait, keyPending, handlePay };
327
260
  }
328
261
 
329
262
  /**
@@ -5,6 +5,7 @@ import {
5
5
  resumeSurface,
6
6
  useCheckoutNav,
7
7
  useCreateFailure,
8
+ useDropOrder,
8
9
  useGoToPayment,
9
10
  useResumedCheckout,
10
11
  useRetryAction,
@@ -135,6 +136,7 @@ export function useCheckoutController(
135
136
  return next;
136
137
  });
137
138
  }, [clearError, tenantSlug]);
139
+ const dropOrder = useDropOrder(setOrder, tenantSlug, clearError);
138
140
  const goToPayment = useGoToPayment({
139
141
  buyer, buyerFields, taxIdOnFile, saveProfile, saveBuyerContact, validation, failure, setStep,
140
142
  });
@@ -170,6 +172,6 @@ export function useCheckoutController(
170
172
  ...resumeSurface(resume, confirming),
171
173
  createError: failure.message, errorField: failure.field, errorCode: failure.code,
172
174
  goToMenu: onExitToMenu, back, editBuyer,
173
- goToPayment, startPayment, refresh, payWithEmail, handleResolved, retry, completed,
175
+ goToPayment, startPayment, refresh, payWithEmail, handleResolved, retry, completed, dropOrder,
174
176
  };
175
177
  }
@@ -68,6 +68,11 @@ function buildRuntime(config: PaymentFlowsConfig): FlowsRuntime {
68
68
  };
69
69
  }
70
70
 
71
+ /** The host's one-list Pagamento (FUT-3591), when it opted in — a hook, read every render. */
72
+ function useHostPaymentList(runtime: FlowsRuntime) {
73
+ return runtime.config.usePaymentList?.();
74
+ }
75
+
71
76
  /** The whole three-step flow, with the config fetched and availability decided. */
72
77
  function buildCheckout(
73
78
  runtime: FlowsRuntime,
@@ -80,6 +85,7 @@ function buildCheckout(
80
85
  const cart = runtime.config.useCart();
81
86
  const defaults = runtime.config.useBuyerDefaults?.() ?? {};
82
87
  const hostSettlement = runtime.config.useSettlement?.() ?? null;
88
+ const paymentList = useHostPaymentList(runtime);
83
89
  const { config, pending } = useResolvedConfig(runtime);
84
90
  const availability = runtime.useAvailability();
85
91
  const tenantSlug = runtime.useTenantSlug();
@@ -108,6 +114,7 @@ function buildCheckout(
108
114
  confirmationExtra={runtime.config.confirmation?.extra}
109
115
  confirmationHero={runtime.config.confirmation?.hero}
110
116
  validateApplePayMerchant={ports.validateApplePayMerchant}
117
+ paymentList={paymentList}
111
118
  />
112
119
  );
113
120
  }
@@ -19,6 +19,7 @@
19
19
  * `chain[].provider`, looked up in the tokenizer registry and used verbatim as
20
20
  * a `tokensByProvider` key. A host never types one.
21
21
  */
22
+ import type { CheckoutPaymentList } from "../components/checkout/list/types";
22
23
  import type { ComponentType, ReactNode } from "react";
23
24
 
24
25
  import type { SavedCard } from "../card";
@@ -115,6 +116,12 @@ export interface PaymentFlowsConfig extends CheckoutPipelineConfig {
115
116
  useBuyerDefaults?(): { buyer?: BuyerInfo; taxIdOnFile?: boolean; pending?: boolean };
116
117
  /** Present ⇒ this checkout settles a settlement rather than the cart. */
117
118
  useSettlement?(): SettlementCheckout | null;
119
+ /**
120
+ * The Pagamento step as ONE list (FUT-3591) — `CheckoutFlowProps.paymentList`,
121
+ * read through a HOOK because the host's door options follow its own state.
122
+ * Absent, or answering `undefined`, keeps the method tabs.
123
+ */
124
+ usePaymentList?(): CheckoutPaymentList | undefined;
118
125
 
119
126
  /** Design-system slots, filled ONCE instead of per screen. */
120
127
  components?: Partial<CheckoutComponents>;
package/src/index.ts CHANGED
@@ -54,11 +54,10 @@ export { PT_BR_CHECKOUT_PAYMENT_COPY } from './components/checkout-payment-pt-BR
54
54
  // mounted by a host in one line. See ADOPTING.md §3 for the ports and the
55
55
  // design-system slot contract.
56
56
  // ---------------------------------------------------------------------------
57
- export {
58
- CheckoutFlow,
59
- type CheckoutCartView,
60
- type CheckoutFlowProps,
61
- } from './components/checkout/checkout-flow';
57
+ export { CheckoutFlow, type CheckoutCartView, type CheckoutFlowProps } from './components/checkout/checkout-flow';
58
+ // The Pagamento step as ONE list (FUT-3591/3592) — opt-in via `CheckoutFlowProps.paymentList`.
59
+ export type { CheckoutDoorOption, CheckoutListChoice, CheckoutListHold, CheckoutOnlineChoice, CheckoutPaymentList, PaymentListCopy } from './components/checkout/list/types';
60
+ export { PT_BR_PAYMENT_LIST_COPY } from './components/checkout/list/pt-BR';
62
61
  export type { BackActionEmphasis } from './components/checkout/payment-status-parts';
63
62
  export type { CheckoutDeliverySummary, CheckoutSummaryLine } from './components/checkout/payment-summary';
64
63
 
package/src/locales.ts CHANGED
@@ -20,6 +20,9 @@ import {
20
20
  import { EN_US_CHECKOUT_SCREENS_COPY } from './components/checkout/screens-en-US';
21
21
  import type { CheckoutScreensCopy } from './components/checkout/screens-copy';
22
22
  import { PT_BR_CHECKOUT_SCREENS_COPY } from './components/checkout/screens-pt-BR';
23
+ import { EN_US_PAYMENT_LIST_COPY } from './components/checkout/list/en-US';
24
+ import { PT_BR_PAYMENT_LIST_COPY } from './components/checkout/list/pt-BR';
25
+ import type { PaymentListCopy } from './components/checkout/list/types';
23
26
  import type { CheckoutViewCopy, PaymentStatusCopy } from './components/checkout/view-copy';
24
27
  import type { PlatformHomologacaoCopy } from './components/platform/copy';
25
28
  import { EN_US_PLATFORM_HOMOLOGACAO_COPY } from './components/platform/en-US';
@@ -76,6 +79,15 @@ export const CHECKOUT_SCREENS_COPY = {
76
79
  'en-US': EN_US_CHECKOUT_SCREENS_COPY,
77
80
  } as const satisfies LocalePack<CheckoutScreensCopy>;
78
81
 
82
+ /**
83
+ * The one-list Pagamento step's words (FUT-3591) — `CheckoutFlowProps.paymentList.copy`.
84
+ * Read by the SHOPPER, like every checkout pack.
85
+ */
86
+ export const PAYMENT_LIST_COPY = {
87
+ 'pt-BR': PT_BR_PAYMENT_LIST_COPY,
88
+ 'en-US': EN_US_PAYMENT_LIST_COPY,
89
+ } as const satisfies LocalePack<PaymentListCopy>;
90
+
79
91
  export const CHECKOUT_COPY = {
80
92
  'pt-BR': PT_BR_CHECKOUT_COPY,
81
93
  'en-US': EN_US_CHECKOUT_COPY,
@@ -123,6 +135,7 @@ export {
123
135
  EN_US_PAYMENT_STATUS_COPY,
124
136
  } from './components/checkout/en-US';
125
137
  export { EN_US_CHECKOUT_SCREENS_COPY } from './components/checkout/screens-en-US';
138
+ export { EN_US_PAYMENT_LIST_COPY } from './components/checkout/list/en-US';
126
139
  export { EN_US_PAYMENTS_SETTINGS_COPY } from './components/settings-en-US';
127
140
  export { EN_US_PLATFORM_HOMOLOGACAO_COPY } from './components/platform/en-US';
128
141
  export { EN_US_TENDER_SPLIT_COPY } from './tender-split/en-US';