@12-apps/payments-frontend 3.30.0 → 3.31.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.
|
|
3
|
+
"version": "3.31.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.",
|
|
@@ -4,7 +4,7 @@ import QRCode from "react-qr-code";
|
|
|
4
4
|
|
|
5
5
|
import { useCheckoutCopy } from "./copy-context";
|
|
6
6
|
import { ContentCopyIcon } from "./icons";
|
|
7
|
-
import type { SettlingCopy } from "./screens-copy";
|
|
7
|
+
import type { PixPaneCopy, SettlingCopy } from "./screens-copy";
|
|
8
8
|
import { StalledWait } from "./stalled-wait";
|
|
9
9
|
import type { CheckoutOrder, OrderStatus, PixCharge } from "./types";
|
|
10
10
|
import { useCheckoutComponents } from "./ui";
|
|
@@ -163,14 +163,18 @@ function PixPollFooter({
|
|
|
163
163
|
error,
|
|
164
164
|
timedOut,
|
|
165
165
|
onCheckAgain,
|
|
166
|
+
manual,
|
|
166
167
|
}: {
|
|
167
168
|
error: string | null;
|
|
168
169
|
timedOut: boolean;
|
|
169
170
|
onCheckAgain: () => void;
|
|
171
|
+
/** The store confirms this Pix: the wait is for THEM, not for the bank. */
|
|
172
|
+
manual: boolean;
|
|
170
173
|
}): JSX.Element {
|
|
171
174
|
const { Text } = useCheckoutComponents();
|
|
172
175
|
const { pix, settling } = useCheckoutCopy().screens;
|
|
173
176
|
const panel = pixWaitPanel(settling, error, timedOut);
|
|
177
|
+
const awaiting = (manual ? pix.manual?.awaiting : undefined) ?? pix.awaiting;
|
|
174
178
|
if (panel) {
|
|
175
179
|
// The same panel the card and wallet panes show, held to the width of the
|
|
176
180
|
// copy-and-paste strip above it so the centred PIX column stays a column.
|
|
@@ -190,12 +194,23 @@ function PixPollFooter({
|
|
|
190
194
|
<Box sx={{ display: "flex", alignItems: "center", gap: 1, color: "text.secondary" }}>
|
|
191
195
|
<LoadingDot />
|
|
192
196
|
<Text variant="caption" size="xs" color="secondary" as="span" data-testid="pix-awaiting">
|
|
193
|
-
{
|
|
197
|
+
{awaiting}
|
|
194
198
|
</Text>
|
|
195
199
|
</Box>
|
|
196
200
|
);
|
|
197
201
|
}
|
|
198
202
|
|
|
203
|
+
/**
|
|
204
|
+
* The pane's two sentences that depend on who confirms. A store-confirmed Pix
|
|
205
|
+
* must not say "a confirmação é automática": nothing confirms it but the store.
|
|
206
|
+
*/
|
|
207
|
+
function pixSentences(
|
|
208
|
+
copy: PixPaneCopy,
|
|
209
|
+
manual: boolean,
|
|
210
|
+
): Pick<PixPaneCopy, "instructions" | "validUntil"> {
|
|
211
|
+
return (manual ? copy.manual : undefined) ?? copy;
|
|
212
|
+
}
|
|
213
|
+
|
|
199
214
|
export function PixView({
|
|
200
215
|
order,
|
|
201
216
|
onResolved,
|
|
@@ -239,10 +254,9 @@ export function PixView({
|
|
|
239
254
|
// The locale is the HOST's (FUT-760): it decides what a buyer reads off the
|
|
240
255
|
// clock, so it travels with the sentence it feeds rather than being frozen
|
|
241
256
|
// to the origin host's here.
|
|
242
|
-
const validUntil = new Date(pix.expiresAt).toLocaleTimeString(copy.expiryLocale, {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
});
|
|
257
|
+
const validUntil = new Date(pix.expiresAt).toLocaleTimeString(copy.expiryLocale, { hour: "2-digit", minute: "2-digit" });
|
|
258
|
+
const manual = pix.confirmation === "MANUAL";
|
|
259
|
+
const sentences = pixSentences(copy, manual);
|
|
246
260
|
|
|
247
261
|
return (
|
|
248
262
|
<Box
|
|
@@ -253,7 +267,7 @@ export function PixView({
|
|
|
253
267
|
{copy.heading}
|
|
254
268
|
</Text>
|
|
255
269
|
<Text variant="body" size="sm" color="secondary" as="p">
|
|
256
|
-
{
|
|
270
|
+
{sentences.instructions(order.totalLabel)}
|
|
257
271
|
</Text>
|
|
258
272
|
|
|
259
273
|
<Box
|
|
@@ -268,10 +282,10 @@ export function PixView({
|
|
|
268
282
|
<PixCodeBox pix={pix} />
|
|
269
283
|
|
|
270
284
|
<Text variant="caption" size="xs" color="secondary" as="p" data-testid="pix-expiry">
|
|
271
|
-
{
|
|
285
|
+
{sentences.validUntil(validUntil)}
|
|
272
286
|
</Text>
|
|
273
287
|
|
|
274
|
-
<PixPollFooter error={error} timedOut={timedOut} onCheckAgain={checkAgain} />
|
|
288
|
+
<PixPollFooter error={error} timedOut={timedOut} onCheckAgain={checkAgain} manual={manual} />
|
|
275
289
|
</Box>
|
|
276
290
|
);
|
|
277
291
|
}
|
|
@@ -107,6 +107,17 @@ export interface PixPaneCopy {
|
|
|
107
107
|
awaiting: string;
|
|
108
108
|
/** The order came back with no PIX charge on it — nothing to show. */
|
|
109
109
|
chargeMissing: string;
|
|
110
|
+
/**
|
|
111
|
+
* The same pane for a Pix the STORE confirms (`PixCharge.confirmation:
|
|
112
|
+
* 'MANUAL'`). Optional so a host's own table keeps compiling; absent, the
|
|
113
|
+
* automatic sentences are used — which promise "automática", so a host that
|
|
114
|
+
* enables a store-confirmed provider should set them.
|
|
115
|
+
*/
|
|
116
|
+
manual?: {
|
|
117
|
+
instructions(totalLabel: string): string;
|
|
118
|
+
validUntil(time: string): string;
|
|
119
|
+
awaiting: string;
|
|
120
|
+
};
|
|
110
121
|
}
|
|
111
122
|
|
|
112
123
|
/** The card pane's own heading. Everything else in it is {@link SettlingCopy}. */
|
|
@@ -51,6 +51,12 @@ export const EN_US_CHECKOUT_SCREENS_COPY: CheckoutScreensCopy = {
|
|
|
51
51
|
expiryLocale: 'en-US',
|
|
52
52
|
awaiting: 'Waiting for payment…',
|
|
53
53
|
chargeMissing: 'Could not generate the PIX code.',
|
|
54
|
+
manual: {
|
|
55
|
+
instructions: (totalLabel) =>
|
|
56
|
+
`Pay ${totalLabel} with the QR code or the code below. The store checks it arrived and confirms your order.`,
|
|
57
|
+
validUntil: (time) => `The store confirms the payment by ${time}.`,
|
|
58
|
+
awaiting: 'Waiting for the store to confirm the payment…',
|
|
59
|
+
},
|
|
54
60
|
},
|
|
55
61
|
card: {
|
|
56
62
|
heading: 'Pay by card',
|
|
@@ -40,6 +40,12 @@ export const PT_BR_CHECKOUT_SCREENS_COPY: CheckoutScreensCopy = {
|
|
|
40
40
|
expiryLocale: 'pt-BR',
|
|
41
41
|
awaiting: 'Aguardando pagamento…',
|
|
42
42
|
chargeMissing: 'Não foi possível gerar o código PIX.',
|
|
43
|
+
manual: {
|
|
44
|
+
instructions: (totalLabel) =>
|
|
45
|
+
`Pague ${totalLabel} com o QR code ou o código abaixo. A loja confere o recebimento e confirma o seu pedido.`,
|
|
46
|
+
validUntil: (time) => `A loja confirma o pagamento até ${time}.`,
|
|
47
|
+
awaiting: 'Aguardando confirmação do pagamento pela loja…',
|
|
48
|
+
},
|
|
43
49
|
},
|
|
44
50
|
card: {
|
|
45
51
|
heading: 'Pague com cartão',
|
|
@@ -66,15 +66,15 @@ export interface BuyerInfo {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
|
-
* A raised PIX charge. `copyPaste` is the EMV "copia e cola" payload
|
|
70
|
-
*
|
|
71
|
-
* returns a provider QR image; the client renders its own QR from `copyPaste`, so
|
|
72
|
-
* no image URL is needed here.
|
|
69
|
+
* A raised PIX charge. `copyPaste` is the EMV "copia e cola" payload: what the
|
|
70
|
+
* QR encodes (rendered client-side, so no image URL) and what the button copies.
|
|
73
71
|
*/
|
|
74
72
|
export interface PixCharge {
|
|
75
73
|
copyPaste: string;
|
|
76
74
|
/** ISO-8601 instant when the charge expires. */
|
|
77
75
|
expiresAt: string;
|
|
76
|
+
/** `'MANUAL'`: only the store confirms it (`pixmanual`); absent is automatic. */
|
|
77
|
+
confirmation?: 'AUTOMATIC' | 'MANUAL';
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
/**
|