@asteby/storefront-react 0.11.1 → 0.12.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/README.md +25 -0
- package/dist/checkout.cjs +670 -49
- package/dist/checkout.cjs.map +1 -1
- package/dist/checkout.css +230 -0
- package/dist/checkout.d.cts +323 -4
- package/dist/checkout.d.ts +323 -4
- package/dist/checkout.js +651 -44
- package/dist/checkout.js.map +1 -1
- package/dist/payments.cjs +162 -37
- package/dist/payments.cjs.map +1 -1
- package/dist/payments.css +6 -1
- package/dist/payments.d.cts +37 -1
- package/dist/payments.d.ts +37 -1
- package/dist/payments.js +162 -38
- package/dist/payments.js.map +1 -1
- package/package.json +1 -1
package/dist/payments.css
CHANGED
|
@@ -57,9 +57,14 @@
|
|
|
57
57
|
[data-sf-pay-method] [data-sf-pay-choice]:has(input[name='payment_choice']:checked) [data-sf-pay-brands='cash'] {
|
|
58
58
|
display: none;
|
|
59
59
|
}
|
|
60
|
+
/* The card form opens inside its row: a little air between the row and the provider form. */
|
|
61
|
+
[data-sf-pay-method] [data-sf-pay-card] [data-sf-pay-container] {
|
|
62
|
+
margin-block: 0.25rem;
|
|
63
|
+
}
|
|
60
64
|
@media (max-width: 24rem) {
|
|
61
65
|
/* Narrow phones: the row text wins over the preview marks. */
|
|
66
|
+
/* !important: the logo plate sets its own inline `display`. */
|
|
62
67
|
[data-sf-pay-method] [data-sf-pay-choice] [data-sf-pay-brands] [data-sf-brand-mark]:nth-child(n + 3) {
|
|
63
|
-
display: none;
|
|
68
|
+
display: none !important;
|
|
64
69
|
}
|
|
65
70
|
}
|
package/dist/payments.d.cts
CHANGED
|
@@ -33,6 +33,8 @@ type PaymentFormMountOptions = {
|
|
|
33
33
|
locale?: string;
|
|
34
34
|
/** Visual tokens read from CSS variables (see `readPaymentTheme`). */
|
|
35
35
|
theme?: Record<string, string>;
|
|
36
|
+
/** Light or dark page (see `readPaymentScheme`): the adapter picks the provider's matching base theme. */
|
|
37
|
+
colorScheme?: 'light' | 'dark';
|
|
36
38
|
onReady: () => void;
|
|
37
39
|
onError: (error: PaymentFormError) => void;
|
|
38
40
|
};
|
|
@@ -168,6 +170,8 @@ type UseEmbeddedPaymentOptions = {
|
|
|
168
170
|
onEvent?: (event: PaymentEvent) => void;
|
|
169
171
|
/** Overrides the theme read from `--sf-pay-*` tokens. */
|
|
170
172
|
theme?: Record<string, string>;
|
|
173
|
+
/** Overrides the light / dark scheme read from the page (`--sf-pay-scheme` or `color-scheme`). */
|
|
174
|
+
colorScheme?: 'light' | 'dark';
|
|
171
175
|
/** Test hooks. */
|
|
172
176
|
newAttemptId?: () => string;
|
|
173
177
|
};
|
|
@@ -326,6 +330,10 @@ type PaymentMethodMessages = {
|
|
|
326
330
|
pay: string;
|
|
327
331
|
/** Button label for card and cash, before the total. */
|
|
328
332
|
placeOrder: string;
|
|
333
|
+
/** Button label for cash (the buyer gets a payment slip and pays later), before the total. */
|
|
334
|
+
placeOrderCash: string;
|
|
335
|
+
/** Button label while no delivery is chosen yet. */
|
|
336
|
+
chooseDelivery: string;
|
|
329
337
|
/** Button label when the buyer leaves for the provider's page. */
|
|
330
338
|
payRedirect: string;
|
|
331
339
|
/** Button label for the first step (address) of a two-step checkout. */
|
|
@@ -443,6 +451,22 @@ type PaymentMethodSectionProps = {
|
|
|
443
451
|
transport?: PaymentTransport;
|
|
444
452
|
/** Extra props for the card form (`adapter`, `adapters`, `messages`, `minHeight`, `storage`, timeouts...). */
|
|
445
453
|
brickProps?: Partial<Omit<PaymentBrickProps, 'client' | 'amount' | 'transport' | 'onResult' | 'onEvent' | 'onFallback'>>;
|
|
454
|
+
/**
|
|
455
|
+
* Remember the chosen row (and cash point) for this `scope` in `sessionStorage`, so a reload, the "back" button from
|
|
456
|
+
* the provider or the address step does not ask to choose again. Used only while that row is still published.
|
|
457
|
+
* Default true (needs `scope`); `false` turns it off. Nothing personal is stored: only the row value.
|
|
458
|
+
*/
|
|
459
|
+
rememberChoice?: boolean;
|
|
460
|
+
/**
|
|
461
|
+
* Cash points shown before "more payment points". Default: every point the provider marks `main`. With a number, the
|
|
462
|
+
* first N `main` points show and the rest join the "more" list (a remembered point inside it opens the list).
|
|
463
|
+
*/
|
|
464
|
+
cashPointsVisible?: number;
|
|
465
|
+
/**
|
|
466
|
+
* Name of the page form field with the buyer's e-mail. Its value is handed to the card form, so the provider does not
|
|
467
|
+
* ask for the e-mail again. Default `email`; `null` to never pass it. `brickProps.email` wins.
|
|
468
|
+
*/
|
|
469
|
+
payerEmailField?: string | null;
|
|
446
470
|
};
|
|
447
471
|
/**
|
|
448
472
|
* "Payment method", hybrid. Card: the provider's secure form INSIDE the page (`PaymentBrick`) with the shop's own
|
|
@@ -470,11 +494,23 @@ declare const PAYMENT_THEME_TOKENS: {
|
|
|
470
494
|
readonly '--sf-pay-success': "successColor";
|
|
471
495
|
readonly '--sf-pay-outline': "outlinePrimaryColor";
|
|
472
496
|
readonly '--sf-pay-radius': "borderRadiusMedium";
|
|
497
|
+
readonly '--sf-pay-radius-small': "borderRadiusSmall";
|
|
498
|
+
readonly '--sf-pay-radius-large': "borderRadiusLarge";
|
|
499
|
+
readonly '--sf-pay-outline-secondary': "outlineSecondaryColor";
|
|
500
|
+
readonly '--sf-pay-primary-variant': "baseColorFirstVariant";
|
|
501
|
+
readonly '--sf-pay-input-border-width': "inputBorderWidth";
|
|
502
|
+
readonly '--sf-pay-form-padding': "formPadding";
|
|
473
503
|
};
|
|
474
504
|
/**
|
|
475
505
|
* Reads the `--sf-pay-*` tokens from an element's computed style, so the provider form follows the shop's
|
|
476
506
|
* theme without the shop copying colors into JavaScript. Unsafe or empty values are skipped.
|
|
477
507
|
*/
|
|
478
508
|
declare function readPaymentTheme(el: Element | null | undefined, tokens?: Record<string, string>): Record<string, string>;
|
|
509
|
+
/**
|
|
510
|
+
* Light or dark for the provider form, so it does not paint a white card inside a dark page. Order: the
|
|
511
|
+
* `--sf-pay-scheme` token (`light` / `dark`), then the element's `color-scheme` (`light dark` follows the system
|
|
512
|
+
* preference). `null` when nothing says it (the provider default).
|
|
513
|
+
*/
|
|
514
|
+
declare function readPaymentScheme(el: Element | null | undefined): 'light' | 'dark' | null;
|
|
479
515
|
|
|
480
|
-
export { CASH_POINT_FIELD, type EmbeddedPaymentState, type EmbeddedPaymentStatus, type FetchTransportOptions, type LoadScriptOptions, MERCADOPAGO_BRICKS_KIND, type MercadoPagoAdapterOptions, type MercadoPagoCtor, type MountedPaymentForm, PAYMENT_CHOICE_FIELD, PAYMENT_THEME_TOKENS, PayChoices, PaymentBrick, type PaymentBrickHandle, type PaymentBrickProps, PaymentChallenge, type PaymentChallengeProps, type PaymentEvent, type PaymentFallbackReason, type PaymentFormAdapter, type PaymentFormData, type PaymentFormError, type PaymentFormMountOptions, PaymentHttpError, type PaymentMethodClassNames, type PaymentMethodMessages, PaymentMethodSection, type PaymentMethodSectionProps, type PaymentMethodTestIds, type PaymentSubmitRequest, type PaymentTransport, type UseEmbeddedPaymentOptions, VoucherCard, type VoucherCardProps, createFetchTransport, formFields, loadPaymentSdk, mercadoPagoBricksAdapter, paymentMethodMessages, readPaymentTheme, resetPaymentSdkCache, sanitizeMercadoPagoFormData, useEmbeddedPayment };
|
|
516
|
+
export { CASH_POINT_FIELD, type EmbeddedPaymentState, type EmbeddedPaymentStatus, type FetchTransportOptions, type LoadScriptOptions, MERCADOPAGO_BRICKS_KIND, type MercadoPagoAdapterOptions, type MercadoPagoCtor, type MountedPaymentForm, PAYMENT_CHOICE_FIELD, PAYMENT_THEME_TOKENS, PayChoices, PaymentBrick, type PaymentBrickHandle, type PaymentBrickProps, PaymentChallenge, type PaymentChallengeProps, type PaymentEvent, type PaymentFallbackReason, type PaymentFormAdapter, type PaymentFormData, type PaymentFormError, type PaymentFormMountOptions, PaymentHttpError, type PaymentMethodClassNames, type PaymentMethodMessages, PaymentMethodSection, type PaymentMethodSectionProps, type PaymentMethodTestIds, type PaymentSubmitRequest, type PaymentTransport, type UseEmbeddedPaymentOptions, VoucherCard, type VoucherCardProps, createFetchTransport, formFields, loadPaymentSdk, mercadoPagoBricksAdapter, paymentMethodMessages, readPaymentScheme, readPaymentTheme, resetPaymentSdkCache, sanitizeMercadoPagoFormData, useEmbeddedPayment };
|
package/dist/payments.d.ts
CHANGED
|
@@ -33,6 +33,8 @@ type PaymentFormMountOptions = {
|
|
|
33
33
|
locale?: string;
|
|
34
34
|
/** Visual tokens read from CSS variables (see `readPaymentTheme`). */
|
|
35
35
|
theme?: Record<string, string>;
|
|
36
|
+
/** Light or dark page (see `readPaymentScheme`): the adapter picks the provider's matching base theme. */
|
|
37
|
+
colorScheme?: 'light' | 'dark';
|
|
36
38
|
onReady: () => void;
|
|
37
39
|
onError: (error: PaymentFormError) => void;
|
|
38
40
|
};
|
|
@@ -168,6 +170,8 @@ type UseEmbeddedPaymentOptions = {
|
|
|
168
170
|
onEvent?: (event: PaymentEvent) => void;
|
|
169
171
|
/** Overrides the theme read from `--sf-pay-*` tokens. */
|
|
170
172
|
theme?: Record<string, string>;
|
|
173
|
+
/** Overrides the light / dark scheme read from the page (`--sf-pay-scheme` or `color-scheme`). */
|
|
174
|
+
colorScheme?: 'light' | 'dark';
|
|
171
175
|
/** Test hooks. */
|
|
172
176
|
newAttemptId?: () => string;
|
|
173
177
|
};
|
|
@@ -326,6 +330,10 @@ type PaymentMethodMessages = {
|
|
|
326
330
|
pay: string;
|
|
327
331
|
/** Button label for card and cash, before the total. */
|
|
328
332
|
placeOrder: string;
|
|
333
|
+
/** Button label for cash (the buyer gets a payment slip and pays later), before the total. */
|
|
334
|
+
placeOrderCash: string;
|
|
335
|
+
/** Button label while no delivery is chosen yet. */
|
|
336
|
+
chooseDelivery: string;
|
|
329
337
|
/** Button label when the buyer leaves for the provider's page. */
|
|
330
338
|
payRedirect: string;
|
|
331
339
|
/** Button label for the first step (address) of a two-step checkout. */
|
|
@@ -443,6 +451,22 @@ type PaymentMethodSectionProps = {
|
|
|
443
451
|
transport?: PaymentTransport;
|
|
444
452
|
/** Extra props for the card form (`adapter`, `adapters`, `messages`, `minHeight`, `storage`, timeouts...). */
|
|
445
453
|
brickProps?: Partial<Omit<PaymentBrickProps, 'client' | 'amount' | 'transport' | 'onResult' | 'onEvent' | 'onFallback'>>;
|
|
454
|
+
/**
|
|
455
|
+
* Remember the chosen row (and cash point) for this `scope` in `sessionStorage`, so a reload, the "back" button from
|
|
456
|
+
* the provider or the address step does not ask to choose again. Used only while that row is still published.
|
|
457
|
+
* Default true (needs `scope`); `false` turns it off. Nothing personal is stored: only the row value.
|
|
458
|
+
*/
|
|
459
|
+
rememberChoice?: boolean;
|
|
460
|
+
/**
|
|
461
|
+
* Cash points shown before "more payment points". Default: every point the provider marks `main`. With a number, the
|
|
462
|
+
* first N `main` points show and the rest join the "more" list (a remembered point inside it opens the list).
|
|
463
|
+
*/
|
|
464
|
+
cashPointsVisible?: number;
|
|
465
|
+
/**
|
|
466
|
+
* Name of the page form field with the buyer's e-mail. Its value is handed to the card form, so the provider does not
|
|
467
|
+
* ask for the e-mail again. Default `email`; `null` to never pass it. `brickProps.email` wins.
|
|
468
|
+
*/
|
|
469
|
+
payerEmailField?: string | null;
|
|
446
470
|
};
|
|
447
471
|
/**
|
|
448
472
|
* "Payment method", hybrid. Card: the provider's secure form INSIDE the page (`PaymentBrick`) with the shop's own
|
|
@@ -470,11 +494,23 @@ declare const PAYMENT_THEME_TOKENS: {
|
|
|
470
494
|
readonly '--sf-pay-success': "successColor";
|
|
471
495
|
readonly '--sf-pay-outline': "outlinePrimaryColor";
|
|
472
496
|
readonly '--sf-pay-radius': "borderRadiusMedium";
|
|
497
|
+
readonly '--sf-pay-radius-small': "borderRadiusSmall";
|
|
498
|
+
readonly '--sf-pay-radius-large': "borderRadiusLarge";
|
|
499
|
+
readonly '--sf-pay-outline-secondary': "outlineSecondaryColor";
|
|
500
|
+
readonly '--sf-pay-primary-variant': "baseColorFirstVariant";
|
|
501
|
+
readonly '--sf-pay-input-border-width': "inputBorderWidth";
|
|
502
|
+
readonly '--sf-pay-form-padding': "formPadding";
|
|
473
503
|
};
|
|
474
504
|
/**
|
|
475
505
|
* Reads the `--sf-pay-*` tokens from an element's computed style, so the provider form follows the shop's
|
|
476
506
|
* theme without the shop copying colors into JavaScript. Unsafe or empty values are skipped.
|
|
477
507
|
*/
|
|
478
508
|
declare function readPaymentTheme(el: Element | null | undefined, tokens?: Record<string, string>): Record<string, string>;
|
|
509
|
+
/**
|
|
510
|
+
* Light or dark for the provider form, so it does not paint a white card inside a dark page. Order: the
|
|
511
|
+
* `--sf-pay-scheme` token (`light` / `dark`), then the element's `color-scheme` (`light dark` follows the system
|
|
512
|
+
* preference). `null` when nothing says it (the provider default).
|
|
513
|
+
*/
|
|
514
|
+
declare function readPaymentScheme(el: Element | null | undefined): 'light' | 'dark' | null;
|
|
479
515
|
|
|
480
|
-
export { CASH_POINT_FIELD, type EmbeddedPaymentState, type EmbeddedPaymentStatus, type FetchTransportOptions, type LoadScriptOptions, MERCADOPAGO_BRICKS_KIND, type MercadoPagoAdapterOptions, type MercadoPagoCtor, type MountedPaymentForm, PAYMENT_CHOICE_FIELD, PAYMENT_THEME_TOKENS, PayChoices, PaymentBrick, type PaymentBrickHandle, type PaymentBrickProps, PaymentChallenge, type PaymentChallengeProps, type PaymentEvent, type PaymentFallbackReason, type PaymentFormAdapter, type PaymentFormData, type PaymentFormError, type PaymentFormMountOptions, PaymentHttpError, type PaymentMethodClassNames, type PaymentMethodMessages, PaymentMethodSection, type PaymentMethodSectionProps, type PaymentMethodTestIds, type PaymentSubmitRequest, type PaymentTransport, type UseEmbeddedPaymentOptions, VoucherCard, type VoucherCardProps, createFetchTransport, formFields, loadPaymentSdk, mercadoPagoBricksAdapter, paymentMethodMessages, readPaymentTheme, resetPaymentSdkCache, sanitizeMercadoPagoFormData, useEmbeddedPayment };
|
|
516
|
+
export { CASH_POINT_FIELD, type EmbeddedPaymentState, type EmbeddedPaymentStatus, type FetchTransportOptions, type LoadScriptOptions, MERCADOPAGO_BRICKS_KIND, type MercadoPagoAdapterOptions, type MercadoPagoCtor, type MountedPaymentForm, PAYMENT_CHOICE_FIELD, PAYMENT_THEME_TOKENS, PayChoices, PaymentBrick, type PaymentBrickHandle, type PaymentBrickProps, PaymentChallenge, type PaymentChallengeProps, type PaymentEvent, type PaymentFallbackReason, type PaymentFormAdapter, type PaymentFormData, type PaymentFormError, type PaymentFormMountOptions, PaymentHttpError, type PaymentMethodClassNames, type PaymentMethodMessages, PaymentMethodSection, type PaymentMethodSectionProps, type PaymentMethodTestIds, type PaymentSubmitRequest, type PaymentTransport, type UseEmbeddedPaymentOptions, VoucherCard, type VoucherCardProps, createFetchTransport, formFields, loadPaymentSdk, mercadoPagoBricksAdapter, paymentMethodMessages, readPaymentScheme, readPaymentTheme, resetPaymentSdkCache, sanitizeMercadoPagoFormData, useEmbeddedPayment };
|
package/dist/payments.js
CHANGED
|
@@ -108,7 +108,8 @@ function mercadoPagoBricksAdapter(options = {}) {
|
|
|
108
108
|
// fila de método de pago y se veía cortado (p. ej. AMEX partido). hideFormTitle oculta
|
|
109
109
|
// la línea del título y las banderas.
|
|
110
110
|
hideFormTitle: true,
|
|
111
|
-
|
|
111
|
+
// Dark page: the Brick's `dark` base theme, so it does not draw a white card; the shop tokens refine it.
|
|
112
|
+
style: { theme: opts.colorScheme === "dark" ? "dark" : "default", ...opts.theme && Object.keys(opts.theme).length ? { customVariables: opts.theme } : {} }
|
|
112
113
|
}
|
|
113
114
|
},
|
|
114
115
|
callbacks: {
|
|
@@ -152,7 +153,13 @@ var PAYMENT_THEME_TOKENS = {
|
|
|
152
153
|
"--sf-pay-error": "errorColor",
|
|
153
154
|
"--sf-pay-success": "successColor",
|
|
154
155
|
"--sf-pay-outline": "outlinePrimaryColor",
|
|
155
|
-
"--sf-pay-radius": "borderRadiusMedium"
|
|
156
|
+
"--sf-pay-radius": "borderRadiusMedium",
|
|
157
|
+
"--sf-pay-radius-small": "borderRadiusSmall",
|
|
158
|
+
"--sf-pay-radius-large": "borderRadiusLarge",
|
|
159
|
+
"--sf-pay-outline-secondary": "outlineSecondaryColor",
|
|
160
|
+
"--sf-pay-primary-variant": "baseColorFirstVariant",
|
|
161
|
+
"--sf-pay-input-border-width": "inputBorderWidth",
|
|
162
|
+
"--sf-pay-form-padding": "formPadding"
|
|
156
163
|
};
|
|
157
164
|
function readPaymentTheme(el, tokens = PAYMENT_THEME_TOKENS) {
|
|
158
165
|
const out = {};
|
|
@@ -164,6 +171,19 @@ function readPaymentTheme(el, tokens = PAYMENT_THEME_TOKENS) {
|
|
|
164
171
|
}
|
|
165
172
|
return out;
|
|
166
173
|
}
|
|
174
|
+
function readPaymentScheme(el) {
|
|
175
|
+
if (!el || typeof getComputedStyle !== "function") return null;
|
|
176
|
+
const style = getComputedStyle(el);
|
|
177
|
+
const token = style.getPropertyValue("--sf-pay-scheme").trim();
|
|
178
|
+
if (token === "dark" || token === "light") return token;
|
|
179
|
+
const cs = (style.getPropertyValue("color-scheme") || style.colorScheme || "").toLowerCase();
|
|
180
|
+
const dark = /\bdark\b/.test(cs);
|
|
181
|
+
const light = /\blight\b/.test(cs);
|
|
182
|
+
if (dark && !light) return "dark";
|
|
183
|
+
if (light && !dark) return "light";
|
|
184
|
+
if (dark && light && typeof matchMedia === "function") return matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
167
187
|
|
|
168
188
|
// src/payments/use-embedded-payment.ts
|
|
169
189
|
var DEFAULT_ADAPTERS = {};
|
|
@@ -289,6 +309,7 @@ function useEmbeddedPayment(options) {
|
|
|
289
309
|
await adapter.load(client, { ...live.current.nonce ? { nonce: live.current.nonce } : {}, timeoutMs: sdkTimeoutMs });
|
|
290
310
|
if (stale()) return;
|
|
291
311
|
const theme = live.current.theme ?? readPaymentTheme(container);
|
|
312
|
+
const colorScheme = live.current.colorScheme ?? readPaymentScheme(container);
|
|
292
313
|
const m = await adapter.mount({
|
|
293
314
|
container,
|
|
294
315
|
client,
|
|
@@ -296,6 +317,7 @@ function useEmbeddedPayment(options) {
|
|
|
296
317
|
...live.current.email ? { email: live.current.email } : {},
|
|
297
318
|
...live.current.locale ? { locale: live.current.locale } : {},
|
|
298
319
|
theme,
|
|
320
|
+
...colorScheme ? { colorScheme } : {},
|
|
299
321
|
onReady: () => {
|
|
300
322
|
if (stale()) return;
|
|
301
323
|
clearTimeout(timer);
|
|
@@ -649,6 +671,8 @@ var ES = {
|
|
|
649
671
|
legend: "M\xE9todo de pago",
|
|
650
672
|
pay: "Pagar",
|
|
651
673
|
placeOrder: "Realizar el pedido",
|
|
674
|
+
placeOrderCash: "Generar ficha de pago",
|
|
675
|
+
chooseDelivery: "Elige la entrega para continuar",
|
|
652
676
|
payRedirect: "Continuar al pago",
|
|
653
677
|
continue: "Continuar",
|
|
654
678
|
retryAddress: "Guardar direcci\xF3n y continuar",
|
|
@@ -677,6 +701,8 @@ var EN = {
|
|
|
677
701
|
legend: "Payment method",
|
|
678
702
|
pay: "Pay",
|
|
679
703
|
placeOrder: "Place order",
|
|
704
|
+
placeOrderCash: "Get payment slip",
|
|
705
|
+
chooseDelivery: "Choose delivery to continue",
|
|
680
706
|
payRedirect: "Continue to payment",
|
|
681
707
|
continue: "Continue",
|
|
682
708
|
retryAddress: "Save address and continue",
|
|
@@ -715,6 +741,26 @@ function formFields(form) {
|
|
|
715
741
|
for (const [k, v] of new FormData(form).entries()) if (typeof v === "string") out[k] = v;
|
|
716
742
|
return out;
|
|
717
743
|
}
|
|
744
|
+
var CHOICE_STORAGE_PREFIX = "sf:pay-choice:";
|
|
745
|
+
function readStoredChoice(scope) {
|
|
746
|
+
if (!scope || typeof window === "undefined") return null;
|
|
747
|
+
try {
|
|
748
|
+
const raw = window.sessionStorage.getItem(CHOICE_STORAGE_PREFIX + scope);
|
|
749
|
+
if (!raw) return null;
|
|
750
|
+
const v = JSON.parse(raw);
|
|
751
|
+
return typeof v?.choice === "string" ? v : null;
|
|
752
|
+
} catch {
|
|
753
|
+
return null;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
function writeStoredChoice(scope, value) {
|
|
757
|
+
if (!scope || typeof window === "undefined") return;
|
|
758
|
+
try {
|
|
759
|
+
window.sessionStorage.setItem(CHOICE_STORAGE_PREFIX + scope, JSON.stringify(value));
|
|
760
|
+
} catch {
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
718
764
|
var useHydrated = () => useSyncExternalStore(
|
|
719
765
|
() => () => {
|
|
720
766
|
},
|
|
@@ -751,12 +797,37 @@ function PaymentMethodSection(props) {
|
|
|
751
797
|
classNames: cx = {},
|
|
752
798
|
testIds = {},
|
|
753
799
|
hideSubmit,
|
|
754
|
-
brickProps
|
|
800
|
+
brickProps,
|
|
801
|
+
rememberChoice = true,
|
|
802
|
+
cashPointsVisible,
|
|
803
|
+
payerEmailField = "email"
|
|
755
804
|
} = props;
|
|
756
805
|
const locale = useResolvedLocale(props.locale);
|
|
757
806
|
const m = useMemo(() => paymentMethodMessages(locale, props.messages), [locale, props.messages]);
|
|
758
807
|
const hydrated = useHydrated();
|
|
759
|
-
const [choiceValue2,
|
|
808
|
+
const [choiceValue2, setChoiceValueState] = useState(props.defaultChoice ?? choices.defaultValue);
|
|
809
|
+
const remember = rememberChoice && Boolean(scope);
|
|
810
|
+
const rootRef = useRef(null);
|
|
811
|
+
const [storedPoint, setStoredPoint] = useState(null);
|
|
812
|
+
const setChoiceValue = (v) => {
|
|
813
|
+
setChoiceValueState(v);
|
|
814
|
+
if (remember) writeStoredChoice(scope, { choice: v, point: readCheckedPoint(rootRef.current) });
|
|
815
|
+
};
|
|
816
|
+
useEffect(() => {
|
|
817
|
+
if (!remember) return;
|
|
818
|
+
const stored = readStoredChoice(scope);
|
|
819
|
+
if (!stored) return;
|
|
820
|
+
if (choices.choices.some((c) => c.value === stored.choice)) setChoiceValueState(stored.choice);
|
|
821
|
+
if (stored.point) setStoredPoint(stored.point);
|
|
822
|
+
}, [remember, scope]);
|
|
823
|
+
useEffect(() => {
|
|
824
|
+
if (!storedPoint || !rootRef.current) return;
|
|
825
|
+
const input = Array.from(rootRef.current.querySelectorAll(`input[name="${CASH_POINT_FIELD}"]`)).find((i) => i.value === storedPoint);
|
|
826
|
+
if (input) input.checked = true;
|
|
827
|
+
}, [storedPoint, choiceValue2]);
|
|
828
|
+
const onPointChange = (point) => {
|
|
829
|
+
if (remember && choiceValue2) writeStoredChoice(scope, { choice: choiceValue2, point });
|
|
830
|
+
};
|
|
760
831
|
const selected = choices.choices.find((c) => c.value === choiceValue2) ?? null;
|
|
761
832
|
const noPayment = choices.choices.length === 0;
|
|
762
833
|
const tid = (k) => testIds[k] ? { "data-testid": testIds[k] } : {};
|
|
@@ -807,8 +878,33 @@ function PaymentMethodSection(props) {
|
|
|
807
878
|
}
|
|
808
879
|
onEvent?.(e);
|
|
809
880
|
};
|
|
881
|
+
const [payerEmail, setPayerEmail] = useState(void 0);
|
|
882
|
+
useEffect(() => {
|
|
883
|
+
const form = formRef.current;
|
|
884
|
+
if (!payerEmailField || !form) return;
|
|
885
|
+
const selector = `[name="${typeof CSS !== "undefined" && CSS.escape ? CSS.escape(payerEmailField) : payerEmailField}"]`;
|
|
886
|
+
const read = () => {
|
|
887
|
+
const v = String(form.querySelector(selector)?.value ?? "").trim();
|
|
888
|
+
setPayerEmail(EMAIL_RE.test(v) ? v : void 0);
|
|
889
|
+
};
|
|
890
|
+
read();
|
|
891
|
+
const onChange = (e) => {
|
|
892
|
+
if (e.target?.name === payerEmailField) read();
|
|
893
|
+
};
|
|
894
|
+
form.addEventListener("change", onChange);
|
|
895
|
+
return () => form.removeEventListener("change", onChange);
|
|
896
|
+
}, [formRef, payerEmailField]);
|
|
810
897
|
const total = wantSync && (!settled || requote) ? null : renderAmount ? renderAmount(amount) : formatMoney(amount, locale);
|
|
811
|
-
const label = retryAddress ? m.retryAddress : addressFirst ? m.continue :
|
|
898
|
+
const label = retryAddress ? m.retryAddress : addressFirst ? m.continue : !deliveryReady && selected ? (
|
|
899
|
+
// Says what is missing instead of a button that silently does nothing.
|
|
900
|
+
m.chooseDelivery
|
|
901
|
+
) : selected?.mode === "cash" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
902
|
+
m.placeOrderCash,
|
|
903
|
+
total ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
904
|
+
" ",
|
|
905
|
+
total
|
|
906
|
+
] }) : null
|
|
907
|
+
] }) : selected?.mode === "plain" || !selected ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
812
908
|
m.pay,
|
|
813
909
|
total ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
814
910
|
" ",
|
|
@@ -822,6 +918,11 @@ function PaymentMethodSection(props) {
|
|
|
822
918
|
] }) : null
|
|
823
919
|
] });
|
|
824
920
|
function onPayClick(event) {
|
|
921
|
+
if (!addressFirst && !retryAddress && !deliveryReady && selected) {
|
|
922
|
+
event.preventDefault();
|
|
923
|
+
formRef.current?.reportValidity();
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
825
926
|
if (!cardActive || syncFailed) return;
|
|
826
927
|
event.preventDefault();
|
|
827
928
|
const form = formRef.current;
|
|
@@ -830,7 +931,7 @@ function PaymentMethodSection(props) {
|
|
|
830
931
|
}
|
|
831
932
|
const cardNotice = (k, node) => k === "syncFailed" ? /* @__PURE__ */ jsx("p", { role: "alert", className: cx.alert, "data-sf-pay-notice": "sync-failed", ...tid("syncFailed"), children: node }) : /* @__PURE__ */ jsx("p", { role: "status", className: cx.status, "data-sf-pay-notice": k, ...k === "syncing" ? tid("syncing") : {}, children: node });
|
|
832
933
|
const Link = renderLink ?? (({ href, className, children, testId }) => /* @__PURE__ */ jsx("a", { href, className, ...testId ? { "data-testid": testId } : {}, children }));
|
|
833
|
-
return /* @__PURE__ */ jsxs("fieldset", { id: "pago", className: cx.root, "data-sf-pay-method": true, children: [
|
|
934
|
+
return /* @__PURE__ */ jsxs("fieldset", { id: "pago", ref: rootRef, className: cx.root, "data-sf-pay-method": true, children: [
|
|
834
935
|
/* @__PURE__ */ jsx("legend", { className: cx.legend, children: m.legend }),
|
|
835
936
|
choices.choices.map((choice) => {
|
|
836
937
|
const { label: rowLabel, hint } = rowText(choice, m, methodLabel);
|
|
@@ -870,38 +971,40 @@ function PaymentMethodSection(props) {
|
|
|
870
971
|
] }),
|
|
871
972
|
marks.length ? /* @__PURE__ */ jsx("span", { className: cx.brands, "data-sf-pay-brands": choice.option ?? "plain", "aria-hidden": "true", children: marks.map((mk) => /* @__PURE__ */ jsx(BrandMark, { brand: mk.key, logoUrl: mk.logoUrl ?? null, size: 20 }, mk.key)) }) : null
|
|
872
973
|
] }),
|
|
873
|
-
/* @__PURE__ */ jsx(ChoicePanel, { choice, m, invalid, cx, tid, hidden: hydrated && !checked, marks: brandMarks })
|
|
974
|
+
/* @__PURE__ */ jsx(ChoicePanel, { choice, m, invalid, cx, tid, hidden: hydrated && !checked, marks: brandMarks, visible: cashPointsVisible, openMore: storedPoint, onPointChange }),
|
|
975
|
+
choice.mode === "card" && checked && cardChosen && hydrated && choices.cardClient ? /* @__PURE__ */ jsxs("div", { className: cx.brickWrap, "data-sf-pay-card": true, ...tid("card"), children: [
|
|
976
|
+
fallback ? null : !deliveryReady ? cardNotice("pickDelivery", m.pickDeliveryFirst) : syncFailed ? cardNotice("syncFailed", m.syncFailed) : requote ? cardNotice("requote", m.quoteChanged) : !synced ? cardNotice("syncing", m.updatingTotal) : null,
|
|
977
|
+
brickReady || fallback ? /* @__PURE__ */ jsx(
|
|
978
|
+
PaymentBrick,
|
|
979
|
+
{
|
|
980
|
+
...brickProps,
|
|
981
|
+
ref: brick,
|
|
982
|
+
client: choices.cardClient,
|
|
983
|
+
amount,
|
|
984
|
+
transport,
|
|
985
|
+
...nonce ? { nonce } : {},
|
|
986
|
+
locale,
|
|
987
|
+
...scope ? { scope } : {},
|
|
988
|
+
...payerEmail && !brickProps?.email ? { email: payerEmail } : {},
|
|
989
|
+
enabled: brickReady,
|
|
990
|
+
...cx.brick ? { className: cx.brick } : {},
|
|
991
|
+
onEvent: handleEvent,
|
|
992
|
+
onFallback: () => setFallback(true),
|
|
993
|
+
onResult: (o) => {
|
|
994
|
+
if (o.kind === "approved" || o.kind === "in_review" || o.kind === "voucher") onDone(o);
|
|
995
|
+
}
|
|
996
|
+
},
|
|
997
|
+
payerEmail || brickProps?.email ? "with-email" : "without-email"
|
|
998
|
+
) : null,
|
|
999
|
+
/* @__PURE__ */ jsx("p", { className: cx.note, children: m.secureCard }),
|
|
1000
|
+
expired && rebuildHref ? Link({ href: rebuildHref, ...cx.rebuild ? { className: cx.rebuild } : {}, children: m.rebuildCart, ...testIds.rebuild ? { testId: testIds.rebuild } : {} }) : null
|
|
1001
|
+
] }) : null
|
|
874
1002
|
] }, choice.value);
|
|
875
1003
|
}),
|
|
876
1004
|
noPayment ? /* @__PURE__ */ jsxs("div", { role: "alert", className: cx.alert, "data-sf-pay-notice": "no-payment", ...tid("noPayment"), children: [
|
|
877
1005
|
/* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx("strong", { children: m.noPaymentTitle }) }),
|
|
878
1006
|
/* @__PURE__ */ jsx("p", { children: m.noPayment })
|
|
879
1007
|
] }) : null,
|
|
880
|
-
cardChosen && hydrated && choices.cardClient ? /* @__PURE__ */ jsxs("div", { className: cx.brickWrap, "data-sf-pay-card": true, ...tid("card"), children: [
|
|
881
|
-
fallback ? null : !deliveryReady ? cardNotice("pickDelivery", m.pickDeliveryFirst) : syncFailed ? cardNotice("syncFailed", m.syncFailed) : requote ? cardNotice("requote", m.quoteChanged) : !synced ? cardNotice("syncing", m.updatingTotal) : null,
|
|
882
|
-
brickReady || fallback ? /* @__PURE__ */ jsx(
|
|
883
|
-
PaymentBrick,
|
|
884
|
-
{
|
|
885
|
-
...brickProps,
|
|
886
|
-
ref: brick,
|
|
887
|
-
client: choices.cardClient,
|
|
888
|
-
amount,
|
|
889
|
-
transport,
|
|
890
|
-
...nonce ? { nonce } : {},
|
|
891
|
-
locale,
|
|
892
|
-
...scope ? { scope } : {},
|
|
893
|
-
enabled: brickReady,
|
|
894
|
-
...cx.brick ? { className: cx.brick } : {},
|
|
895
|
-
onEvent: handleEvent,
|
|
896
|
-
onFallback: () => setFallback(true),
|
|
897
|
-
onResult: (o) => {
|
|
898
|
-
if (o.kind === "approved" || o.kind === "in_review" || o.kind === "voucher") onDone(o);
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
) : null,
|
|
902
|
-
/* @__PURE__ */ jsx("p", { className: cx.note, children: m.secureCard }),
|
|
903
|
-
expired && rebuildHref ? Link({ href: rebuildHref, ...cx.rebuild ? { className: cx.rebuild } : {}, children: m.rebuildCart, ...testIds.rebuild ? { testId: testIds.rebuild } : {} }) : null
|
|
904
|
-
] }) : null,
|
|
905
1008
|
noPayment || choices.choices.some((c) => c.option) ? null : /* @__PURE__ */ jsx("p", { className: cx.note, children: m.paymentNote }),
|
|
906
1009
|
hideSubmit ? null : /* @__PURE__ */ jsx(
|
|
907
1010
|
"button",
|
|
@@ -930,16 +1033,33 @@ function ChoicePanel({
|
|
|
930
1033
|
cx,
|
|
931
1034
|
tid,
|
|
932
1035
|
hidden,
|
|
933
|
-
marks = true
|
|
1036
|
+
marks = true,
|
|
1037
|
+
visible,
|
|
1038
|
+
openMore,
|
|
1039
|
+
onPointChange
|
|
934
1040
|
}) {
|
|
935
1041
|
if (choice.mode === "redirect") {
|
|
936
1042
|
return /* @__PURE__ */ jsx("p", { className: cx.panel, hidden, "data-sf-pay-panel": "redirect", ...tid("redirectNote"), children: m.redirectNote });
|
|
937
1043
|
}
|
|
938
1044
|
if (choice.mode !== "cash") return null;
|
|
939
|
-
const
|
|
940
|
-
const
|
|
1045
|
+
const allMain = choice.points.filter((p) => p.group === "main");
|
|
1046
|
+
const cut = typeof visible === "number" && visible > 0 ? visible : allMain.length;
|
|
1047
|
+
const main = allMain.slice(0, cut);
|
|
1048
|
+
const more = [...allMain.slice(cut), ...choice.points.filter((p) => p.group !== "main")];
|
|
1049
|
+
const moreOpen = Boolean(openMore && more.some((p) => p.id === openMore));
|
|
941
1050
|
const row = (p, i, first) => /* @__PURE__ */ jsxs("label", { className: cx.cashPoint, "data-sf-pay-point": true, children: [
|
|
942
|
-
/* @__PURE__ */ jsx(
|
|
1051
|
+
/* @__PURE__ */ jsx(
|
|
1052
|
+
"input",
|
|
1053
|
+
{
|
|
1054
|
+
type: "radio",
|
|
1055
|
+
name: CASH_POINT_FIELD,
|
|
1056
|
+
value: p.id,
|
|
1057
|
+
defaultChecked: first && i === 0,
|
|
1058
|
+
className: cx.cashPointInput,
|
|
1059
|
+
"aria-invalid": invalid?.has("cash_point") || void 0,
|
|
1060
|
+
...onPointChange ? { onChange: () => onPointChange(p.id) } : {}
|
|
1061
|
+
}
|
|
1062
|
+
),
|
|
943
1063
|
marks ? /* @__PURE__ */ jsx(BrandMark, { brand: p.payment_point || p.id, logoUrl: p.logo_url ?? null, size: 22 }) : null,
|
|
944
1064
|
/* @__PURE__ */ jsx("span", { children: p.label })
|
|
945
1065
|
] }, p.id);
|
|
@@ -947,7 +1067,7 @@ function ChoicePanel({
|
|
|
947
1067
|
/* @__PURE__ */ jsxs("fieldset", { children: [
|
|
948
1068
|
/* @__PURE__ */ jsx("legend", { children: m.cashPoints }),
|
|
949
1069
|
/* @__PURE__ */ jsx("div", { "data-sf-pay-points": true, children: main.map((p, i) => row(p, i, true)) }),
|
|
950
|
-
more.length ? /* @__PURE__ */ jsxs("details", { children: [
|
|
1070
|
+
more.length ? /* @__PURE__ */ jsxs("details", { ...moreOpen ? { open: true } : {}, children: [
|
|
951
1071
|
/* @__PURE__ */ jsx("summary", { className: cx.cashMore, style: { minHeight: 44 }, children: m.cashMore }),
|
|
952
1072
|
/* @__PURE__ */ jsx("div", { "data-sf-pay-points": true, children: more.map((p, i) => row(p, i, false)) })
|
|
953
1073
|
] }) : null
|
|
@@ -963,6 +1083,10 @@ function defaultIcon(choice) {
|
|
|
963
1083
|
if (choice.option === "cash") return glyph(CASH_GLYPH);
|
|
964
1084
|
return findBrand(choice.methodKey) ? /* @__PURE__ */ jsx(BrandMark, { brand: choice.methodKey, size: 24 }) : null;
|
|
965
1085
|
}
|
|
1086
|
+
function readCheckedPoint(root) {
|
|
1087
|
+
const el = root?.querySelector(`input[name="${CASH_POINT_FIELD}"]:checked`);
|
|
1088
|
+
return el?.value ?? null;
|
|
1089
|
+
}
|
|
966
1090
|
function rowMarks(choice, cardBrands) {
|
|
967
1091
|
if (choice.option === "card") return cardBrands.map((key) => ({ key }));
|
|
968
1092
|
if (choice.option === "cash") {
|
|
@@ -980,6 +1104,6 @@ function rowMarks(choice, cardBrands) {
|
|
|
980
1104
|
return [];
|
|
981
1105
|
}
|
|
982
1106
|
|
|
983
|
-
export { CASH_POINT_FIELD, MERCADOPAGO_BRICKS_KIND, PAYMENT_CHOICE_FIELD, PAYMENT_THEME_TOKENS, PaymentBrick, PaymentChallenge, PaymentHttpError, PaymentMethodSection, VoucherCard, createFetchTransport, formFields, loadPaymentSdk, mercadoPagoBricksAdapter, paymentMethodMessages, readPaymentTheme, resetPaymentSdkCache, sanitizeMercadoPagoFormData, useEmbeddedPayment };
|
|
1107
|
+
export { CASH_POINT_FIELD, MERCADOPAGO_BRICKS_KIND, PAYMENT_CHOICE_FIELD, PAYMENT_THEME_TOKENS, PaymentBrick, PaymentChallenge, PaymentHttpError, PaymentMethodSection, VoucherCard, createFetchTransport, formFields, loadPaymentSdk, mercadoPagoBricksAdapter, paymentMethodMessages, readPaymentScheme, readPaymentTheme, resetPaymentSdkCache, sanitizeMercadoPagoFormData, useEmbeddedPayment };
|
|
984
1108
|
//# sourceMappingURL=payments.js.map
|
|
985
1109
|
//# sourceMappingURL=payments.js.map
|