@12-apps/payments-frontend 3.38.0 → 3.40.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.
- package/package.json +1 -1
- package/src/card/types.ts +6 -0
- package/src/components/checkout/card-sources.ts +11 -2
- package/src/components/checkout/list/bank-apps.ts +113 -0
- package/src/components/checkout/list/bank-en-US.ts +26 -0
- package/src/components/checkout/list/bank-logos.tsx +35 -0
- package/src/components/checkout/list/bank-pt-BR.ts +26 -0
- package/src/components/checkout/list/charge-runners.tsx +22 -3
- package/src/components/checkout/list/choice-list.tsx +4 -1
- package/src/components/checkout/list/choice.ts +30 -5
- package/src/components/checkout/list/context.tsx +27 -3
- package/src/components/checkout/list/en-US.ts +2 -0
- package/src/components/checkout/list/list-face.tsx +92 -29
- package/src/components/checkout/list/list-memory.ts +96 -0
- package/src/components/checkout/list/list-pix.tsx +153 -17
- package/src/components/checkout/list/online-content.tsx +11 -4
- package/src/components/checkout/list/option-row.tsx +4 -2
- package/src/components/checkout/list/payment-list-step.tsx +2 -1
- package/src/components/checkout/list/pix-banks.tsx +178 -0
- package/src/components/checkout/list/pt-BR.ts +2 -0
- package/src/components/checkout/list/types.ts +126 -4
- package/src/components/checkout/list/use-capability.ts +15 -10
- package/src/components/checkout/list/use-list-charge.ts +37 -12
- package/src/components/checkout/list/use-list-state.ts +11 -8
- package/src/components/checkout/pix-after-copy.tsx +8 -2
- package/src/components/checkout/pix-parts.tsx +56 -0
- package/src/components/checkout/pix-view.tsx +2 -0
- package/src/components/checkout/transport.ts +3 -1
- package/src/components/checkout/types.ts +9 -9
- package/src/index.ts +1 -1
- package/src/locales.ts +12 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@12-apps/payments-frontend",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.40.0",
|
|
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.",
|
package/src/card/types.ts
CHANGED
|
@@ -40,6 +40,12 @@ export interface SavedCard {
|
|
|
40
40
|
expMonth: number;
|
|
41
41
|
expYear: number;
|
|
42
42
|
holder: string;
|
|
43
|
+
/**
|
|
44
|
+
* When the buyer last paid with it (ISO-8601), or `null`/absent when the
|
|
45
|
+
* host does not say. The one list preselects the card used LAST (FUT-3591);
|
|
46
|
+
* every other screen keeps the host's own order.
|
|
47
|
+
*/
|
|
48
|
+
lastUsedAt?: string | null;
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
/** Per-field validation messages; `undefined` means the field is fine. */
|
|
@@ -13,6 +13,14 @@ import { useCheckoutClientApi } from "./client-context";
|
|
|
13
13
|
* rather than after the buyer has spent a minute typing.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* A list answer as a list: a host whose card route answers `null` (or
|
|
18
|
+
* nothing) has no saved card, and must not take the checkout down with it.
|
|
19
|
+
*/
|
|
20
|
+
function asList(cards: SavedCard[] | null | undefined): SavedCard[] {
|
|
21
|
+
return Array.isArray(cards) ? cards : [];
|
|
22
|
+
}
|
|
23
|
+
|
|
16
24
|
/**
|
|
17
25
|
* The buyer's saved cards at this store (FUT-697), loaded once per store, and
|
|
18
26
|
* whether the list has answered — "no saved card" and "not asked yet" are
|
|
@@ -29,7 +37,7 @@ export function useSavedCardList(tenantSlug: string | undefined): { cards: Saved
|
|
|
29
37
|
.listInstruments(tenantSlug)
|
|
30
38
|
.catch((): SavedCard[] => [])
|
|
31
39
|
.then((cards) => {
|
|
32
|
-
if (active) setState({ cards, loaded: true });
|
|
40
|
+
if (active) setState({ cards: asList(cards), loaded: true });
|
|
33
41
|
});
|
|
34
42
|
return () => {
|
|
35
43
|
active = false;
|
|
@@ -68,8 +76,9 @@ export function useSavedCards(
|
|
|
68
76
|
void client
|
|
69
77
|
.listInstruments(tenantSlug)
|
|
70
78
|
.catch((): SavedCard[] => [])
|
|
71
|
-
.then((
|
|
79
|
+
.then((answer) => {
|
|
72
80
|
if (!active) return;
|
|
81
|
+
const cards = asList(answer);
|
|
73
82
|
const first = cards[0];
|
|
74
83
|
setState((prev) => ({ savedCards: cards, selection: first && !freshInstrument ? first.id : prev.selection }));
|
|
75
84
|
});
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opening the buyer's bank app from the Pix face (FUT-3612).
|
|
3
|
+
*
|
|
4
|
+
* There is no standard Pix link that pays a copia-e-cola code, so this only
|
|
5
|
+
* OPENS the app; the buyer pastes the code the button already copied. Android
|
|
6
|
+
* opens an app through an `intent:` URL naming its package; iOS only through a
|
|
7
|
+
* URL scheme the bank's app registers. Neither tells the page whether it
|
|
8
|
+
* worked, so {@link openBankApp} watches the page: an app that opened takes
|
|
9
|
+
* the screen within a moment, and a page still visible after
|
|
10
|
+
* {@link OPEN_WAIT_MS} is a bank that did not open — not installed, or a link
|
|
11
|
+
* this phone does not know.
|
|
12
|
+
*/
|
|
13
|
+
import type { PixBankId } from "./types";
|
|
14
|
+
|
|
15
|
+
/** How long a page may stay visible before the bank counts as not opened. */
|
|
16
|
+
const OPEN_WAIT_MS = 1500;
|
|
17
|
+
|
|
18
|
+
interface BankApp {
|
|
19
|
+
/** The Play Store package of the bank's personal app — each one checked on its Play listing (2026-10-16). */
|
|
20
|
+
android: string;
|
|
21
|
+
/**
|
|
22
|
+
* The URL scheme its app answers on iOS (without "://"). Only Nubank's
|
|
23
|
+
* (`nuapp`) is documented — in Nubank's own deep links. The other five
|
|
24
|
+
* publish no scheme we could find: theirs are the likeliest name, and a
|
|
25
|
+
* phone that does not know one is a bank that "did not open", which the face
|
|
26
|
+
* says (owner, 2026-10-16: Android and iOS, and say so when it does not open).
|
|
27
|
+
*/
|
|
28
|
+
ios: string;
|
|
29
|
+
/** A scheme Android opens the app with, when one is known; else the app's launcher, by package. */
|
|
30
|
+
scheme?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The six, in the prototype's order. */
|
|
34
|
+
export const PIX_BANKS: readonly PixBankId[] = ["nubank", "itau", "bradesco", "bb", "caixa", "santander"];
|
|
35
|
+
|
|
36
|
+
const APPS: Record<PixBankId, BankApp> = {
|
|
37
|
+
nubank: { android: "com.nu.production", ios: "nuapp", scheme: "nuapp" },
|
|
38
|
+
itau: { android: "com.itau", ios: "itau" },
|
|
39
|
+
bradesco: { android: "com.bradesco", ios: "bradesco" },
|
|
40
|
+
bb: { android: "br.com.bb.android", ios: "bbapp" },
|
|
41
|
+
caixa: { android: "br.gov.caixa.CAIXA", ios: "caixa" },
|
|
42
|
+
santander: { android: "com.santander.app", ios: "santanderpf" },
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type PhoneOs = "android" | "ios";
|
|
46
|
+
|
|
47
|
+
/** The phone this page runs on, or `null` for a computer (or no browser at all). */
|
|
48
|
+
export function phoneOs(nav: Pick<Navigator, "userAgent" | "maxTouchPoints"> | undefined = typeof navigator === "undefined" ? undefined : navigator): PhoneOs | null {
|
|
49
|
+
if (!nav) return null;
|
|
50
|
+
const ua = nav.userAgent;
|
|
51
|
+
if (/Android/i.test(ua)) return "android";
|
|
52
|
+
if (/iPhone|iPad|iPod/i.test(ua)) return "ios";
|
|
53
|
+
// iPadOS asks for the desktop site: a "Macintosh" with a touch screen.
|
|
54
|
+
if (/Macintosh/i.test(ua) && nav.maxTouchPoints > 1) return "ios";
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The phone the host's bank flow runs on: its own word when it gave one
|
|
60
|
+
* (`phone`), else the browser's. `null` ⇒ a computer: no banks.
|
|
61
|
+
*/
|
|
62
|
+
export function bankFlowOs(phone: boolean | undefined): PhoneOs | null {
|
|
63
|
+
if (phone === false) return null;
|
|
64
|
+
if (phone === true) return phoneOs() ?? "android";
|
|
65
|
+
return phoneOs();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The URL that opens `bank`'s app on `os`. Android: an `intent:` URL naming the
|
|
70
|
+
* package — through the app's scheme when one is known, else its launcher; a
|
|
71
|
+
* phone without the app gets the bank's Play Store page from the browser.
|
|
72
|
+
*/
|
|
73
|
+
export function bankAppUrl(bank: PixBankId, os: PhoneOs): string {
|
|
74
|
+
const app = APPS[bank];
|
|
75
|
+
if (os === "ios") return `${app.ios}://`;
|
|
76
|
+
if (app.scheme) return `intent://#Intent;scheme=${app.scheme};package=${app.android};end`;
|
|
77
|
+
return `intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;package=${app.android};end`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Open `bank`'s app, and say whether it opened: `true` when the page lost the
|
|
82
|
+
* screen (hidden, or left) within {@link OPEN_WAIT_MS}.
|
|
83
|
+
*/
|
|
84
|
+
export function openBankApp(
|
|
85
|
+
bank: PixBankId,
|
|
86
|
+
os: PhoneOs,
|
|
87
|
+
env: { win: Window; doc: Document; waitMs?: number } = { win: window, doc: document },
|
|
88
|
+
): Promise<boolean> {
|
|
89
|
+
const { win, doc } = env;
|
|
90
|
+
return new Promise((resolve) => {
|
|
91
|
+
let left = false;
|
|
92
|
+
const onVisibility = (): void => {
|
|
93
|
+
if (doc.visibilityState === "hidden") left = true;
|
|
94
|
+
};
|
|
95
|
+
const onLeave = (): void => {
|
|
96
|
+
left = true;
|
|
97
|
+
};
|
|
98
|
+
doc.addEventListener("visibilitychange", onVisibility);
|
|
99
|
+
win.addEventListener("pagehide", onLeave);
|
|
100
|
+
win.addEventListener("blur", onLeave);
|
|
101
|
+
win.setTimeout(() => {
|
|
102
|
+
doc.removeEventListener("visibilitychange", onVisibility);
|
|
103
|
+
win.removeEventListener("pagehide", onLeave);
|
|
104
|
+
win.removeEventListener("blur", onLeave);
|
|
105
|
+
resolve(left);
|
|
106
|
+
}, env.waitMs ?? OPEN_WAIT_MS);
|
|
107
|
+
try {
|
|
108
|
+
win.location.href = bankAppUrl(bank, os);
|
|
109
|
+
} catch {
|
|
110
|
+
// A scheme the browser refuses outright is a bank that did not open.
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { PixBankCopy } from "./types";
|
|
2
|
+
|
|
3
|
+
/** The Pix-to-bank flow's words, en-US (FUT-3612). */
|
|
4
|
+
export const EN_US_PIX_BANK_COPY: PixBankCopy = {
|
|
5
|
+
names: {
|
|
6
|
+
nubank: { name: "Nubank", the: "" },
|
|
7
|
+
itau: { name: "Itaú", the: "" },
|
|
8
|
+
bradesco: { name: "Bradesco", the: "" },
|
|
9
|
+
bb: { name: "Banco do Brasil", the: "" },
|
|
10
|
+
caixa: { name: "Caixa", the: "" },
|
|
11
|
+
santander: { name: "Santander", the: "" },
|
|
12
|
+
},
|
|
13
|
+
generateAndCopy: "Create and copy the Pix",
|
|
14
|
+
generateCopyAndOpen: (bank) => `Create, copy and open ${bank.name}`,
|
|
15
|
+
copyAndOpen: (bank) => `Copy and open ${bank.name}`,
|
|
16
|
+
openOther: "Open another bank",
|
|
17
|
+
listTitle: "Open your bank and paste in Pix copia e cola",
|
|
18
|
+
open: (bank) => `Open ${bank.name}`,
|
|
19
|
+
opening: (bank) => `Opening **${bank.name}**…`,
|
|
20
|
+
other: "Another bank",
|
|
21
|
+
notOpened: (bank) => `We couldn't open ${bank.name}. Is the app installed on this phone?`,
|
|
22
|
+
retry: "Try again",
|
|
23
|
+
copied: "Pix code copied",
|
|
24
|
+
copiedPick: "Pix code copied. Choose your bank.",
|
|
25
|
+
copiedOpening: (bank) => `Pix code copied. Opening ${bank.name}…`,
|
|
26
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Box } from "@mui/material";
|
|
2
|
+
import type { JSX } from "react";
|
|
3
|
+
|
|
4
|
+
import type { PixBankId } from "./types";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The six banks' own marks (FUT-3612, owner 2026-10-15: "coloca as logos dos
|
|
8
|
+
* bancos"), drawn at 32px beside each name so a buyer finds their bank by its
|
|
9
|
+
* mark. Inline as data URIs — no remote asset (ADR 0074's sibling rule, §5.1
|
|
10
|
+
* item 5) — and only to identify the bank. Sources: Nubank and Itaú from
|
|
11
|
+
* Wikimedia Commons (PD-textlogo, trademarked); Bradesco, Banco do Brasil,
|
|
12
|
+
* Caixa and Santander from the Bancos-em-SVG collection (the banks' symbols).
|
|
13
|
+
* Each is the bank's trademark.
|
|
14
|
+
*/
|
|
15
|
+
const LOGOS: Record<PixBankId, string> = {
|
|
16
|
+
nubank: "data:image/svg+xml;base64,PHN2ZyB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIiB2aWV3Qm94PSIwIDAgMjYzLjg0MjA3IDE0NS41NjczNyIgdmVyc2lvbj0iMS4xIiBpZD0ic3ZnNiIgc29kaXBvZGk6ZG9jbmFtZT0iTnViYW5rIGxvZ28gMjAyMS5zdmciIHdpZHRoPSIyNjMuODQyMDciIGhlaWdodD0iMTQ1LjU2NzM3IiBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9IkM6XFVzZXJzXGFsZXhcc2l0ZXNcbnViYW5rLWxvZ28tMC5wbmciIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI1NjEuNzM3MTIiIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI1NjEuNzM3MTIiIGlua3NjYXBlOnZlcnNpb249IjEuMC4yIChlODZjODcwODc5LCAyMDIxLTAxLTE1LCBjdXN0b20pIj4gPG1ldGFkYXRhIGlkPSJtZXRhZGF0YTEyIj4gPHJkZjpSREY+IDxjYzpXb3JrIHJkZjphYm91dD0iIj4gPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+IDxkYzp0eXBlIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+IDxkYzp0aXRsZT48L2RjOnRpdGxlPiA8L2NjOldvcms+IDwvcmRmOlJERj4gPC9tZXRhZGF0YT4gPGRlZnMgaWQ9ImRlZnMxMCIgLz4gPHNvZGlwb2RpOm5hbWVkdmlldyBwYWdlY29sb3I9IiNmZmZmZmYiIGJvcmRlcmNvbG9yPSIjNjY2NjY2IiBib3JkZXJvcGFjaXR5PSIxIiBvYmplY3R0b2xlcmFuY2U9IjEwIiBncmlkdG9sZXJhbmNlPSIxMCIgZ3VpZGV0b2xlcmFuY2U9IjEwIiBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMCIgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxMzY2IiBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI3MDUiIGlkPSJuYW1lZHZpZXc4IiBzaG93Z3JpZD0iZmFsc2UiIGlua3NjYXBlOnpvb209IjAuMjE0NTk3NTkiIGlua3NjYXBlOmN4PSIyMDguODkzNiIgaW5rc2NhcGU6Y3k9IjEyOC41MTMxNSIgaW5rc2NhcGU6d2luZG93LXg9Ii04IiBpbmtzY2FwZTp3aW5kb3cteT0iLTgiIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9InN2ZzYiIGlua3NjYXBlOmRvY3VtZW50LXJvdGF0aW9uPSIwIiBmaXQtbWFyZ2luLXRvcD0iMCIgZml0LW1hcmdpbi1sZWZ0PSIwIiBmaXQtbWFyZ2luLXJpZ2h0PSIwIiBmaXQtbWFyZ2luLWJvdHRvbT0iMCIgLz4gPHBhdGggZD0iTSA0Ny42Mjc1OTgsMTMuODg1NjUgQyA1NS45NzA5MTgsNS4xMjAyMiA2Ny4wMzgxODgsMCA4MC4wNDAxNTgsMCBjIDI1LjMyOTMwMiwwIDQyLjEyMjg2MiwxOC40OTM2MSA0NS4zMzU4MTIsNDYuMTk4MzEgMS4wNDE3Myw4Ljk5NzAyIDEuMDMyMTcsMjEuNjgxNDYgMS4wMjE3MiwzNi4zNzMzOCAtMC4wMDIsMS41MDY2MiAtMC4wMDIsMy4wMzQ2NCAtMC4wMDIsNC41ODE3NSB2IDU1LjAzODM5IEggOTEuNTYzMDY4IHYgLTQwLjcwODEyIGMgMCwwIC0wLjA3MSwtMzQuODQwMzYgLTAuMjgzODYsLTQxLjM1MTggLTAuOTM0ODIsLTI4LjM1OTQ1IC0xNy43MjM4MywtNDYuMTc5MTEgLTQzLjY1NDk3LC00Ni4xOTgyNiAtNy44MjM2LDguMjY1NzcgLTEyLjAxNTU5LDE4LjM3MjEgLTEyLjYzMzgxLDMzLjgyNDk4IC0wLjA4NSwyLjE1NTMxIC0wLjA2MzYsOS43OTQ5MSAtMC4wMzU0LDE5Ljg2MzY3IDAuMDE0Niw1LjIxNjggMC4wMzEsMTEuMDg1OTIgMC4wMzU0LDE3LjE4MjA0IDAuMDI1OCwyNi41MzM4OCAwLDU3LjM5MzQxIDAsNTcuMzkzNDEgSCAwLjE1NzcwMTQ1IFYgNzkuNTQ4NDIgYyAwLC0yLjE0NjY4IC0wLjAzOTE1LC00LjMxMTU1IC0wLjA3ODM5LC02LjQ4NTA2IC0wLjA3ODk5OTk5NzEsLTQuMzcyMDUgLTAuMTU4NjI2LC04Ljc3Nzc1IDAuMDc4MzksLTEzLjE0MDI1IEMgMC41NTEyNTI0NSw1Mi42NTA2MiAxLjgwOTMyMjUsNDUuNTAxNCA1LjIwMjg2ODUsMzguODU5OTUgMTIuOTcwNjU4LDIzLjY0NDgxIDI4Ljg4Njg4OCwxMy44NDgzNSA0NS44NTQ4NDgsMTMuODQ4MzUgYyAwLjU5Mjc0LDAgMS4xODU5MywwLjAxMzcgMS43NzI3NSwwLjAzNjQgeiIgY2xhc3M9IlBhdGgteHJ0a3BkLTAgZXFmWWlSIiBpZD0icGF0aDIiIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIHN0eWxlPSJmaWxsOiM4MjBhZDE7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlLXdpZHRoOjQuNTQ5IiBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9IkM6XFVzZXJzXGFsZXhcc2l0ZXNcbnViYW5rLWxvZ28tNS5wbmciIGlua3NjYXBlOmV4cG9ydC14ZHBpPSIxMzIuNzY1MzgiIGlua3NjYXBlOmV4cG9ydC15ZHBpPSIxMzIuNzY1MzgiIC8+IDxwYXRoIGQ9Im0gMjYzLjY4NDMzLDg1LjY0NDk5IGMgMC4yMzcsLTQuMzYyNDkgMC4xNTczOSwtOC43Njg2NiAwLjA3ODcsLTEzLjE0MDI1IC0wLjAzOTYsLTIuMTczNTEgLTAuMDc4NywtNC4zMzgzOCAtMC4wNzg3LC02LjQ4NTA1IFYgMy4zNzAyMiBoIC0zNC44MzIxOCBjIDAsMCAtMC4wMjYsMzAuODU5NTMgMCw1Ny4zOTMwOSAwLjAwNCw2LjA5NjEyIDAuMDIwNSwxMS45NjQ3OSAwLjAzNSwxNy4xODE1OSAwLjAyODIsMTAuMDY5MjEgMC4wNDk2LDE3LjcwODgxIC0wLjAzNSwxOS44NjQxMyAtMC42MTgyMSwxNS40NTM0MiAtNC44MTA1NiwyNS41NTk0OCAtMTIuNjMzOTQsMzMuODI1NDggLTI1LjkzMDY5LC0wLjAxODIgLTQyLjcxOTIzLC0xNy44MzkzOCAtNDMuNjU0NTEsLTQ2LjE5ODMyIC0wLjIxMjksLTYuNTExNDQgLTAuMzAyOTcsLTIyLjY2OTk1IC0wLjMwMjk3LC00MS4zODQ1MSBWIDMuMzQzNjEgbCAtMzQuODA2NjksMC4wMzE4IHYgNTUuMDM4NTIgYyAwLDEuNTQ3MTIgLTAuMDAyLDMuMDc0NjggLTAuMDAyLDQuNTgxNzYgLTAuMDExLDE0LjY5MTkxIC0wLjAyLDI3LjM3NTkgMS4wMjE3LDM2LjM3MzM4IDMuMjA2MTUsMjcuNzA0NzkgMTkuOTk5Nyw0Ni4xOTgzIDQ1LjMyOSw0Ni4xOTgzIDEzLjAwMjQyLDAgMjQuMDY5NjksLTUuMTIwMzUgMzIuNDEzMDEsLTEzLjg4NTgyIDAuNTg2MzcsMC4wMjI3IDEuMTc5MTEsMC4wMzY0IDEuNzcxODQsMC4wMzY0IDE2Ljk2Nzc4LDAgMzIuODg0MjksLTkuNzk2MjggNDAuNjUyMTcsLTI1LjAxMTMzIDMuMzkzNTUsLTYuNjQyIDQuNjUxMzUsLTEzLjc5MDc2IDUuMDQ0ODQsLTIxLjA2MzI1IHoiIGNsYXNzPSJQYXRoLXhydGtwZC0wIGVxZllpUiIgaWQ9InBhdGg0IiBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiBzdHlsZT0iZmlsbDojODIwYWQxO2ZpbGwtb3BhY2l0eToxO3N0cm9rZS13aWR0aDo0LjU0OSIgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSJDOlxVc2Vyc1xhbGV4XHNpdGVzXG51YmFuay1sb2dvLTUucG5nIiBpbmtzY2FwZTpleHBvcnQteGRwaT0iMTMyLjc2NTM4IiBpbmtzY2FwZTpleHBvcnQteWRwaT0iMTMyLjc2NTM4IiAvPiA8cGF0aCBkPSJtIDExOC41ODczMSw3OTQuNjAwOTMgYyAxNC4xNTg0NiwtMTQuOTQ0NjQgMzIuOTM5NDIsLTIzLjY3NDM1IDU1LjAwMzc4LC0yMy42NzQzNSA0Mi45ODMzMSwwIDcxLjQ4MTY1LDMxLjUzMDY1IDc2LjkzNDAxLDc4Ljc2NTY1IDEuNzY3NzcsMTUuMzM5NSAxLjc1MTYsMzYuOTY1OCAxLjczMzg5LDYyLjAxNDcgMCwyLjU2ODggMCw1LjE3MzkgMCw3LjgxMTcgdiA5My44Mzc0NyBoIC01OS4xMTA0NCB2IC02OS40MDUxNyBjIDAsMCAtMC4xMjA1NSwtNTkuNDAwOSAtMC40ODE4NiwtNzAuNTAyNiAtMS41ODYxOCwtNDguMzUxNCAtMzAuMDc2NzgsLTc4LjczMyAtNzQuMDgxNjksLTc4Ljc2NTYgLTEzLjI3NjQyLDE0LjA5MjcgLTIwLjM5MDM3MiwzMS4zMjM0IC0yMS40Mzk0MDIsNTcuNjY5OCAtMC4xNDQxMiwzLjY3NDcgLTAuMTA3OTEsMTYuNjk5OCAtMC4wNjA2LDMzLjg2NjUgMC4wMjQ4LDguODk0NCAwLjA1MzMsMTguOTAwOSAwLjA2MDYsMjkuMjk0NSAwLjA0NSw0NS4yMzg5IDAsOTcuODUyNjcgMCw5Ny44NTI2NyBIIDM4LjAzNTA2OCBWIDkwNi41NTI0MyBjIDAsLTMuNjU5OSAtMC4wNjcsLTcuMzUwOSAtMC4xMzMsLTExLjA1NjcgLTAuMTMzOTMsLTcuNDU0MSAtMC4yNjkwMywtMTQuOTY1NiAwLjEzMywtMjIuNDAzNCAwLjY2ODAzLC0xMi4zOTkyIDIuODAyOTMsLTI0LjU4ODMgOC41NjE4LC0zNS45MTE1IDEzLjE4MTYzLC0yNS45NDExIDQwLjE5MTM0LC00Mi42NDM1IDY4Ljk4NTcyMiwtNDIuNjQzNSAxLjAwNTc3LDAgMi4wMTI0NCwwLjAyMyAzLjAwODIxLDAuMDYyIHoiIGNsYXNzPSJQYXRoLXhydGtwZC0wIGVxZllpUiIgaWQ9InBhdGgyLTYiIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIHN0eWxlPSJmaWxsOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjcuNzM3NjgiIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iQzpcVXNlcnNcYWxleFxzaXRlc1xudWJhbmstbG9nby00LnBuZyIgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjkyLjYxODA5NSIgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjkyLjYxODA5NSIgLz4gPHBhdGggZD0ibSA0ODUuMjMyMTcsOTE2Ljk0NjgzIGMgMC40MDIyMSwtNy40Mzc5IDAuMjY3MTQsLTE0Ljk1MDEgMC4xMzM2LC0yMi40MDM1IC0wLjA2NzIsLTMuNzA1NyAtMC4xMzM2LC03LjM5NjcgLTAuMTMzNiwtMTEuMDU2NyB2IC0xMDYuODE0IGggLTU5LjEwOTYyIGMgMCwwIC0wLjA0NDMsNTIuNjEzOSAwLDk3Ljg1MjIgMC4wMSwxMC4zOTM2IDAuMDM0NiwyMC4zOTkzIDAuMDU5MywyOS4yOTM3IDAuMDQ3OCwxNy4xNjc1IDAuMDg0MSwzMC4xOTI2IC0wLjA1OTMsMzMuODY3MyAtMS4wNDkxMSwyNi4zNDczIC04LjE2MzQzLDQzLjU3NzYgLTIxLjQzOTU5LDU3LjY3MDcgLTQ0LjAwMzk4LC0wLjAzMSAtNzIuNDkzODUsLTMwLjQxNTMgLTc0LjA4MTA1LC03OC43NjU3IC0wLjM2MTI1LC0xMS4xMDE3IC0wLjUxNDE4LC0zOC42NTExIC0wLjUxNDE4LC03MC41NTg0IHYgLTY5LjQwNTE2IGwgLTU5LjA2NjM1LDAuMDU0MSB2IDkzLjgzNzg2IGMgMCwyLjYzNzcgMCw1LjI0MjEgMCw3LjgxMTYgLTAuMDE5MiwyNS4wNDkgLTAuMDMzLDQ2LjY3NDUgMS43MzM4Nyw2Mi4wMTQ3IDUuNDQwNzEsNDcuMjM1MiAzMy45MzkwNSw3OC43NjU2NyA3Ni45MjI1NSw3OC43NjU2NyAyMi4wNjUwMSwwIDQwLjg0NTg3LC04LjcyOTkgNTUuMDA0MzYsLTIzLjY3NDU3IDAuOTk1MDgsMC4wMzkgMi4wMDA5NCwwLjA2MiAzLjAwNjc5LDAuMDYyIDI4Ljc5NDA4LDAgNTUuODA0MTIsLTE2LjcwMjEgNjguOTg2MDUsLTQyLjY0MyA1Ljc1ODg5LC0xMS4zMjQzIDcuODkzMjgsLTIzLjUxMjUgOC41NjEwNSwtMzUuOTExNyB6IiBjbGFzcz0iUGF0aC14cnRrcGQtMCBlcWZZaVIiIGlkPSJwYXRoNC01IiBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiBzdHlsZT0iZmlsbDojZmZmZmZmO3N0cm9rZS13aWR0aDo3LjczNzY4IiBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9IkM6XFVzZXJzXGFsZXhcc2l0ZXNcbnViYW5rLWxvZ28tNC5wbmciIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI5Mi42MTgwOTUiIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI5Mi42MTgwOTUiIC8+IDwvc3ZnPg==",
|
|
17
|
+
itau: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MDAiIGhlaWdodD0iNTAwIiB2aWV3Qm94PSIwIDAgNTAwIDUwMCI+PHBhdGggZD0iTTIxOC42NzYgMTAuNTc0Yy0xMy43OTcuMzI4LTIzLjkxOC44MTMtNDIuNDczIDEuOTU3LTguNTgyLjUxMi0xNy45NSAxLjI2Ni0yNC41NDcgMS45MjYtMS42NTYuMTgtNS4xMi41MTItNy42OC43NTQtMTAuNzUzIDEuMDU1LTI2LjcxOCAzLjA3LTMzLjQzMyA0LjIxNS0xLjQxOC4yNDItMy40OTYuNTc0LTQuNjY4Ljc1NC0xLjE0NS4xNTItMy4xOTUuNTExLTQuNTIuNzU0LTEuMzI0LjI0Mi0zLjU1NC42NjQtNC45NjguOTAyLTQuOTczLjg0NC0xMy40MzQgMi41NjItMTguMjIzIDMuNzA3LTEuMzI4LjMzMi0zLjcwNy45MDItNS4yNzMgMS4yNjYtMS41NjcuMzU5LTIuOTguNjkxLTMuMTYuNzIyLTguODI5IDIuMTA2LTE3LjU5NCA2LjM1Ni0yNC4zNCAxMS44NjdDMzguODI0IDQ0LjczIDMyLjk1MyA1My4zNDQgMzAgNjEuODk4Yy0uNDggMS4zMjUtLjk2NSAyLjY4LTEuMTEzIDMuMDEyLS41MTIgMS4xNDUtMi43NDIgMTAuNzgxLTQuMzQgMTguNjc2LS4yMzggMS4zMjQtLjY2IDMuMjgxLS45MDIgNC4zNjctLjI0MyAxLjA4Mi0uNTcgMi45OC0uNzgyIDQuMjE1LS4xODMgMS4yMzQtLjQyMiAyLjc0Mi0uNTc0IDMuMzEyLS40NTMgMS43Mi0yLjI4OSAxMy40NjUtMy40NjUgMjEuOTg5LTEuMTQ0IDguMjU0LTEuODk4IDE0LjI1LTIuNTU4IDIwLjMzMi0uMzMyIDIuOTgtLjY2NCA1LjkwMi0uNzIzIDYuNDc2LS4wOS41Ny0uMzYzIDMuNDkzLS42MzMgNi40NzctLjI0MiAyLjk4LS42MDEgNi42MjUtLjc4NSA4LjEzMy0uNjMzIDUuNTM5LTIuMiAyOS42NjgtMi45OCA0Ni42ODctLjYwMiAxMi42MTctLjk5MyAzOS42MzctLjc4MiA1NC4zNjcuMjExIDE4LjM3Mi42NiAzNC43OSAxLjA4MiA0MC41MTIuMTUzIDIuMzE3LjQ1MyA3LjIuNjMzIDEwLjg0NC4xOCAzLjY0NC40MjIgOC4zMTIuNTc0IDEwLjM5LjY5MiAxMC40MjIgMS4yMzUgMTcuMjU4IDEuNTA0IDE5LjQyNi4xNTMgMS4zMjguNTEyIDQuODUyLjc1NCA3LjgwMS4yNDIgMi45NTMuNjAyIDYuNDc3Ljc1NCA3LjgzMi4xOCAxLjM1Ni41MTIgNC4yNzcuNzUgNi41MDguNzU0IDcuMTM3IDEuMzI4IDExLjgwNSAxLjgwOSAxNC45MS4yNDIgMS42NTYuNjY0IDQuNDg4LjkwMiA2LjMyNC44NzUgNi42MjUgMS44OTggMTMuMDcgMy4wMTIgMTguOTc3LjI0MiAxLjMyNC42MzMgMy41NTUuOTA2IDQuOTY5LjUxMiAzLjAxMSAxLjY4NyA5LjAwNyAyLjUzMSAxMi44IDIuODkgMTMuMjg2IDQuMTU2IDE3LjI1OCA3LjU1OSAyMy43OTcuOTMzIDEuODA1IDIuMTM3IDMuOTE0IDIuNjggNC42NjguNTExLjc1NCAxLjI2NSAxLjgzNiAxLjY1NiAyLjQxIDEuNzE4IDIuNTU5IDYuNjI5IDcuNTU5IDkuMzQgOS40ODkuNDQ5LjMyOCAxLjMyNC45NiAxLjg5NCAxLjQxNC42MDYuNDggMS4xNzYuODQzIDEuMzI4Ljg0My4xMjEgMCAuNDIyLjIxMS42Ni40NTQgMS4xNzYgMS4xNDQgOS40NjEgNS4wOSAxMy4wMTIgNi4xNDQuNjY0LjIxMSAxLjQ3Ny40OCAxLjgwOS42MzMuNzg1LjM2IDUuMjEgMS40NzMgMTAuNTQzIDIuNjggMi4zMi41NDMgNC42OTkgMS4xMTMgNS4yNyAxLjI2NSAxLjM4Ni4zNiAxMC4xMiAyLjEwNiAxNi43MTggMy4zMTMgMy43OTMuNjkxIDExLjE3NiAxLjg2NyAxNS44MTIgMi41MzEgMS43NDcuMjM4IDMuOTc3LjU3IDQuOTcuNzUgMy42NDQuNjMzIDE4LjcwNiAyLjM4MyAyOC4xNjMgMy4yODUgMy40MDMuMzMyIDcuNTkuNzIzIDkuMzM2LjkwMiAyLjgzMi4zMDEgNS43MjMuNTQzIDE5LjU3OCAxLjUzNiAyLjA3OC4xNTIgNi44MDkuNDIyIDEwLjU0My42MDUgMy43MzUuMTggOC45NDYuNDUgMTEuNTk4LjYwMiAyMS40NDUgMS4yMzQgODIuNzcgMS4yMzQgMTAzLjkxNCAwIDIuNjUyLS4xOCA3Ljg2My0uNDIyIDExLjU5OC0uNjAyIDYuNDE0LS4zIDguNzY1LS40NTMgMTguODI0LTEuMjA3IDEyLjg5LS45OTIgMzEuODQtMi44MzIgMzguMjU0LTMuNzM0IDEuODM2LS4yNyA1LS42OTIgNy4wNzgtLjk2NSA3LjY4LS45OTIgMTguMjIzLTIuNTkgMjQuMjQ2LTMuNzAzIDYuNTk4LTEuMjA3IDE1LjMzMi0yLjk1MyAxNi43MTktMy4zMTMuNTctLjE1MiAyLjk0OS0uNzIyIDUuMjctMS4yNjUgNS4yMS0xLjE3NiA5LjczLTIuMzIgMTAuNTQyLTIuNjhhMTc0LjggMTc0LjggMCAwIDEgMy4wMTItMS4wNTVjMi40NjktLjgxMiAxMC42NjQtNC42OTkgMTEuMzU1LTUuMzYzLjIxMS0uMjExLjgxMy0uNjYgMS4zMjUtLjk2NSAyLjM1MS0xLjQ3MyAzLjQzMy0yLjMxNiA1LjU3NC00LjI0NiAyLjQxLTIuMiA1Ljc1NC01LjgxMiA2LjU2Ni03LjA0Ny4yNy0uNDIyLjk5My0xLjQ0NSAxLjU5NC0yLjI1OC42MzMtLjg0MyAxLjE0NS0xLjU5NyAxLjE0NS0xLjcxOCAwLS4xMjIuNDg0LS45NjUgMS4wNTQtMS44NjguNTc1LS45MDIgMS4yNjYtMi4yMyAxLjU0LTIuOTUzLjMtLjY5MS42LTEuNDQ1LjcyMi0xLjU5My41Ny0uNzU0IDIuNjgtNi43NSAzLjU4Mi0xMC4xNTMgMS40MTgtNS4yNyA0LjA2Ni0xNy43MSA1LjAzMS0yMy41ODYuMjQyLTEuNTA0LjUxMi0yLjkxOC42MDItMy4xNi4yNzMtLjY2NCAxLjkzLTEwLjk5NiAzLjQzMy0yMS41MzUuMzMyLTIuMzIuNjY0LTQuNjQuNzU0LTUuMTIxLjI0My0xLjM4NyAxLjMyNS0xMC42MzMgMS44MDktMTUuNTEyLjIzOC0yLjQxLjU3LTUuMTgzLjc1LTYuMTc2LjE4NC0uOTk2LjUxMi00LjI0Ni43NTQtNy4yMy4yNDItMi45OC41NzQtNi42NTYuNzIzLTguMTMzLjE4LTEuNTA0LjQ1My00LjkzNy42MzItNy42OC4xOC0yLjc0Mi40NTMtNi4xMTMuNjAyLTcuNTMuMTgzLTEuNDE1LjUxMi02LjYyNi43NTQtMTEuNTk1LjI3My00Ljk3Mi41NzQtMTEuMDg2Ljc1NC0xMy41NTQgMS4zNTUtMjEuODk5IDEuMzU1LTc5LjM2OCAwLTEwMS45NTctLjE1My0yLjU2My0uNDIyLTcuNTktLjYwMi0xMS4xNDUtLjE4My0zLjU1NS0uNDUzLTguMjU0LS42MDUtMTAuMzk0LS4xOC0yLjE2OC0uNTctNy41LS45MDMtMTEuODk1LS4zMzItNC4zOTgtLjY2NC04LjUyNy0uNzU0LTkuMTg3LS4wOS0uNjY1LS4zNTktMy41ODYtLjYwMS02LjQ3Ny0uMjQyLTIuODktLjUxMi01LjYwMi0uNjAyLTYuMDIzLS4wOS0uNDIyLS40MjItMy4xOTYtLjc1NC02LjE3Ni0uNzgtNy4yLTEuNzQ2LTE1LjE0OS0xLjk1Ny0xNi4wODItLjA5LS40MjItLjQyMi0yLjgzMi0uNzU0LTUuMzA1LTEuNDc2LTExLjI2Mi00LjIxNC0yNi45NTctNi41NjYtMzcuNjQ4LS4zMzItMS41MDgtLjg3MS0zLjk0Ni0xLjIwMy01LjQyMi0uODQ0LTMuODU2LTEuODQtNy43NDItMi4xNjgtOC40MzQtLjE1Mi0uMzMyLS40MjItMS4xNDQtLjYzMy0xLjgwOC0uNjY0LTIuMjI3LTQuMDA4LTkuNjY4LTQuODUxLTEwLjg0NC0uMTIyLS4xOC0xLjA4Mi0xLjU5NC0yLjExLTMuMTYtMi4xMzctMy4yMjMtNy42MTctOC45NDYtMTAuOTAyLTExLjM1Ni02LjUwNC00Ljc4OS0xMy43MzUtOC4wNDMtMjMuMDctMTAuMzMyYTQ0MC45MzIgNDQwLjkzMiAwIDAgMS00LjgyLTEuMjA3Yy0xLjExNC0uMzI4LTMuMzQ1LS44MTItOC4xMzQtMS44MDVhMzk2LjMxNyAzOTYuMzE3IDAgMCAxLTQuMDY2LS44NzVjLTUuODEzLTEuNDE0LTI0LjczLTQuNDg4LTM3LjA0Ny02LjA1NC0yLjQ3My0uMzAxLTQuOTEtLjYzMy01LjQyMi0uNzUtLjkwNi0uMTg0LTUuMjczLS42MzMtMTQuMTU2LTEuNTA4LTIuNDczLS4yNDItNS44NzUtLjYwMi03LjUzMS0uNzU0LTEuNjU2LS4xOC00LjY0LS40NS02LjYyNS0uNjMzLTEuOTg5LS4xNDgtNS4yNDItLjQyMi03LjIzLS41Ny02Ljc0Ny0uNTc0LTI1LjQ4MS0xLjY1Ni0zNS44NDQtMi4xMS0yMC4wMzItLjg3NC01Ny4wMi0xLjE0NC03OS45Ny0uNTdaTTg1Ljk2NSAyMTQuMDk4Yy4xOC4xNDggMS4wNTUuNDIyIDEuOTI2LjYzMiAxLjYyOS4zOTEgMy45MTggMS40NDYgNS42MzIgMi41OSAxLjM1Ni45MDMgNC41NTEgNC4zMzYgNS4xOCA1LjU0My4zMDUuNjAyLjYzMyAxLjE0NS43MjMgMS4yMzUuMDk0LjA5LjM2My42OTEuNjA1IDEuMzU1LjIxMS42Ni40OCAxLjM1Ni42MzMgMS41MDQuMzkuNTc0Ljg0NCA0LjE1Ni44NDQgNi44MDkgMCAyLjU5LS4zOTUgNS42MzItLjkwNiA2Ljc0Ni0xLjYyNSAzLjczNC0yLjQxIDQuOTY4LTQuNDU3IDcuMTQtMS44OTkgMS45NTctMi42OCAyLjU1OS01LjI3IDMuODI1LTIuMTEgMS4wNTQtMy42MTcgMS41OTctNC44MiAxLjcxNC0uOTY1LjEyMS0xLjgwOS4zMzItMS44OTkuNDU0LS4yMS4zNjMtNi43NDYuMzYzLTYuNzQ2IDAgMC0uMTIyLS43NTQtLjMzMy0xLjcxOS0uNDU0LS45MzMtLjExNy0yLjEwNS0uMzktMi42MTctLjYwMWEzMC45OTggMzAuOTk4IDAgMCAwLTEuOTg4LS44MTNjLS41NzQtLjIxLTEuMTE3LS40NTMtMS4yMDctLjU0My0uMDktLjEyLS41NDMtLjM5LTEuMDU1LS42MzItMS43NDYtLjg3Mi01LjM2LTQuODgtNi40MTQtNy4wNzktLjU3NC0xLjE3NS0xLjExMy0yLjMyLTEuMjY1LTIuNTU4LTEuMDI0LTIuMDUtMS4yMDQtMTEuMzg3LS4yNDMtMTMuNTU1LjI3NC0uNTc0LjY2NC0xLjUzNS44NzUtMi4xMS4yMTEtLjU3LjQ1My0xLjExMy41NDMtMS4yMDIuMDktLjA5LjQ1LS42OTYuNzgyLTEuMzU2LjU3NC0xLjExNyA0LjE1Ni00Ljk3MiA0LjY2OC00Ljk3Mi4xMiAwIC4zOTQtLjIxMS42MDUtLjQ4LjU3LS42MzQgMy40OTItMi4wNDggNS4yNy0yLjUuODQzLS4yMTIgMS43NzctLjUxMyAyLjEwOS0uNjY1LjMzMi0uMTQ4IDEuMTQ0LS4zIDEuODA1LS4zOSAxLjc3Ny0uMTggOC4wMTUuMDkgOC40MDYuMzYzWm0zMjguMTkxIDIwLjk5MnYxNS4yMWgtNTguNDMzdi0yMC4zNTlsMy4yNTQtLjUxNWM3LjE5OS0xLjExMyAxMS42ODctMS44NjcgMTEuOTU3LTIuMDQ3LjE4LS4xMjEgMS42NTYtLjM2IDMuMzEyLS41NyAxLjY1Ni0uMjExIDMuMTY0LS40ODUgMy4zMTMtLjYwNi4xODMtLjExNyAxLjU5Ny0uMzkgMy4xNjQtLjYwMSAxLjU2Ni0uMTggMy42MTMtLjU0MyA0LjUyLS43ODIuOTAyLS4yMSAyLjgtLjU0MyA0LjIxNC0uNzIyIDEuNDE4LS4xODQgMi44MzItLjQ1MyAzLjE2NC0uNTc1LjMzMi0uMTQ4IDEuODM2LS40MjEgMy4zMTMtLjYzMiAxLjUwNy0uMTggMy4xOTEtLjQ1IDMuNzY1LS42MzMuNTctLjE0OSAyLjc0Mi0uNTcgNC44Mi0uOTAzIDIuMDc5LS4zMzIgNC43OS0uNzggNi4wMjQtLjk5MiAxLjIzNC0uMjQyIDIuNTU5LS40MjIgMi45NS0uNDUzbC42NjMtLjAzMVptLTI0OS4zOTggMTMuNDMzdjE4LjA0M2gzMC4xMnYyNi44MDlIMTY0LjczbC4xMTggMjcuOTIyYy4wOTMgMzAuMDkuMDMgMjguNjEzIDEuNjYgMzIuMzE2IDEuMjM0IDIuODY0IDQuNzI2IDUuNzg1IDcuNzM4IDYuNTA4LjUxMi4xMjEgMS4wODYuMzYgMS4zMjguNTQzLjU3LjQ1IDEyLjc3LjQ1IDEzLjMxMy0uMDMxLjIzOC0uMTggMS4zMjQtLjQyMiAyLjQ2OC0uNTQzbDIuMDItLjIxMXYyNi40MThsLS44MTYuMzZjLS43NS4zMzEtNC4yMTUuODc0LTguOTczIDEuNDQ1LTYuNzc3Ljc4NS0xOS4xMjkuODc1LTE5Ljg1Mi4xMi0uMTgtLjE0OC0uNjYtLjI2OS0xLjExMy0uMjY5LTEuMTc2IDAtNi4wNTUtLjkwNi02LjQxOC0xLjE3Ni0uMTgtLjEyLS45OTItLjQyMi0xLjgzNi0uNjAxLS44MTItLjIxMS0xLjYyNS0uNDg1LTEuODA4LS42MDItLjE0OS0uMTUyLS44NC0uNDIyLTEuNTA0LS42MzMtLjY2NC0uMjEtMS4yNjYtLjQ4NC0xLjM1Ni0uNTc0LS4wOS0uMDktLjYzMy0uNDIyLTEuMjA3LS43NTQtMi41LTEuMzI0LTMuMjUtMS44MDQtNC41NzgtMi45MjItLjc4MS0uNjMyLTEuNTA0LTEuMTcxLTEuNjU2LTEuMTcxLS4zMDEtLjAzMi0yLjU5LTIuNTMyLTQuMzk1LTQuODItMS4zODYtMS43NzgtMy40MzctNS4xOC00LjEyOS02LjkzLS4yNDItLjU3LS41MTEtMS4xMTQtLjYwMS0xLjIwNC0uMTIxLS4wOS0uNDIyLTEuMDIzLS43MjMtMi4xMDktLjI3My0xLjA4Mi0uNjMzLTIuMjI3LS43ODUtMi41NTktLjE0OC0uMzMyLS41MTItMS42ODctLjc1LTMuMDExYTE0NC4yODYgMTQ0LjI4NiAwIDAgMC0uODE2LTMuNzY2Yy0uMjExLS45MDItLjM2LTExLjUwOC0uNDUtMzEuNTY2bC0uMTItMzAuMThoLTE3LjQ0MnYtMjYuODA5aDE3LjQ3M3YtMzAuMzYzbDIuMDQ2LS4yMWMxLjExNC0uMTE4IDIuMTY4LS4zMjkgMi4zMi0uNDUuMTgtLjEyMSAxLjY1Ny0uMzkgMy4zMTMtLjYwMiAxLjY1Ni0uMjEgMy4xNjQtLjUxNSAzLjMxMy0uNjMyLjE4LS4xMjEgMi4wNzgtLjQ1NCA0LjIxOC0uNzIzIDIuMTY4LS4zMDUgNC4wNjctLjYzMyA0LjIxNS0uNzU0LjE4LS4xMjEgMS4xNzYtLjMzMiAyLjI1OC0uNDIyYTQ5LjcxOSA0OS43MTkgMCAwIDAgNC4yMTktLjY5MWMzLjIyMy0uNjY0IDguODU1LTEuNTQgOS4xMjUtMS4zODcuMTIxLjA1OS4yMSA4LjI1NC4yMSAxOC4xOTFabTk5Ljg1MSAxNS4xOGM0LjIxNS4yNDIgOC45NzcuNzg1IDkuMzM2IDEuMDU1LjE4LjEyLjkwMy4zMzIgMS42NTcuNDIyIDEuNzE4LjI3MyA1LjkwNiAxLjUwNyA4LjQzMyAyLjUzIDIuMTEuODQ1IDYuODA5IDMuMTkyIDcuNTMxIDMuNzk4LjI0My4xOC43ODIuNTM5IDEuMjA0LjcyMi40MjEuMjExIDEuNzUgMS4yNjIgMi45MjEgMi4yOSAxLjE3NiAxLjA1NCAyLjI2MiAxLjk1NyAyLjQxIDIuMDE1LjQ1NC4yMTEgNS44MTMgNi43MTkgNS44MTMgNy4wNzggMCAuMDkuMjc0LjU3NS42MDYgMS4wMjQuNjMyLjkwNiAzLjMxMiA2LjExNyAzLjMxMiA2LjQ0OSAwIC4xMTcuMjQyLjc4MS41NyAxLjQ3My4zMDEuNjk1LjY2NCAxLjc1Ljc4NiAyLjMyLjEyLjU3NC4zMzIgMS4xNzYuNDQ5IDEuMzU1LjEyLjE1My4zOTQgMS4xMTQuNjA1IDIuMTEuMTguOTkyLjQyMiAyLjAyLjUxMiAyLjI1OC4xMjEuMjQyLjM5IDEuNTM1LjYzMyAyLjg2My4zNiAxLjk4OC40NDkgOS40ODguNTcgNDIuNjhsLjEyMSA0MC4zaC0zMi44NmwtLjAzLTMuNTU0Yy0uMDMyLTEuOTI2LS4xMjItNC43MjctLjI0My02LjIwNGwtLjE4LTIuNzEtLjg3NCAxLjIwM2MtMS4zODMgMS44NC01LjkzNCA2LjE3NS03LjczOSA3LjM3OS0zLjk0OSAyLjU5My01IDMuMjIyLTYuMDg2IDMuNTg2LS42NjQuMTgtMS41MzUuNTQzLTEuOTU3Ljc4LS40NTMuMjEyLTEuNTY2LjU3NS0yLjQ3Mi43NTUtLjkwMy4yMS0xLjgwNS40ODQtMS45NTcuNjAxLTEuNTM1IDEuMTQ1LTIwLjUxMiAxLjExNy0yMS45ODktLjAyNy0uMTQ4LS4xMjEtMS4yMzQtLjM5LTIuNDEtLjYwMi0xLjE0NC0uMjEtMi41LS41NDMtMy4wMTEtLjc4NS0uNDgtLjIxLTEuNzc4LS43NTQtMi44MjktMS4xNzZhNDIuNDIgNDIuNDIgMCAwIDEtMy41NTQtMS43NDYgNDkuODY2IDQ5Ljg2NiAwIDAgMC0yLjQ0Mi0xLjQxNGMtMS4yNjUtLjY5NS0xLjY4Ny0xLjA4Ni01LjEyLTQuNTItMy41MjQtMy41MjMtMy45NzctNC4wMDMtMy45NzctNC4zMzUgMC0uMTIxLS4zOTEtLjc4NS0uODQtMS40NzctLjQ4NS0uNjkxLTEuMTc2LTEuOTU3LTEuNTQtMi43NzMtLjM1OS0uODQtLjg0My0xLjgzNi0xLjA1NC0yLjI1OC0uMjM4LS40MjItLjU3LTEuNTA0LS43ODEtMi40MS0uMjExLS45MDMtLjQ4LTEuODA1LS42MDItMS45NTctLjMzMi0uNDIyLS45MDYtNC43LS45MDYtNi41NjcgMC0uODctLjE0OC0xLjc0Ni0uMzI4LTEuOTI1LS4zNjMtLjM2NC0uMjc0LTEuNTY3LjY2LTguODI5LjE4LTEuNDE0LjQ1My0yLjcxLjU3NC0yLjg1OS4xMjEtLjE4LjM5LS45NjUuNTctMS43NzcuMzkxLTEuNTY3IDEuMjA4LTMuNjE0IDIuMDUxLTUuMTUzLjI3LS41MTEuNjMtMS4yMDMuODEzLTEuNTY2LjE4LS4zOS40MjItLjY5MS41Ny0uNjkxLjEyMSAwIC4yMTEtLjE4LjIxMS0uMzkxIDAtLjMzMiAzLjMxMy00LjY0IDMuODg3LTUuMDMxLjEyLS4wOS4zMzItLjM5LjQyMi0uNjkyLjEyLS4zMzIuNDgtLjYzMi44MTItLjcyMi4zMzItLjA5LjYwMi0uMjc0LjYwMi0uMzk1IDAtLjMgNS4wNjItNC4yNzcgNi43NzctNS4yNyAxLjIzNC0uNzUzIDQuMDA4LTIuMTY3IDguMDQzLTQuMDk3LjU3NC0uMyA2LjIwMy0yLjEwNiA4LjY3Ni0yLjguOTAyLS4yNyAyLjY4LS42MzQgMy45MTQtLjgxMyAxLjIzNC0uMjExIDIuNDEtLjQ1MyAyLjU2Mi0uNTcuMTgtLjEyMiAxLjk4NS0uMzk1IDQuMDY3LS41NzUgMi4wNzgtLjE4IDQuNjM3LS40OCA1LjcyMi0uNjMzIDQuMjc4LS42MzIgMTkuMzA1LS41MTEgMjAuOTAzLjE1My41NDMuMjM4LjU3LjEyLjM2LTIuNDQyLS4xMTgtMS40NzYtLjMyOS0yLjc0Mi0uNDUtMi44MzItLjE1Mi0uMDktLjMzMi0uNjYtLjQ1My0xLjI2NS0uMjExLTEuMTE0LTEuMzU2LTMuNTUxLTIuNDM4LTUuMjExLS42OTUtMS4wNTEtMy42MTctNC4wNjctMy45NDktNC4wNjctLjExNyAwLS42MjktLjMtMS4xNDQtLjY5MS0xLjMyNS0uOTY1LTMuNDYxLTEuOTI2LTQuNzU4LTIuMTY4LS42MzMtLjEyMS0xLjE0NS0uMzMyLTEuMTQ1LS40NTMgMC0xLjMyNC0xOS40NTctMS41MzUtMjUuMy0uMjM5LS43NTQuMTQ5LTIuNS40OC0zLjkxNS43MjMtMS40MTguMjM4LTIuODMyLjU3LTMuMTY0LjcyMy0uMzMyLjE0OC0xLjQxNC40MjItMi40MS42MDEtLjk5Mi4xOC0yLjA3OC40NTMtMi40MS42MDItLjMzMi4xNTItMS41MzUuNDg0LTIuNjguNzU0LTEuMTQ0LjI3LTIuMjMuNTctMi40MS43MjItLjE4LjEyMi0uOTkyLjQyMi0xLjgzNi42MzMtLjgxMi4yMTEtMS42NTYuNTEyLTEuODA4LjYzMy0uMTguMTIxLS45OTMuMzktMS44MDkuNjAyLS44NC4xOC0yLjAxNi42MDEtMi42MTcuOTAyLS42MzMuMzMyLTEuMjA3LjU3NC0xLjI5Ny41NzQtLjA5IDAtLjE1Mi02LjI5Ny0uMTUyLTEzLjk3NiAwLTEwLjg3NS4wOTMtMTQuMDM2LjM5NC0xNC4yNzguMjExLS4xOCAxLjA1NS0uNDggMS44NjctLjY5MS44NDQtLjE4IDEuNjU3LS40NTMgMS44MDUtLjU3NC4xODQtLjEyMSAxLjE3Ni0uNDggMi4yNjItLjc1NCAxLjA4Mi0uMzAxIDIuMTA1LS42MyAyLjI1OC0uNzUuMTgtLjE1MyAxLjExMy0uMzk1IDIuMDc4LS42MDIuOTk2LS4yMSAyLjAyLS40ODQgMi4yNTgtLjYzMy4yNzMtLjEyIDEuNTA3LS40NTMgMi43NDItLjcyMmE1OC45NSA1OC45NSAwIDAgMCAyLjg2My0uNjMzYy4zMjgtLjA5NCAyLjAxNi0uMzYzIDMuNzYyLS42MDYgMS43NS0uMjM4IDMuNTg2LS41NyA0LjA2Ni0uNzIyIDEuNzUtLjU0IDE3LjUzMS0xLjUzNSAyMS4wODYtMS4zMjQuOTkyLjA1OCAzLjE2NC4xOCA0LjgyLjI3Wk05OC40OTIgMzI2LjUwOHY1OS45MzdINjMuMjU0VjI2Ni41NjZoMzUuMjM4Wm0yNjYuMjY2LTIyLjU5NGMwIDM1LjY2NC4xNTIgNDIuNTYzLjg3NSA0My41MjcuMTQ4LjE0OS4zMzIuNzUuNDUzIDEuMzI1LjQyMiAyLjI1NyAyLjM3OSA1LjU0MyA0LjYwNSA3Ljc3IDEuMTc2IDEuMjA2IDIuNSAyLjI2IDIuOTIyIDIuMzc4LjQ1My4wOTQuNzg1LjI3NC43ODUuMzk1IDAgLjExNyAxLjA1NS41MzkgMi4zNDguOTYgMS45My42MDYgMi45NTMuNzIzIDUuOTY1LjcyMyAyLjExIDAgMy45NDUtLjE0OCA0LjM2Ny0uMzI4LjM5LS4yMSAxLjMyNC0uNTEyIDIuMDc4LS43MjMuNzU0LS4yMSAyLjExLS44NDMgMy4wMTItMS40NDkgMS42ODctMS4wODIgNC44Mi0zLjk3MiA0LjgyLTQuNDU3IDAtLjE0OC40MjItLjgxMi45MDMtMS40NDUuNTExLS42NjQuOTA2LTEuMzI0LjkwNi0xLjUwNCAwLS4xODQuMjctLjgxNi41Ny0xLjQxOC4zMzItLjYwMi42OTItMS42MjUuODEzLTIuMjU4LjA5LS42NjQuMy0xLjMyNC40NTMtMS40NzYuNzU0LS45NjUuODc1LTcuMDQ3Ljg3NS00Mi4zOHYtMzYuOTg4aDM1LjIzOHYxMTkuODhINDIwLjA2Yy0xMy4wNCAwLTE2Ljc3OC0uMDktMTYuOTU3LS4zOTEtLjEyMi0uMTgtLjI3LTMuMDQzLS4zMzItNi4zMjUtLjA2LTMuMjUzLS4yMTEtNS45MzMtLjMyOS01LjkzMy0uMTIgMC0uNDg0LjM2LS44NDMuODEyLTEuNjg4IDIuMjktNC4zNCA0Ljg4LTguNDk2IDguMzEzLS42MDIuNDgtMS44MzYgMS4xNDQtNC41NDcgMi40NjktMS4yMzUuNjAxLTIuNTkgMS4yOTYtMy4wMTIgMS41MDctLjQyMi4yMTEtMS41NjYuNTQzLTIuNTYzLjc1NC0uOTkyLjIxMS0xLjg2Ny40OC0xLjk1Ny42MDItLjMuNDUtNS42MzIuOTAyLTEwLjkwMi45MDItNS4xOCAwLTkuMzk4LS4zNi0xMC42MzMtLjg3NS0uMzMyLS4xNDgtMS40NzYtLjUxMS0yLjU2Mi0uNzgxLTEuMDgyLS4yNy0yLjA3OC0uNjMzLTIuMjU4LS43NTQtLjE0OC0uMTIxLS44NzEtLjQyMi0xLjU2Ni0uNjMzLS43MjMtLjE4LTEuMjkzLS40NDktMS4yOTMtLjU3IDAtLjEyMS0uNTQzLS4zOS0xLjIwNy0uNjAyLS42Ni0uMjEtMS4yMDQtLjQ4NC0xLjIwNC0uNjA1IDAtLjExNy0uMzMyLS4zNi0uNzIyLS41NC0yLjU5LTEuMTc1LTguNDY1LTYuNjg3LTEwLjkzNC0xMC4yNDEtMS41MDgtMi4xNjgtMy44MjgtNi41MDgtNC4zMDgtOC4xMDItLjE4LS42MzMtLjU0My0xLjU2Ni0uNzU0LTIuMDUtLjIxMS0uNTEyLS41Ny0xLjU5NC0uNzU0LTIuNDEtLjE4LS44NC0uNDUtMS43MTYtLjYwMi0yLjAxNi0uMTQ4LS4yNzQtLjQyMi0xLjY4OC0uNjAxLTMuMTY0LS4xOC0xLjQ0Ni0uNTEyLTIuOTIyLS42OTItMy4yNTQtLjI3My0uNDUtLjM5NC0xMS4yMDQtLjQ1My00My4zMTNsLS4wOS00Mi42OGgzNS4yN1ptMCAwIiBzdHlsZT0ic3Ryb2tlOm5vbmU7ZmlsbC1ydWxlOm5vbnplcm87ZmlsbDojRkY2MjAwO2ZpbGwtb3BhY2l0eToxIi8+PHBhdGggZD0iTTI2MC42OTEgMzMzLjE2NGMtMS40NzIuMTQ5LTIuOTguMzktMy4zMTIuNTQtLjMzMi4xODMtMS40MTQuNDUyLTIuNDEuNjYzLS45NjEuMTgtMi4yNTguNTQzLTIuODYuODEzLTQuNTIgMS45NTctNi43MTggMy4yNTQtOC4yMjIgNC44Mi0xLjQ0NiAxLjUwOC0yLjg5NSA0LjMwOS0zLjEzMyA2LjA1NS0uMDYzLjYwMS0uMjc0IDEuMzg2LS40NTMgMS43MTUtLjMzMi42OTUtLjIxMSAyLjgzMi4zMzIgNS42MzIuNjAxIDMuMDQzIDMuMDEyIDYuNzUgNS4xNDggNy44NjQgMy43OTcgMS45NTcgNC41MiAyLjI1NyA2LjYzIDIuNTkgMy43OTIuNTcgMTEuMDIzLjI0MiAxMi41ODktLjYwMi4yNy0uMTUyIDEuMzg3LS42NjQgMi40NjktMS4xNDUgMS4wODYtLjUxMSAyLjUtMS4zMjggMy4xNjQtMS44NC42NjQtLjUxMSAxLjQxNC0xLjExMyAxLjY4Ny0xLjMyNCAxLjcxNS0xLjI5MyA0Ljg4LTYuNTM1IDUuMzAxLTguNzAzLjA5LS41NDMuMzMyLTEuMTc2LjUxMi0xLjQxOC4yMS0uMjcuMzYtMy4wNDMuNDIyLTguMDEybC4xMi03LjU5LTEuNjI4LS4xNzljLTIuMi0uMjczLTEzLjA0LS4xOC0xNi4zNTYuMTIxWm0wIDAiIHN0eWxlPSJzdHJva2U6bm9uZTtmaWxsLXJ1bGU6bm9uemVybztmaWxsOiNGRjYyMDA7ZmlsbC1vcGFjaXR5OjEiLz48L3N2Zz4=",
|
|
18
|
+
bradesco: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjUwMCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMzc4Ljc2MjM0IDM3OC44MDYiIHZlcnNpb249IjEuMSIgaWQ9InN2ZzEwIiBzb2RpcG9kaTpkb2NuYW1lPSJicmFkZXNjby5zdmciIGlua3NjYXBlOnZlcnNpb249IjEuMi4yICg3MzJhMDFkYTYzLCAyMDIyLTEyLTA5KSIgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4gPGRlZnMgaWQ9ImRlZnMxNCIgLz4gPHNvZGlwb2RpOm5hbWVkdmlldyBpZD0ibmFtZWR2aWV3MTIiIHBhZ2Vjb2xvcj0iIzUwNTA1MCIgYm9yZGVyY29sb3I9IiNlZWVlZWUiIGJvcmRlcm9wYWNpdHk9IjEiIGlua3NjYXBlOnNob3dwYWdlc2hhZG93PSIwIiBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMCIgaW5rc2NhcGU6cGFnZWNoZWNrZXJib2FyZD0iMCIgaW5rc2NhcGU6ZGVza2NvbG9yPSIjNTA1MDUwIiBzaG93Z3JpZD0iZmFsc2UiIGlua3NjYXBlOnpvb209IjAuMTUzMzAwNzUiIGlua3NjYXBlOmN4PSIxODE5Ljk1MiIgaW5rc2NhcGU6Y3k9IjE1MjYuNDExMyIgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxOTIwIiBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMDA5IiBpbmtzY2FwZTp3aW5kb3cteD0iLTgiIGlua3NjYXBlOndpbmRvdy15PSItOCIgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0iZzgiIC8+IDxnIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpZD0iZzgiPiA8cGF0aCBkPSJNIC0wLjAxMTkyODE0LDAuMjA0NzA0MDggSCAzNzguNzE5NTUgViAzNzguOTEwNDQgSCAyMjIuMDc3NTQgViAyMjIuMDE5MjYgSCAxODcuNzQyNjggViAzNzguOTEwNDQgSCAxNjkuNTAzMDMgViAyNzEuNzk0MjkgSCAxNTIuMzM4NyBWIDM3OC45MTA0NCBIIC0wLjAxMTkyODE0IFogTSAxMi44NTk3NzUsMTMyLjIxMjEgQyAzMi44ODM3OTksMTIzLjE5OTM3IDUyLjkxMDI5OCwxMTQuMTgxNjQgNzIuOTQyOTg0LDEwNS4xNjE0MyAxNTMuMzYzMjksLTcuODgzNDU5NiAyNTcuODM1NDMsMzQuOTE0OSAyOTUuMDMyNDUsODguOTMxNTIyIDIwOC40ODE5NCwzMy4wMjk2MTQgMTQ0LjQ2MzcxLDYxLjUyNDQ3MiAxMTIuNjQwODQsOTkuNzUyMjkgMzU1LjgzODMxLDc0LjMxNTI1OSA0MTYuNjM1NTIsMjIzLjYzNDE0IDI4NS4zNzU1OCwyNzguMjgzNzYgNDAxLjYwMjAzLDE4NC4xNDc4MSAyNTMuOTAwNDEsMTA3LjMyNDU4IDk5Ljc2NzksMTE0Ljg5ODEzIDYyLjc0MTY0NSwxODMuNzgyNzIgNzQuODk1NjQyLDIzNC42MzgwOCAxMDkuNDIxMDUsMjgwLjQ0NjkyIDcyLjE5NDM0MSwyNTEuNzA3ODQgNDcuNTA1MjIyLDIwOS43MDMyMiA2Ny41Nzg3NDMsMTIwLjMwODUxIDQ5LjMzNzg0OSwxMjQuMjc5NyAzMS4wOTY5NTYsMTI4LjI0NTkgMTIuODU5Nzc1LDEzMi4yMTIxIFoiIGZpbGw9IiNjYzIyMjkiIGlkPSJwYXRoMiIgc3R5bGU9InN0cm9rZS13aWR0aDoxLjI0MTc0IiAvPiA8L2c+IDwvc3ZnPg==",
|
|
19
|
+
bb: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjUwMCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMTkyLjc1NiAxOTIuNzU2IiB2ZXJzaW9uPSIxLjEiIGlkPSJzdmcxMCIgc29kaXBvZGk6ZG9jbmFtZT0iYmFuY28tZG8tYnJhc2lsLXNlbS1mdW5kby5zdmciIGlua3NjYXBlOnZlcnNpb249IjEuMi4yICg3MzJhMDFkYTYzLCAyMDIyLTEyLTA5KSIgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4gPGRlZnMgaWQ9ImRlZnMxNCIgLz4gPHNvZGlwb2RpOm5hbWVkdmlldyBpZD0ibmFtZWR2aWV3MTIiIHBhZ2Vjb2xvcj0iIzUwNTA1MCIgYm9yZGVyY29sb3I9IiNlZWVlZWUiIGJvcmRlcm9wYWNpdHk9IjEiIGlua3NjYXBlOnNob3dwYWdlc2hhZG93PSIwIiBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMCIgaW5rc2NhcGU6cGFnZWNoZWNrZXJib2FyZD0iMCIgaW5rc2NhcGU6ZGVza2NvbG9yPSIjNTA1MDUwIiBzaG93Z3JpZD0iZmFsc2UiIGlua3NjYXBlOnpvb209IjAuMjE2OCIgaW5rc2NhcGU6Y3g9IjEyNTAiIGlua3NjYXBlOmN5PSIxMjUwIiBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE5MjAiIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEwMDkiIGlua3NjYXBlOndpbmRvdy14PSItOCIgaW5rc2NhcGU6d2luZG93LXk9Ii04IiBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIiBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJzdmcxMCIgLz4gPGcgZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGlkPSJnOCI+IDxwYXRoIGZpbGw9IiMzMzM0OGUiIGQ9Ik05Ni4zOTYgMTYuOTI1bC03OC44NSA1Mi44NSAzMi44MTkgMjEuMzExTDg5LjU3NyA2NC42NiA3NC4wMjMgNTQuNDQzbDIxLjMwNS0xNC4yNzQgNDYuMjMxIDMwLjY3OS03NS44NDUgNTAuOTE4IDE2LjQwNSAxMC44NjUgOTQuMzc5LTYyLjg0OC0uMjEzLS4yMTMtNzkuODg5LTUyLjY0NXpNMTc1LjAyNyAxNi45NDdsLTMyLjgwOCAyMS43MzEgMTYuNDA0IDExLjA3OCAxNi40MDQtMTEuMDc4VjE2Ljk0N3pNMTcuMDA1IDE3NS44MzJsMzIuODA5LTIxLjczLTE2LjQwNC0xMS4wNzktMTYuNDA1IDExLjA3OXYyMS43M3oiIGlkPSJwYXRoNCIgLz4gPHBhdGggZmlsbD0iIzMzMzQ4ZSIgZD0iTTk2LjM2IDE3NS43ODdsNzguODQ5LTUyLjg1MS0zMi44MTgtMjEuMzExLTM5LjIxMSAyNi40MjYgMTUuNTUyIDEwLjIxNy0yMS4zMDQgMTQuMjc1LTQ2LjIzMS0zMC42OCA3NS44NDQtNTAuOTE3LTE2LjQwNC0xMC44NjYtOTQuMzggNjIuODQ4LjIxMy4yMTUgNzkuODkgNTIuNjQ0eiIgaWQ9InBhdGg2IiAvPiA8L2c+IDwvc3ZnPg==",
|
|
20
|
+
caixa: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjUwMCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMTkyLjc1NiAxOTIuNzU2IiB2ZXJzaW9uPSIxLjEiIGlkPSJzdmc3NDI5IiBzb2RpcG9kaTpkb2NuYW1lPSJjYWl4YS1lY29ub21pY2EtZmVkZXJhbC1YLnN2ZyIgaW5rc2NhcGU6dmVyc2lvbj0iMS4yLjIgKDczMmEwMWRhNjMsIDIwMjItMTItMDkpIiB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPiA8ZGVmcyBpZD0iZGVmczc0MzMiIC8+IDxzb2RpcG9kaTpuYW1lZHZpZXcgaWQ9Im5hbWVkdmlldzc0MzEiIHBhZ2Vjb2xvcj0iIzUwNTA1MCIgYm9yZGVyY29sb3I9IiNlZWVlZWUiIGJvcmRlcm9wYWNpdHk9IjEiIGlua3NjYXBlOnNob3dwYWdlc2hhZG93PSIwIiBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMCIgaW5rc2NhcGU6cGFnZWNoZWNrZXJib2FyZD0iMCIgaW5rc2NhcGU6ZGVza2NvbG9yPSIjNTA1MDUwIiBzaG93Z3JpZD0iZmFsc2UiIGlua3NjYXBlOnpvb209IjAuMTUzMzAwNzUiIGlua3NjYXBlOmN4PSIyOTMuNTQwNjQiIGlua3NjYXBlOmN5PSIxNDgwLjc0OTQiIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTkyMCIgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTAwOSIgaW5rc2NhcGU6d2luZG93LXg9Ii04IiBpbmtzY2FwZTp3aW5kb3cteT0iLTgiIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9InN2Zzc0MjkiIC8+IDxnIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpZD0iZzc0MjciIHRyYW5zZm9ybT0ibWF0cml4KDQuNDMzNTkwOCwwLDAsNC40MzM1OTA4LC00NDguMTk1NzEsLTMyNi4wNzg1OCkiPiA8cGF0aCBkPSJtIDExNC43MjUsOTcuNjU2IGggMTQuNjM2IGwgMTAuMDMsMTYuNjEyIGggLTE0LjYzOSB6IiBmaWxsPSIjMGQ2ZmFiIiBpZD0icGF0aDc0MjEiIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+IDxwYXRoIGZpbGw9IiNkYjgxMzUiIGQ9Im0gMTE2LjI0Niw5NS4xMDQgaCAxNS4xMjkgbCAxMy4xMzksLTE2LjU0IGggLTE1LjEyOSB6IG0gLTE1LjEyOSwxOS4yNjUgaCAxNS4xMjkgbCAxMy4xMzksLTE2Ljc0NCBoIC0xNS4xMjkgeiIgaWQ9InBhdGg3NDIzIiAvPiA8cGF0aCBmaWxsPSIjMGQ2ZmFiIiBkPSJtIDEwNi41NzIsNzguMzYyIGggMTQuMTIxIGwgOS42NzQsMTYuNzQyIGggLTE0LjEyMSB6IiBpZD0icGF0aDc0MjUiIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+IDwvZz4gPC9zdmc+",
|
|
21
|
+
santander: "data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjI1MDAiIHZpZXdCb3g9IjAgMC40IDIzOC4yIDI0MC43MTkyNiIgd2lkdGg9IjI1MDAiIHZlcnNpb249IjEuMSIgaWQ9InN2ZzQiIHNvZGlwb2RpOmRvY25hbWU9ImJhbmNvLXNhbnRhbmRlci1sb2dvLnN2ZyIgaW5rc2NhcGU6dmVyc2lvbj0iMS4yLjIgKDczMmEwMWRhNjMsIDIwMjItMTItMDkpIiB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPiA8ZGVmcyBpZD0iZGVmczgiIC8+IDxzb2RpcG9kaTpuYW1lZHZpZXcgaWQ9Im5hbWVkdmlldzYiIHBhZ2Vjb2xvcj0iIzUwNTA1MCIgYm9yZGVyY29sb3I9IiNlZWVlZWUiIGJvcmRlcm9wYWNpdHk9IjEiIGlua3NjYXBlOnNob3dwYWdlc2hhZG93PSIwIiBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMCIgaW5rc2NhcGU6cGFnZWNoZWNrZXJib2FyZD0iMCIgaW5rc2NhcGU6ZGVza2NvbG9yPSIjNTA1MDUwIiBzaG93Z3JpZD0iZmFsc2UiIGlua3NjYXBlOnpvb209IjAuMTczMzgyNTgiIGlua3NjYXBlOmN4PSItNDAuMzczMTQ0IiBpbmtzY2FwZTpjeT0iMTEwMS42MTAxIiBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE5MjAiIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEwMDkiIGlua3NjYXBlOndpbmRvdy14PSItOCIgaW5rc2NhcGU6d2luZG93LXk9Ii04IiBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIiBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJzdmc0IiAvPiA8cGF0aCBkPSJtIDE3MS43MzY1LDExMS43MjI0NyBjIC0wLjU0Nzk4LC04LjY2Mjc2IC0yLjczOTg2LC0xNy4zMjU1MTkgLTcuMTIzNjUsLTI0LjgzMzI0OCBMIDEyNy4zNTA2OSwxOC4xNjQ2NDEgYyAtMi43Mzk4NSwtNS4xOTc2NTYgLTQuOTMxNzUsLTEwLjk3MjgzMDMgLTYuMDI3NywtMTYuNzQ4MDA2IGwgLTEuNjQzOTIsMi44ODc1ODc1IGMgLTkuMzE1NTMsMTYuNzQ4MDA4NSAtOS4zMTU1MywzOC4xMTYxNTQ1IDAsNTQuODY0MTYxNSBsIDMwLjEzODUsNTQuODY0MTU2IGMgOS4zMTU1NSwxNi43NDggOS4zMTU1NSwzOC4xMTYxNiAwLDU0Ljg2NDE2IGwgLTEuNjQzOSwyLjg4NzU4IGMgLTEuMDk1OTQsLTUuNzc1MTcgLTMuMjg3ODQsLTExLjU1MDM1IC02LjAyNzcxLC0xNi43NDgwMSBMIDExNC43NDczMiwxMDQuNzkyMjYgOTcuMjEyMTg2LDcyLjQ1MTI4NSBDIDk0LjQ3MjMyMSw2Ny4yNTM2MjggOTIuMjgwNDI4LDYxLjQ3ODQ1NCA5MS4xODQ0ODMsNTUuNzAzMjc5IGwgLTEuNjQzOTE5LDIuODg3NTg4IGMgLTkuMzE1NTQxLDE2Ljc0ODAwNiAtOS4zMTU1NDEsMzcuNTM4NjM2IDAsNTQuODY0MTczIGwgMzAuMTM4NTA2LDU0Ljg2NDE0IGMgOS4zMTU1NCwxNi43NDggOS4zMTU1NCwzOC4xMTYxNSAwLDU0Ljg2NDE2IGwgLTEuNjQzOTEsMi44ODc1OSBjIC0xLjA5NTk0LC01Ljc3NTE4IC0zLjI4Nzg0LC0xMS41NTAzNiAtNi4wMjc3MSwtMTYuNzQ4MDEgTCA3NC4xOTczMTksMTQwLjU5ODMzIGMgLTQuOTMxNzU0LC05LjI0MDI3IC03LjEyMzY0NywtMTkuNjM1NTcgLTcuMTIzNjQ3LC0zMC4wMzA4OSAtNDAuMDAyMDMsMTAuOTcyODMgLTY3Ljk0ODY1MDk1LDM0LjY1MTAzIC02Ny45NDg2NTA5NSw2MS43OTQzNSAwLDM4LjExNjE2IDUzLjcwMTM1MTk1LDY4LjcyNDU5IDEyMC4wMDYwNzg5NSw2OC43MjQ1OSA2Ni4zMDQ3MywwIDEyMC4wMDYwOSwtMzAuNjA4NDMgMTIwLjAwNjA5LC02OC43MjQ1OSAwLjU0Nzk2LC0yNS45ODgyOCAtMjYuODUwNjgsLTQ5LjY2NjQ5IC02Ny40MDA2OSwtNjAuNjM5MzIgeiIgZmlsbD0iI2VhMWQyNSIgaWQ9InBhdGgyIiBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2NjY2NjY2NjY2NjY2NjY3NzY2MiIHN0eWxlPSJzdHJva2Utd2lkdGg6NS42MjU1MSIgLz4gPC9zdmc+",
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export function BankLogo({ bank }: { bank: PixBankId }): JSX.Element {
|
|
25
|
+
return (
|
|
26
|
+
<Box
|
|
27
|
+
component="img"
|
|
28
|
+
src={LOGOS[bank]}
|
|
29
|
+
alt=""
|
|
30
|
+
aria-hidden="true"
|
|
31
|
+
data-bank={bank}
|
|
32
|
+
sx={{ width: 32, height: 32, flex: "none", objectFit: "contain", borderRadius: 1 }}
|
|
33
|
+
/>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { PixBankCopy } from "./types";
|
|
2
|
+
|
|
3
|
+
/** The Pix-to-bank flow's words, pt-BR (FUT-3612). */
|
|
4
|
+
export const PT_BR_PIX_BANK_COPY: PixBankCopy = {
|
|
5
|
+
names: {
|
|
6
|
+
nubank: { name: "Nubank", the: "o " },
|
|
7
|
+
itau: { name: "Itaú", the: "o " },
|
|
8
|
+
bradesco: { name: "Bradesco", the: "o " },
|
|
9
|
+
bb: { name: "Banco do Brasil", the: "o " },
|
|
10
|
+
caixa: { name: "Caixa", the: "a " },
|
|
11
|
+
santander: { name: "Santander", the: "o " },
|
|
12
|
+
},
|
|
13
|
+
generateAndCopy: "Gerar e copiar o Pix",
|
|
14
|
+
generateCopyAndOpen: (bank) => `Gerar, copiar e abrir ${bank.the}${bank.name}`,
|
|
15
|
+
copyAndOpen: (bank) => `Copiar e abrir ${bank.the}${bank.name}`,
|
|
16
|
+
openOther: "Abrir outro banco",
|
|
17
|
+
listTitle: "Abra seu banco e cole em Pix copia e cola",
|
|
18
|
+
open: (bank) => `Abrir ${bank.name}`,
|
|
19
|
+
opening: (bank) => `Abrindo ${bank.the}**${bank.name}**…`,
|
|
20
|
+
other: "Outro banco",
|
|
21
|
+
notOpened: (bank) => `Não conseguimos abrir ${bank.the}${bank.name}. O app está instalado neste celular?`,
|
|
22
|
+
retry: "Tentar de novo",
|
|
23
|
+
copied: "Código Pix copiado",
|
|
24
|
+
copiedPick: "Código Pix copiado. Escolha o banco.",
|
|
25
|
+
copiedOpening: (bank) => `Código Pix copiado. Abrindo ${bank.the}${bank.name}…`,
|
|
26
|
+
};
|
|
@@ -106,11 +106,27 @@ export function CardRun({
|
|
|
106
106
|
return submitted ? <SubmittedState card={submit} /> : null;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
/**
|
|
110
|
+
* A refusal a host can fix: its order answers no `amountDueCents`, and its
|
|
111
|
+
* total is not what the sheet showed — the shape of a balance taken off the
|
|
112
|
+
* charge that the order view does not report. Said once in development; the
|
|
113
|
+
* buyer still gets the refusal.
|
|
114
|
+
*/
|
|
115
|
+
function warnMissingAmountDue(order: CheckoutOrder, sheetCents: number): void {
|
|
116
|
+
const development = typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
|
|
117
|
+
if (order.amountDueCents !== undefined || !development) return;
|
|
118
|
+
console.warn(
|
|
119
|
+
`[payments-frontend] Google Pay refused: the order costs ${order.totalCents} cents and the sheet showed ${sheetCents}. ` +
|
|
120
|
+
"A host that takes a balance off the charge must answer CheckoutOrder.amountDueCents.",
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
109
124
|
/**
|
|
110
125
|
* Google Pay: the sheet was opened INSIDE the buyer's tap (`sheet`, priced at
|
|
111
126
|
* `sheetCents`) while the order was raised; its key is charged against that
|
|
112
|
-
* order only if the order
|
|
113
|
-
*
|
|
127
|
+
* order only if the order asks the provider for what the sheet showed — its
|
|
128
|
+
* amount due, which a balance the host holds may have made less than its
|
|
129
|
+
* total. A closed sheet sends nothing more.
|
|
114
130
|
*/
|
|
115
131
|
export function WalletRun({
|
|
116
132
|
order,
|
|
@@ -140,7 +156,10 @@ export function WalletRun({
|
|
|
140
156
|
.then((key) => {
|
|
141
157
|
if (key === null) return onFailed(null);
|
|
142
158
|
// The sheet showed one amount; never charge another under it.
|
|
143
|
-
if (order.totalCents !== sheetCents)
|
|
159
|
+
if ((order.amountDueCents ?? order.totalCents) !== sheetCents) {
|
|
160
|
+
warnMissingAmountDue(order, sheetCents);
|
|
161
|
+
return onFailed(refused);
|
|
162
|
+
}
|
|
144
163
|
return void wallet.payWithKey("GOOGLE_PAY", key);
|
|
145
164
|
})
|
|
146
165
|
.catch(() => onFailed(refused));
|
|
@@ -43,6 +43,8 @@ interface RowProps {
|
|
|
43
43
|
onBuyerChange: (buyer: BuyerInfo) => void;
|
|
44
44
|
provider: string | null;
|
|
45
45
|
failure: ListChargeFailure | null;
|
|
46
|
+
/** The host's balance pays the whole amount: the card asks for no card at all. */
|
|
47
|
+
covered?: boolean;
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
/** One of the store's online options, with what opens inside it. */
|
|
@@ -62,7 +64,7 @@ function OnlineOptionRow({ row, props }: { row: OnlineRow; props: RowProps }): J
|
|
|
62
64
|
onChoose={() => state.choose({ kind: "online", method: row.method })}
|
|
63
65
|
testId={`list-option-${row.method}`}
|
|
64
66
|
>
|
|
65
|
-
{opensContent(row.method, state.asked, props.failure) ? (
|
|
67
|
+
{opensContent(row.method, state.asked, props.failure, props.covered) ? (
|
|
66
68
|
<OnlineContent
|
|
67
69
|
method={row.method}
|
|
68
70
|
asked={state.asked}
|
|
@@ -72,6 +74,7 @@ function OnlineOptionRow({ row, props }: { row: OnlineRow; props: RowProps }): J
|
|
|
72
74
|
copy={copy}
|
|
73
75
|
provider={provider}
|
|
74
76
|
failure={props.failure}
|
|
77
|
+
covered={props.covered}
|
|
75
78
|
/>
|
|
76
79
|
) : null}
|
|
77
80
|
</OptionRow>
|
|
@@ -63,12 +63,32 @@ export function raisedMethod(choice: CheckoutOnlineChoice, offered: PaymentMetho
|
|
|
63
63
|
return "CARD";
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
/**
|
|
67
|
+
* The saved card to choose for the buyer: the one used LAST (owner,
|
|
68
|
+
* 2026-10-15), or the list's head — the host's own order, newest first — when
|
|
69
|
+
* no card says when it was used. A card never used loses to any used one.
|
|
70
|
+
*/
|
|
71
|
+
export function lastUsedCard(saved: readonly SavedCard[]): SavedCard | undefined {
|
|
72
|
+
let pick: SavedCard | undefined;
|
|
73
|
+
let pickAt = -Infinity;
|
|
74
|
+
for (const card of saved) {
|
|
75
|
+
const at = card.lastUsedAt ? Date.parse(card.lastUsedAt) : Number.NaN;
|
|
76
|
+
if (!Number.isNaN(at) && at > pickAt) {
|
|
77
|
+
pick = card;
|
|
78
|
+
pickAt = at;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return pick ?? saved[0];
|
|
82
|
+
}
|
|
83
|
+
|
|
66
84
|
/**
|
|
67
85
|
* What is chosen before the buyer touches anything (M7, owner 2026-10-15): a
|
|
68
86
|
* saved card makes "Cartão de crédito" the choice with that card selected —
|
|
69
|
-
* the
|
|
70
|
-
*
|
|
71
|
-
*
|
|
87
|
+
* the one used last ({@link lastUsedCard}). The buyer's LAST online method
|
|
88
|
+
* (`lastMethod`, FUT-3611) wins when the store offers it: Pix as Pix, since
|
|
89
|
+
* choosing creates nothing any more. Never a door tender (FUT-1478), and not
|
|
90
|
+
* a store's only method by itself either (that pick used to raise an order
|
|
91
|
+
* with no tap at all).
|
|
72
92
|
*
|
|
73
93
|
* A buyer back here because a card was REFUSED (`fresh`) keeps the card
|
|
74
94
|
* chosen, with no saved card selected for them — the one this would pick is
|
|
@@ -78,11 +98,14 @@ export function preselection(
|
|
|
78
98
|
rows: readonly OnlineRow[],
|
|
79
99
|
saved: readonly SavedCard[],
|
|
80
100
|
fresh: boolean,
|
|
101
|
+
lastMethod: "PIX" | "CARD" | null = null,
|
|
81
102
|
): { choice: CheckoutListChoice; selection: string | null } | null {
|
|
103
|
+
const pixOffered = rows.some((row) => row.method === "PIX" && !row.disabled);
|
|
104
|
+
if (lastMethod === "PIX" && pixOffered && !fresh) return { choice: { kind: "online", method: "PIX" }, selection: null };
|
|
82
105
|
const card = rows.find((row) => row.method === "CARD" && !row.disabled);
|
|
83
106
|
if (!card) return null;
|
|
84
107
|
if (fresh) return { choice: { kind: "online", method: "CARD" }, selection: saved.length > 0 ? null : NEW_CARD };
|
|
85
|
-
const head = saved
|
|
108
|
+
const head = lastUsedCard(saved);
|
|
86
109
|
if (!head) return null;
|
|
87
110
|
return { choice: { kind: "online", method: "CARD" }, selection: head.id };
|
|
88
111
|
}
|
|
@@ -157,6 +180,8 @@ export function blockedReason(input: {
|
|
|
157
180
|
buyer: BuyerInfo;
|
|
158
181
|
selection: string | null;
|
|
159
182
|
cardIsComplete: boolean;
|
|
183
|
+
/** The host's balance pays the whole amount: no card needs choosing. */
|
|
184
|
+
covered?: boolean;
|
|
160
185
|
}): string | null {
|
|
161
186
|
const { copy, choice } = input;
|
|
162
187
|
if (input.hold) return input.hold;
|
|
@@ -164,7 +189,7 @@ export function blockedReason(input: {
|
|
|
164
189
|
if (choice.kind === "door") return input.door ? input.door.blocked : copy.reasons.choose;
|
|
165
190
|
const buyer = buyerReason(input.asked, input.buyer, copy.reasons);
|
|
166
191
|
if (buyer) return buyer;
|
|
167
|
-
if (choice.method !== "CARD") return null;
|
|
192
|
+
if (choice.method !== "CARD" || input.covered) return null;
|
|
168
193
|
return cardReason(input.selection, input.cardIsComplete, copy.reasons);
|
|
169
194
|
}
|
|
170
195
|
|
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
import { createContext, useContext, useMemo, useState, type JSX, type ReactNode } from "react";
|
|
1
|
+
import { createContext, useContext, useMemo, useRef, useState, type JSX, type MutableRefObject, type ReactNode } from "react";
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type { DeferredCopy } from "../pix-parts";
|
|
4
|
+
|
|
5
|
+
import type { CheckoutPaymentList, PixBankId } from "./types";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* What the bar's Pix press asked of the code it is raising (FUT-3612): copy it
|
|
9
|
+
* the moment it arrives (the clipboard was opened inside the tap), then open
|
|
10
|
+
* `bank` — or show the six banks when `pick`. Consumed once by the Pix face.
|
|
11
|
+
*/
|
|
12
|
+
export interface PixIntent {
|
|
13
|
+
copy: DeferredCopy;
|
|
14
|
+
bank: PixBankId | null;
|
|
15
|
+
pick: boolean;
|
|
16
|
+
}
|
|
4
17
|
|
|
5
18
|
/**
|
|
6
19
|
* What the one list shares with the panes it mounts (FUT-3591/3592): its
|
|
@@ -23,6 +36,15 @@ export interface PaymentListMode {
|
|
|
23
36
|
* default — because the list skips that step.
|
|
24
37
|
*/
|
|
25
38
|
consent: ListConsent;
|
|
39
|
+
/** The Pix press's intent, waiting for its code — see {@link PixIntent}. */
|
|
40
|
+
pixIntent: MutableRefObject<PixIntent | null>;
|
|
41
|
+
/**
|
|
42
|
+
* The armed charge (`armedCharge`) for this step: when it was armed and
|
|
43
|
+
* whether it was spent. Held HERE, above the faces, so a list face that
|
|
44
|
+
* remounts (after a Pix, "Prefere pagar com cartão?") can never fire it
|
|
45
|
+
* again — the 1-tap tap consented to ONE charge, right away.
|
|
46
|
+
*/
|
|
47
|
+
armed: MutableRefObject<{ since: number; spent: boolean }>;
|
|
26
48
|
}
|
|
27
49
|
|
|
28
50
|
export interface ListConsent {
|
|
@@ -45,7 +67,9 @@ export function PaymentListProvider({
|
|
|
45
67
|
children: ReactNode;
|
|
46
68
|
}): JSX.Element {
|
|
47
69
|
const [qrOpen, setQrOpen] = useState(false);
|
|
48
|
-
const
|
|
70
|
+
const pixIntent = useRef<PixIntent | null>(null);
|
|
71
|
+
const armed = useRef({ since: Date.now(), spent: false });
|
|
72
|
+
const value = useMemo(() => ({ list, qrOpen, setQrOpen, onLeavePix, consent, pixIntent, armed }), [list, qrOpen, onLeavePix, consent]);
|
|
49
73
|
return <PaymentListContext.Provider value={value}>{children}</PaymentListContext.Provider>;
|
|
50
74
|
}
|
|
51
75
|
|
|
@@ -35,6 +35,7 @@ export const EN_US_PAYMENT_LIST_COPY: PaymentListCopy = {
|
|
|
35
35
|
details: "Fill in your details to pay in the app.",
|
|
36
36
|
chooseCard: "Choose the card.",
|
|
37
37
|
cardDetails: "Fill in the card details.",
|
|
38
|
+
repricing: "Updating the amount…",
|
|
38
39
|
},
|
|
39
40
|
actions: {
|
|
40
41
|
choose: "Choose how to pay",
|
|
@@ -46,6 +47,7 @@ export const EN_US_PAYMENT_LIST_COPY: PaymentListCopy = {
|
|
|
46
47
|
payer: (name) => `Paying as ${name} · CPF ✓`,
|
|
47
48
|
payerChange: "Change",
|
|
48
49
|
charging: (total, card) => `Paying ${total} with ${card ?? "the card entered"}…`,
|
|
50
|
+
chargingCovered: "Confirming the order, paid with your balance…",
|
|
49
51
|
cancel: "Cancel",
|
|
50
52
|
pixFace: {
|
|
51
53
|
title: (total) => `Pay ${total} with Pix`,
|