@fayz-ai/storefront 0.14.3 → 0.16.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/dist/{chunk-GS7TDBF5.js → chunk-STL6MATQ.js} +621 -83
- package/dist/chunk-STL6MATQ.js.map +1 -0
- package/dist/components/cart/CartDrawer.d.ts.map +1 -1
- package/dist/components/checkout/CardBrick.d.ts +64 -0
- package/dist/components/checkout/CardBrick.d.ts.map +1 -0
- package/dist/components/checkout/CheckoutPayment.d.ts +25 -1
- package/dist/components/checkout/CheckoutPayment.d.ts.map +1 -1
- package/dist/hooks/use-checkout.d.ts.map +1 -1
- package/dist/hooks/use-discount-validator.d.ts +2 -0
- package/dist/hooks/use-discount-validator.d.ts.map +1 -1
- package/dist/hooks/use-known-customer.d.ts +26 -0
- package/dist/hooks/use-known-customer.d.ts.map +1 -0
- package/dist/hooks/use-shipping.d.ts.map +1 -1
- package/dist/index.js +11 -6
- package/dist/index.js.map +1 -1
- package/dist/lib/testids.d.ts +2 -0
- package/dist/lib/testids.d.ts.map +1 -1
- package/dist/render.js +1 -1
- package/dist/stores/cart.store.d.ts +12 -3
- package/dist/stores/cart.store.d.ts.map +1 -1
- package/dist/views/CheckoutPage.d.ts.map +1 -1
- package/dist/views/MyPurchasesPage.d.ts.map +1 -1
- package/dist/workflows/checkout.d.ts +1 -1
- package/dist/workflows/checkout.d.ts.map +1 -1
- package/package.json +7 -7
- package/dist/chunk-GS7TDBF5.js.map +0 -1
|
@@ -6,7 +6,7 @@ import { setShopCarrierQuotesResolver, setShopAccessTokenResolver, setShopShippi
|
|
|
6
6
|
import { normalizePostalCode, lookupPostalCode, defaultRouterAdapter, defineLoader, staticRouterAdapter, isLoaderParamRef, isLoaderPropRef, resolveLoader, dataNeedKey, getBlockMeta, defaultPropsFromSettings, getBlockErrorVisibility, isBlockEnabledOn, checkBlockConstraints, checkBlockContext, repairBlockTree, renderBlocks, clearExtensionPoints, defineExtensionPoint, runExtensionPoint, runEscapeValve, breadcrumbJsonLd, hasEntityDeclaration, resolveEntityDeclaration, defineBlock, formatPostalCode, defineEntity, listEntityDeclarations, resolveHandle, seoOrigin, RESERVED_ENTITY_FIELDS, ENTITY_FIELD_TYPES, handleNameFor, registerHandle, hasHandle, listHandles, blockRegistry, loaderRegistry, listLoaders } from '@fayz-ai/core';
|
|
7
7
|
import React4, { createContext, useContext, useEffect, useRef, useState, useSyncExternalStore, useMemo, useCallback } from 'react';
|
|
8
8
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
9
|
-
import { isStorageImageUrl, imageVariantUrl, imageSrcSet, IMAGE_SRCSET_WIDTHS, validateDiscount, documentDigits, isChargeableProvider, formatDocument, isValidDocument } from '@fayz-ai/shop';
|
|
9
|
+
import { isStorageImageUrl, imageVariantUrl, imageSrcSet, IMAGE_SRCSET_WIDTHS, validateDiscount, documentDigits, isChargeableProvider, supportsCard, formatDocument, isValidDocument, gatewayLabel } from '@fayz-ai/shop';
|
|
10
10
|
import { ChevronLeft, ChevronRight, ShoppingBag, X, Minus, Plus, Send, MessageCircle, Mail, Truck, RefreshCcw, ShieldCheck, ChevronDown, Check, Search, Trash2, Lock, CreditCard, Star, MapPin, Phone, User, UserCircle, Package, LogOut, Menu, QrCode, Copy, XCircle, RotateCcw, Clock, PackageCheck, Info, AlertCircle } from 'lucide-react';
|
|
11
11
|
import { getLucideIcon } from '@fayz-ai/ui/icons';
|
|
12
12
|
import { storefrontDiscountToPromotion, previewCouponPercent, discountToPromotion, PROMOTION_TYPES, PROMOTION_STATUSES, APPLICATION_METHOD_TYPES, APPLICATION_METHOD_TARGET_TYPES, APPLICATION_METHOD_ALLOCATIONS, hasRuleAttribute, listRuleAttributeKeys, RULE_OPERATORS, resolveRuleAttribute } from '@fayz-ai/shop/rules';
|
|
@@ -329,6 +329,7 @@ var useCartStore = create()(
|
|
|
329
329
|
lines: [],
|
|
330
330
|
discountCode: null,
|
|
331
331
|
discountPercent: 0,
|
|
332
|
+
discountFreeShipping: false,
|
|
332
333
|
isOpen: false,
|
|
333
334
|
justAddedLineId: null,
|
|
334
335
|
addItem: (product, qty = 1, options) => set((state) => {
|
|
@@ -384,9 +385,13 @@ var useCartStore = create()(
|
|
|
384
385
|
};
|
|
385
386
|
}),
|
|
386
387
|
removeItem: (lineId) => set((state) => ({ lines: state.lines.filter((l) => (l.lineId ?? l.productId) !== lineId) })),
|
|
387
|
-
applyDiscount: (code, percent) => set({
|
|
388
|
-
|
|
389
|
-
|
|
388
|
+
applyDiscount: (code, percent, options) => set({
|
|
389
|
+
discountCode: code,
|
|
390
|
+
discountPercent: percent,
|
|
391
|
+
discountFreeShipping: options?.freeShipping === true
|
|
392
|
+
}),
|
|
393
|
+
clearDiscount: () => set({ discountCode: null, discountPercent: 0, discountFreeShipping: false }),
|
|
394
|
+
clear: () => set({ lines: [], discountCode: null, discountPercent: 0, discountFreeShipping: false }),
|
|
390
395
|
openDrawer: () => set({ isOpen: true }),
|
|
391
396
|
closeDrawer: () => set({ isOpen: false, justAddedLineId: null }),
|
|
392
397
|
reconcile: async (resolve) => {
|
|
@@ -404,7 +409,8 @@ var useCartStore = create()(
|
|
|
404
409
|
partialize: (state) => ({
|
|
405
410
|
lines: state.lines,
|
|
406
411
|
discountCode: state.discountCode,
|
|
407
|
-
discountPercent: state.discountPercent
|
|
412
|
+
discountPercent: state.discountPercent,
|
|
413
|
+
discountFreeShipping: state.discountFreeShipping
|
|
408
414
|
})
|
|
409
415
|
}
|
|
410
416
|
)
|
|
@@ -416,6 +422,7 @@ var selectRequiresShipping = (s2) => s2.lines.some((l) => l.requiresShipping !==
|
|
|
416
422
|
var selectShipping = (s2, cfg) => {
|
|
417
423
|
if (s2.lines.length === 0) return 0;
|
|
418
424
|
if (!selectRequiresShipping(s2)) return 0;
|
|
425
|
+
if (s2.discountFreeShipping) return 0;
|
|
419
426
|
const subtotal = selectSubtotal(s2);
|
|
420
427
|
const quoted = selectQuotedShipping(useDeliveryStore.getState(), subtotal);
|
|
421
428
|
if (quoted != null) return quoted;
|
|
@@ -1136,10 +1143,12 @@ var TID = {
|
|
|
1136
1143
|
authTabSignup: "auth-tab-signup",
|
|
1137
1144
|
signinEmail: "signin-email",
|
|
1138
1145
|
signinPassword: "signin-password",
|
|
1146
|
+
signinPasswordConfirm: "signin-password-confirm",
|
|
1139
1147
|
signinName: "signin-name",
|
|
1140
1148
|
signinSubmit: "signin-submit",
|
|
1141
1149
|
authError: "auth-error",
|
|
1142
1150
|
authNotice: "auth-notice",
|
|
1151
|
+
checkoutExpired: "checkout-expired",
|
|
1143
1152
|
purchasesList: "purchases-list",
|
|
1144
1153
|
purchaseItem: "purchase-item",
|
|
1145
1154
|
purchasesEmpty: "purchases-empty",
|
|
@@ -6907,6 +6916,9 @@ var REASON_MESSAGE = {
|
|
|
6907
6916
|
rules_not_matched: "Este cupom n\xE3o se aplica ao seu carrinho.",
|
|
6908
6917
|
unsupported: "Este cupom n\xE3o \xE9 suportado na loja."
|
|
6909
6918
|
};
|
|
6919
|
+
function cartSubtotal() {
|
|
6920
|
+
return selectSubtotal({ lines: useCartStore.getState().lines });
|
|
6921
|
+
}
|
|
6910
6922
|
function cartSnapshot() {
|
|
6911
6923
|
const lines = useCartStore.getState().lines;
|
|
6912
6924
|
return {
|
|
@@ -6928,15 +6940,21 @@ function useDiscountValidator() {
|
|
|
6928
6940
|
...(config.discounts ?? []).map(storefrontDiscountToPromotion)
|
|
6929
6941
|
];
|
|
6930
6942
|
const localPreview = previewCouponPercent(local, normalized, cartSnapshot());
|
|
6931
|
-
if (localPreview.valid)
|
|
6943
|
+
if (localPreview.valid) {
|
|
6944
|
+
return { valid: true, percent: localPreview.percent, freeShipping: localPreview.freeShipping };
|
|
6945
|
+
}
|
|
6932
6946
|
if (localPreview.reason !== "not_found") {
|
|
6933
6947
|
return { valid: false, percent: 0, message: REASON_MESSAGE[localPreview.reason ?? "not_found"] ?? "Cupom inv\xE1lido." };
|
|
6934
6948
|
}
|
|
6935
|
-
const validation = await validateDiscount({ code: normalized });
|
|
6949
|
+
const validation = await validateDiscount({ code: normalized, subtotal: cartSubtotal() });
|
|
6936
6950
|
if (!validation.valid) {
|
|
6951
|
+
if (validation.reason === "min_subtotal" && validation.minSubtotal != null) {
|
|
6952
|
+
const missing = formatMoney(validation.minSubtotal, config.currency, config.locale);
|
|
6953
|
+
return { valid: false, percent: 0, message: `Este cupom vale em pedidos a partir de ${missing}.` };
|
|
6954
|
+
}
|
|
6937
6955
|
return { valid: false, percent: 0, message: REASON_MESSAGE[validation.reason ?? "not_found"] ?? "Cupom inv\xE1lido ou expirado." };
|
|
6938
6956
|
}
|
|
6939
|
-
if (validation.type !== "percentage") {
|
|
6957
|
+
if (validation.type !== "percentage" && validation.type !== "free_shipping") {
|
|
6940
6958
|
return { valid: false, percent: 0, message: REASON_MESSAGE.unsupported };
|
|
6941
6959
|
}
|
|
6942
6960
|
const promotion = discountToPromotion({
|
|
@@ -6944,7 +6962,7 @@ function useDiscountValidator() {
|
|
|
6944
6962
|
tenantId: "storefront",
|
|
6945
6963
|
title: normalized,
|
|
6946
6964
|
code: validation.code ?? normalized,
|
|
6947
|
-
type:
|
|
6965
|
+
type: validation.type,
|
|
6948
6966
|
method: "code",
|
|
6949
6967
|
value: validation.value,
|
|
6950
6968
|
usageLimit: null,
|
|
@@ -6964,7 +6982,7 @@ function useDiscountValidator() {
|
|
|
6964
6982
|
if (!preview?.valid) {
|
|
6965
6983
|
return { valid: false, percent: 0, message: REASON_MESSAGE[preview?.reason ?? "not_found"] ?? "Cupom inv\xE1lido." };
|
|
6966
6984
|
}
|
|
6967
|
-
return { valid: true, percent: preview.percent };
|
|
6985
|
+
return { valid: true, percent: preview.percent, freeShipping: preview.freeShipping };
|
|
6968
6986
|
}, [config.discounts, config.promotions]);
|
|
6969
6987
|
}
|
|
6970
6988
|
var seq = 0;
|
|
@@ -7035,9 +7053,10 @@ function CartDrawer() {
|
|
|
7035
7053
|
const result = await validate(code);
|
|
7036
7054
|
if (result.valid) {
|
|
7037
7055
|
const applied = code.trim().toUpperCase();
|
|
7038
|
-
cart.applyDiscount(applied, result.percent);
|
|
7056
|
+
cart.applyDiscount(applied, result.percent, { freeShipping: result.freeShipping });
|
|
7039
7057
|
setCode("");
|
|
7040
|
-
|
|
7058
|
+
const effect = result.freeShipping ? "frete gr\xE1tis" : `${result.percent}% de desconto`;
|
|
7059
|
+
toast.success("Cupom aplicado!", `${applied} \u2022 ${effect}`);
|
|
7041
7060
|
} else {
|
|
7042
7061
|
setDiscountError(result.message ?? "Cupom inv\xE1lido.");
|
|
7043
7062
|
toast.error("Cupom inv\xE1lido", result.message ?? "Verifique o c\xF3digo e tente novamente.");
|
|
@@ -7231,12 +7250,25 @@ function CartDrawer() {
|
|
|
7231
7250
|
] })
|
|
7232
7251
|
] }),
|
|
7233
7252
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
|
|
7234
|
-
/* @__PURE__ */ jsxs("dt", { className: "text-muted-foreground", children: [
|
|
7253
|
+
/* @__PURE__ */ jsxs("dt", { className: cart.discountFreeShipping ? "text-emerald-700" : "text-muted-foreground", children: [
|
|
7235
7254
|
"Frete",
|
|
7236
7255
|
delivery.status === "served" && delivery.postalCode && /* @__PURE__ */ jsxs("span", { className: "ml-1 text-xs", children: [
|
|
7237
7256
|
"\xB7 ",
|
|
7238
7257
|
formatPostalCode(delivery.postalCode)
|
|
7239
|
-
] })
|
|
7258
|
+
] }),
|
|
7259
|
+
cart.discountFreeShipping && /* @__PURE__ */ jsxs(
|
|
7260
|
+
"button",
|
|
7261
|
+
{
|
|
7262
|
+
type: "button",
|
|
7263
|
+
onClick: cart.clearDiscount,
|
|
7264
|
+
className: "ml-1 py-1 text-xs text-muted-foreground underline",
|
|
7265
|
+
children: [
|
|
7266
|
+
"(",
|
|
7267
|
+
cart.discountCode,
|
|
7268
|
+
" \u2715)"
|
|
7269
|
+
]
|
|
7270
|
+
}
|
|
7271
|
+
)
|
|
7240
7272
|
] }),
|
|
7241
7273
|
/* @__PURE__ */ jsx("dd", { "data-testid": TID.cartShipping, "data-price": shipping.toFixed(2), children: shipping === 0 ? "Gr\xE1tis" : money(shipping) })
|
|
7242
7274
|
] }),
|
|
@@ -7466,6 +7498,41 @@ async function placeStorefrontOrder({
|
|
|
7466
7498
|
rememberLocalOrder(order.id);
|
|
7467
7499
|
return { order, customerId: customerId ?? order.customerId ?? "" };
|
|
7468
7500
|
}
|
|
7501
|
+
function useMyOrders() {
|
|
7502
|
+
const customerId = useSessionStore((s2) => s2.customerId);
|
|
7503
|
+
const email = useSessionStore((s2) => s2.email);
|
|
7504
|
+
const [orders, setOrders] = useState([]);
|
|
7505
|
+
const [loading, setLoading] = useState(true);
|
|
7506
|
+
const [tick, setTick] = useState(0);
|
|
7507
|
+
const refresh = useCallback(() => setTick((t) => t + 1), []);
|
|
7508
|
+
useEffect(() => {
|
|
7509
|
+
let cancelled = false;
|
|
7510
|
+
const local = listLocalOrderIds();
|
|
7511
|
+
if (!customerId && !email) {
|
|
7512
|
+
if (local.length === 0) {
|
|
7513
|
+
setOrders([]);
|
|
7514
|
+
setLoading(false);
|
|
7515
|
+
return;
|
|
7516
|
+
}
|
|
7517
|
+
}
|
|
7518
|
+
setLoading(true);
|
|
7519
|
+
const query = customerId ? { customerId, limit: 50 } : { customerEmail: email, limit: 50 };
|
|
7520
|
+
getShopProvider().listOrders(query).then((data) => {
|
|
7521
|
+
if (!cancelled) setOrders(data);
|
|
7522
|
+
}).catch(async () => {
|
|
7523
|
+
const mine = await Promise.all(
|
|
7524
|
+
listLocalOrderIds().map((id) => getShopProvider().getOrder(id).catch(() => null))
|
|
7525
|
+
);
|
|
7526
|
+
if (!cancelled) setOrders(mine.filter((o) => !!o));
|
|
7527
|
+
}).finally(() => {
|
|
7528
|
+
if (!cancelled) setLoading(false);
|
|
7529
|
+
});
|
|
7530
|
+
return () => {
|
|
7531
|
+
cancelled = true;
|
|
7532
|
+
};
|
|
7533
|
+
}, [customerId, email, tick]);
|
|
7534
|
+
return { orders, loading, refresh };
|
|
7535
|
+
}
|
|
7469
7536
|
function SignInModal({ defaultEmail = "", onClose, onSignedIn }) {
|
|
7470
7537
|
const [email, setEmail] = useState(defaultEmail);
|
|
7471
7538
|
const [password, setPassword] = useState("");
|
|
@@ -7652,13 +7719,199 @@ function PulseDot({ className = "" }) {
|
|
|
7652
7719
|
/* @__PURE__ */ jsx("span", { className: "relative inline-flex h-2.5 w-2.5 rounded-full bg-current" })
|
|
7653
7720
|
] });
|
|
7654
7721
|
}
|
|
7722
|
+
var SDK_URL = "https://sdk.mercadopago.com/js/v2";
|
|
7723
|
+
var CONTAINER_ID = "fayz-mp-card-brick";
|
|
7724
|
+
var DEVICE_SCRIPT_URL = "https://www.mercadopago.com/v2/security.js";
|
|
7725
|
+
var DEVICE_VIEW = "checkout";
|
|
7726
|
+
function loadDeviceScript() {
|
|
7727
|
+
if (typeof document === "undefined") return;
|
|
7728
|
+
if (document.querySelector(`script[src="${DEVICE_SCRIPT_URL}"]`)) return;
|
|
7729
|
+
const script = document.createElement("script");
|
|
7730
|
+
script.src = DEVICE_SCRIPT_URL;
|
|
7731
|
+
script.setAttribute("view", DEVICE_VIEW);
|
|
7732
|
+
script.async = true;
|
|
7733
|
+
document.body.appendChild(script);
|
|
7734
|
+
}
|
|
7735
|
+
function deviceSessionId() {
|
|
7736
|
+
if (typeof window === "undefined") return null;
|
|
7737
|
+
const id = window.MP_DEVICE_SESSION_ID;
|
|
7738
|
+
return typeof id === "string" && id.trim() ? id.trim() : null;
|
|
7739
|
+
}
|
|
7740
|
+
var sdkPromise = null;
|
|
7741
|
+
function loadSdk() {
|
|
7742
|
+
if (typeof window === "undefined") return Promise.reject(new Error("no window"));
|
|
7743
|
+
if (window.MercadoPago) return Promise.resolve();
|
|
7744
|
+
if (sdkPromise) return sdkPromise;
|
|
7745
|
+
sdkPromise = new Promise((resolve, reject) => {
|
|
7746
|
+
const existing = document.querySelector(`script[src="${SDK_URL}"]`);
|
|
7747
|
+
const script = existing ?? document.createElement("script");
|
|
7748
|
+
script.src = SDK_URL;
|
|
7749
|
+
script.async = true;
|
|
7750
|
+
script.addEventListener("load", () => resolve());
|
|
7751
|
+
script.addEventListener("error", () => {
|
|
7752
|
+
sdkPromise = null;
|
|
7753
|
+
reject(new Error("N\xE3o conseguimos carregar o pagamento com cart\xE3o."));
|
|
7754
|
+
});
|
|
7755
|
+
if (!existing) document.body.appendChild(script);
|
|
7756
|
+
});
|
|
7757
|
+
return sdkPromise;
|
|
7758
|
+
}
|
|
7759
|
+
function CardBrick({ publicKey, amount, email, onSubmit, onError }) {
|
|
7760
|
+
const [ready, setReady] = useState(false);
|
|
7761
|
+
const [failed, setFailed] = useState(null);
|
|
7762
|
+
const mounted = useRef(false);
|
|
7763
|
+
const controller = useRef(null);
|
|
7764
|
+
const submitRef = useRef(onSubmit);
|
|
7765
|
+
submitRef.current = onSubmit;
|
|
7766
|
+
useEffect(() => {
|
|
7767
|
+
if (mounted.current) return;
|
|
7768
|
+
mounted.current = true;
|
|
7769
|
+
let cancelled = false;
|
|
7770
|
+
loadDeviceScript();
|
|
7771
|
+
void (async () => {
|
|
7772
|
+
try {
|
|
7773
|
+
await loadSdk();
|
|
7774
|
+
if (cancelled || !window.MercadoPago) return;
|
|
7775
|
+
const mp = new window.MercadoPago(publicKey, { locale: "pt-BR" });
|
|
7776
|
+
const builder = mp.bricks();
|
|
7777
|
+
controller.current = await builder.create("cardPayment", CONTAINER_ID, {
|
|
7778
|
+
initialization: {
|
|
7779
|
+
amount,
|
|
7780
|
+
...email ? { payer: { email } } : {}
|
|
7781
|
+
},
|
|
7782
|
+
customization: {
|
|
7783
|
+
visual: { style: { theme: "default" } },
|
|
7784
|
+
paymentMethods: { maxInstallments: 12 }
|
|
7785
|
+
},
|
|
7786
|
+
callbacks: {
|
|
7787
|
+
onReady: () => {
|
|
7788
|
+
if (!cancelled) setReady(true);
|
|
7789
|
+
},
|
|
7790
|
+
onSubmit: (formData) => (
|
|
7791
|
+
// Their contract: resolve when the payment is handled, reject to
|
|
7792
|
+
// keep the form up. Rejecting is what lets a declined card be
|
|
7793
|
+
// corrected in place instead of re-typed from scratch.
|
|
7794
|
+
submitRef.current({
|
|
7795
|
+
token: String(formData?.token ?? ""),
|
|
7796
|
+
paymentMethodId: formData?.payment_method_id ?? null,
|
|
7797
|
+
issuerId: formData?.issuer_id == null ? null : String(formData.issuer_id),
|
|
7798
|
+
installments: Number(formData?.installments) || 1,
|
|
7799
|
+
email: formData?.payer?.email ?? null,
|
|
7800
|
+
document: formData?.payer?.identification?.number ? {
|
|
7801
|
+
type: String(formData.payer.identification.type ?? "CPF"),
|
|
7802
|
+
number: String(formData.payer.identification.number)
|
|
7803
|
+
} : null
|
|
7804
|
+
})
|
|
7805
|
+
),
|
|
7806
|
+
onError: (brickError) => {
|
|
7807
|
+
const message = brickError?.message ?? "N\xE3o conseguimos carregar o formul\xE1rio do cart\xE3o.";
|
|
7808
|
+
if (!cancelled) onError?.(message);
|
|
7809
|
+
}
|
|
7810
|
+
}
|
|
7811
|
+
});
|
|
7812
|
+
} catch (err) {
|
|
7813
|
+
if (cancelled) return;
|
|
7814
|
+
const message = err instanceof Error ? err.message : "N\xE3o conseguimos carregar o pagamento com cart\xE3o.";
|
|
7815
|
+
setFailed(message);
|
|
7816
|
+
onError?.(message);
|
|
7817
|
+
}
|
|
7818
|
+
})();
|
|
7819
|
+
return () => {
|
|
7820
|
+
cancelled = true;
|
|
7821
|
+
try {
|
|
7822
|
+
controller.current?.unmount();
|
|
7823
|
+
} catch {
|
|
7824
|
+
}
|
|
7825
|
+
controller.current = null;
|
|
7826
|
+
mounted.current = false;
|
|
7827
|
+
};
|
|
7828
|
+
}, []);
|
|
7829
|
+
if (failed) {
|
|
7830
|
+
return /* @__PURE__ */ jsx("p", { className: "rounded-lg border border-destructive/40 bg-destructive/5 p-4 text-sm text-destructive", children: failed });
|
|
7831
|
+
}
|
|
7832
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
7833
|
+
!ready && /* @__PURE__ */ jsxs(SkeletonGroup, { label: "Carregando o formul\xE1rio do cart\xE3o", className: "space-y-3", children: [
|
|
7834
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-11 w-full rounded-lg" }),
|
|
7835
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
|
|
7836
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-11 w-full rounded-lg" }),
|
|
7837
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-11 w-full rounded-lg" })
|
|
7838
|
+
] }),
|
|
7839
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-11 w-full rounded-lg" })
|
|
7840
|
+
] }),
|
|
7841
|
+
/* @__PURE__ */ jsx("div", { id: CONTAINER_ID, className: ready ? "" : "hidden" })
|
|
7842
|
+
] });
|
|
7843
|
+
}
|
|
7655
7844
|
var POLL_MS = 3e3;
|
|
7656
|
-
|
|
7845
|
+
var RESUME_KEY = "fz.checkout.resume";
|
|
7846
|
+
function useExpiry(expiresAt) {
|
|
7847
|
+
const target = React4.useMemo(() => {
|
|
7848
|
+
if (!expiresAt) return null;
|
|
7849
|
+
const t = new Date(expiresAt).getTime();
|
|
7850
|
+
return Number.isFinite(t) ? t : null;
|
|
7851
|
+
}, [expiresAt]);
|
|
7852
|
+
const [now, setNow] = React4.useState(() => Date.now());
|
|
7853
|
+
React4.useEffect(() => {
|
|
7854
|
+
if (target === null) return;
|
|
7855
|
+
const id = setInterval(() => setNow(Date.now()), 1e3);
|
|
7856
|
+
return () => clearInterval(id);
|
|
7857
|
+
}, [target]);
|
|
7858
|
+
if (target === null) return { secondsLeft: null, expired: false };
|
|
7859
|
+
const secondsLeft = Math.max(0, Math.round((target - now) / 1e3));
|
|
7860
|
+
return { secondsLeft, expired: secondsLeft === 0 };
|
|
7861
|
+
}
|
|
7862
|
+
function formatCountdown(seconds) {
|
|
7863
|
+
const m = Math.floor(seconds / 60);
|
|
7864
|
+
const s2 = seconds % 60;
|
|
7865
|
+
return `${m}:${String(s2).padStart(2, "0")}`;
|
|
7866
|
+
}
|
|
7867
|
+
async function copyText(text) {
|
|
7868
|
+
try {
|
|
7869
|
+
if (navigator.clipboard?.writeText) {
|
|
7870
|
+
await navigator.clipboard.writeText(text);
|
|
7871
|
+
return true;
|
|
7872
|
+
}
|
|
7873
|
+
} catch {
|
|
7874
|
+
}
|
|
7875
|
+
try {
|
|
7876
|
+
const area = document.createElement("textarea");
|
|
7877
|
+
area.value = text;
|
|
7878
|
+
area.setAttribute("readonly", "");
|
|
7879
|
+
area.style.position = "fixed";
|
|
7880
|
+
area.style.top = "-1000px";
|
|
7881
|
+
area.style.opacity = "0";
|
|
7882
|
+
document.body.appendChild(area);
|
|
7883
|
+
area.select();
|
|
7884
|
+
area.setSelectionRange(0, text.length);
|
|
7885
|
+
const ok = document.execCommand("copy");
|
|
7886
|
+
document.body.removeChild(area);
|
|
7887
|
+
return ok;
|
|
7888
|
+
} catch {
|
|
7889
|
+
return false;
|
|
7890
|
+
}
|
|
7891
|
+
}
|
|
7892
|
+
function rememberSession(sessionId, provider) {
|
|
7893
|
+
try {
|
|
7894
|
+
sessionStorage.setItem(RESUME_KEY, JSON.stringify({ sessionId, provider }));
|
|
7895
|
+
} catch {
|
|
7896
|
+
}
|
|
7897
|
+
}
|
|
7898
|
+
function recallSessionProvider(sessionId) {
|
|
7899
|
+
try {
|
|
7900
|
+
const raw = JSON.parse(sessionStorage.getItem(RESUME_KEY) ?? "null");
|
|
7901
|
+
return raw?.sessionId === sessionId ? raw.provider ?? null : null;
|
|
7902
|
+
} catch {
|
|
7903
|
+
return null;
|
|
7904
|
+
}
|
|
7905
|
+
}
|
|
7906
|
+
function CheckoutPayment({ input, onPaid, onBack, money, onUnavailable, resume, amount }) {
|
|
7657
7907
|
const [phase, setPhase] = useState("opening");
|
|
7658
7908
|
const [charge, setCharge] = useState(null);
|
|
7909
|
+
const expiry = useExpiry(charge?.expiresAt);
|
|
7659
7910
|
const [total, setTotal] = useState(null);
|
|
7660
|
-
const [
|
|
7661
|
-
const [
|
|
7911
|
+
const [redirectUrl, setRedirectUrl] = useState(null);
|
|
7912
|
+
const [brickKey, setBrickKey] = useState(null);
|
|
7913
|
+
const [sessionId, setSessionId] = useState(resume?.sessionId ?? null);
|
|
7914
|
+
const [provider, setProvider] = useState(resume?.provider ?? null);
|
|
7662
7915
|
const [error, setError] = useState(null);
|
|
7663
7916
|
const [copied, setCopied] = useState(false);
|
|
7664
7917
|
const [checking, setChecking] = useState(false);
|
|
@@ -7674,15 +7927,37 @@ function CheckoutPayment({ input, onPaid, onBack, money, onUnavailable }) {
|
|
|
7674
7927
|
setPhase("opening");
|
|
7675
7928
|
setError(null);
|
|
7676
7929
|
try {
|
|
7677
|
-
|
|
7930
|
+
if (input.paymentMethod === "credit_card" && shop.paymentPublicKey) {
|
|
7931
|
+
const providerSlug = input.provider ?? null;
|
|
7932
|
+
const publicKey = providerSlug ? await shop.paymentPublicKey(providerSlug) : null;
|
|
7933
|
+
if (publicKey) {
|
|
7934
|
+
setProvider(providerSlug);
|
|
7935
|
+
setBrickKey(publicKey);
|
|
7936
|
+
setPhase("card");
|
|
7937
|
+
return;
|
|
7938
|
+
}
|
|
7939
|
+
}
|
|
7940
|
+
const session = await shop.openCheckoutSession({
|
|
7941
|
+
...input,
|
|
7942
|
+
// Para onde o adquirente devolve o comprador. É esta página, com o id da
|
|
7943
|
+
// sessão pendurado: quem volta volta em página nova, sem estado nenhum.
|
|
7944
|
+
returnUrl: typeof window === "undefined" ? null : window.location.href.split("?")[0]
|
|
7945
|
+
});
|
|
7678
7946
|
setSessionId(session.sessionId);
|
|
7679
7947
|
setProvider(session.provider ?? input.provider ?? null);
|
|
7680
7948
|
setTotal(session.total);
|
|
7681
7949
|
setCharge(session.charge);
|
|
7950
|
+
if (session.paymentUrl && !session.charge) {
|
|
7951
|
+
setRedirectUrl(session.paymentUrl);
|
|
7952
|
+
setPhase("redirect");
|
|
7953
|
+
return;
|
|
7954
|
+
}
|
|
7682
7955
|
setPhase(session.charge ? "waiting" : "error");
|
|
7683
7956
|
if (!session.charge) setError("N\xE3o conseguimos abrir a cobran\xE7a agora.");
|
|
7684
7957
|
} catch (err) {
|
|
7685
|
-
|
|
7958
|
+
const status = err?.status;
|
|
7959
|
+
const code = err?.code;
|
|
7960
|
+
if (status === 404 || code === "method_unavailable") {
|
|
7686
7961
|
onUnavailable?.();
|
|
7687
7962
|
return;
|
|
7688
7963
|
}
|
|
@@ -7693,14 +7968,18 @@ function CheckoutPayment({ input, onPaid, onBack, money, onUnavailable }) {
|
|
|
7693
7968
|
useEffect(() => {
|
|
7694
7969
|
if (opened.current) return;
|
|
7695
7970
|
opened.current = true;
|
|
7971
|
+
if (resume?.sessionId) {
|
|
7972
|
+
setPhase("waiting");
|
|
7973
|
+
return;
|
|
7974
|
+
}
|
|
7696
7975
|
void open();
|
|
7697
|
-
}, [open]);
|
|
7976
|
+
}, [open, resume?.sessionId]);
|
|
7698
7977
|
const check = useCallback(async () => {
|
|
7699
7978
|
if (!sessionId || settled.current) return false;
|
|
7700
7979
|
const shop = getShopProvider();
|
|
7701
7980
|
if (!shop.settleCheckoutSession) return false;
|
|
7702
7981
|
try {
|
|
7703
|
-
const result = await shop.settleCheckoutSession(sessionId, provider);
|
|
7982
|
+
const result = await shop.settleCheckoutSession(sessionId, provider, resume?.chargeToken ?? null);
|
|
7704
7983
|
if (settled.current) return false;
|
|
7705
7984
|
if (result.state === "paid" && result.orderId) {
|
|
7706
7985
|
settled.current = true;
|
|
@@ -7718,7 +7997,7 @@ function CheckoutPayment({ input, onPaid, onBack, money, onUnavailable }) {
|
|
|
7718
7997
|
} catch {
|
|
7719
7998
|
return false;
|
|
7720
7999
|
}
|
|
7721
|
-
}, [sessionId, provider, onPaid]);
|
|
8000
|
+
}, [sessionId, provider, resume?.chargeToken, onPaid]);
|
|
7722
8001
|
useEffect(() => {
|
|
7723
8002
|
if (phase !== "waiting" || !sessionId) return;
|
|
7724
8003
|
let stopped = false;
|
|
@@ -7737,13 +8016,116 @@ function CheckoutPayment({ input, onPaid, onBack, money, onUnavailable }) {
|
|
|
7737
8016
|
}
|
|
7738
8017
|
async function copy() {
|
|
7739
8018
|
if (!charge?.emv) return;
|
|
7740
|
-
|
|
7741
|
-
await navigator.clipboard.writeText(charge.emv);
|
|
8019
|
+
if (await copyText(charge.emv)) {
|
|
7742
8020
|
setCopied(true);
|
|
7743
8021
|
setTimeout(() => setCopied(false), 2400);
|
|
7744
|
-
|
|
7745
|
-
toast.error("Copie o c\xF3digo manualmente");
|
|
8022
|
+
return;
|
|
7746
8023
|
}
|
|
8024
|
+
toast.error("Copie o c\xF3digo manualmente");
|
|
8025
|
+
}
|
|
8026
|
+
if (phase === "card" && brickKey) {
|
|
8027
|
+
const acquirer = gatewayLabel(provider);
|
|
8028
|
+
return /* @__PURE__ */ jsxs("div", { "data-testid": TID.checkoutPayment, className: "space-y-4 rounded-xl border bg-card p-6", children: [
|
|
8029
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
8030
|
+
/* @__PURE__ */ jsx(CreditCard, { className: "h-5 w-5 text-primary" }),
|
|
8031
|
+
/* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", children: "Pague com cart\xE3o sem sair da loja" })
|
|
8032
|
+
] }),
|
|
8033
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: acquirer ? `Os campos do cart\xE3o s\xE3o da ${acquirer} e o n\xFAmero n\xE3o passa por esta loja. Seu pedido \xE9 criado assim que o pagamento for aprovado.` : "O n\xFAmero do cart\xE3o n\xE3o passa por esta loja. Seu pedido \xE9 criado assim que o pagamento for aprovado." }),
|
|
8034
|
+
(total ?? amount) != null && /* @__PURE__ */ jsxs("p", { className: "text-sm", children: [
|
|
8035
|
+
"Valor: ",
|
|
8036
|
+
/* @__PURE__ */ jsx("strong", { "data-testid": TID.checkoutPaymentTotal, children: money(total ?? amount) })
|
|
8037
|
+
] }),
|
|
8038
|
+
/* @__PURE__ */ jsx(
|
|
8039
|
+
CardBrick,
|
|
8040
|
+
{
|
|
8041
|
+
publicKey: brickKey,
|
|
8042
|
+
amount: total ?? amount ?? 0,
|
|
8043
|
+
email: input.customer?.email ?? null,
|
|
8044
|
+
onError: (message) => setError(message),
|
|
8045
|
+
onSubmit: async (result) => {
|
|
8046
|
+
const shop = getShopProvider();
|
|
8047
|
+
if (!shop.openCheckoutSession) throw new Error("sem gateway");
|
|
8048
|
+
try {
|
|
8049
|
+
const session = await shop.openCheckoutSession({
|
|
8050
|
+
...input,
|
|
8051
|
+
cardToken: result.token,
|
|
8052
|
+
installments: result.installments,
|
|
8053
|
+
paymentMethodId: result.paymentMethodId,
|
|
8054
|
+
issuerId: result.issuerId,
|
|
8055
|
+
// Their anti-fraud reads this, and a card charged without it is
|
|
8056
|
+
// declined more often for no visible reason.
|
|
8057
|
+
deviceId: deviceSessionId()
|
|
8058
|
+
});
|
|
8059
|
+
setSessionId(session.sessionId);
|
|
8060
|
+
setProvider(session.provider ?? input.provider ?? null);
|
|
8061
|
+
setTotal(session.total);
|
|
8062
|
+
const orderId = session.orderId ?? null;
|
|
8063
|
+
if (orderId) {
|
|
8064
|
+
settled.current = true;
|
|
8065
|
+
setPhase("settling");
|
|
8066
|
+
onPaid(orderId);
|
|
8067
|
+
return;
|
|
8068
|
+
}
|
|
8069
|
+
setPhase("waiting");
|
|
8070
|
+
} catch (err) {
|
|
8071
|
+
const message = err instanceof Error ? err.message : "O pagamento n\xE3o foi aprovado.";
|
|
8072
|
+
setError(message);
|
|
8073
|
+
throw err;
|
|
8074
|
+
}
|
|
8075
|
+
}
|
|
8076
|
+
}
|
|
8077
|
+
),
|
|
8078
|
+
error && /* @__PURE__ */ jsx("p", { className: "rounded-lg border border-destructive/40 bg-destructive/5 p-3 text-sm text-destructive", children: error }),
|
|
8079
|
+
/* @__PURE__ */ jsx(
|
|
8080
|
+
"button",
|
|
8081
|
+
{
|
|
8082
|
+
type: "button",
|
|
8083
|
+
onClick: onBack,
|
|
8084
|
+
className: "inline-flex min-h-11 items-center rounded-lg border px-4 py-2.5 text-sm font-medium transition hover:bg-muted",
|
|
8085
|
+
children: "Voltar"
|
|
8086
|
+
}
|
|
8087
|
+
)
|
|
8088
|
+
] });
|
|
8089
|
+
}
|
|
8090
|
+
if (phase === "redirect" && redirectUrl) {
|
|
8091
|
+
const acquirer = gatewayLabel(provider);
|
|
8092
|
+
return /* @__PURE__ */ jsxs("div", { "data-testid": TID.checkoutPayment, className: "space-y-4 rounded-xl border bg-card p-6", children: [
|
|
8093
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
8094
|
+
/* @__PURE__ */ jsx(CreditCard, { className: "h-5 w-5 text-primary" }),
|
|
8095
|
+
/* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", children: acquirer ? `Pague com cart\xE3o na p\xE1gina da ${acquirer}` : "Pague com cart\xE3o" })
|
|
8096
|
+
] }),
|
|
8097
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: acquirer ? `Os dados do cart\xE3o s\xE3o digitados no ambiente seguro da ${acquirer} \u2014 a loja n\xE3o v\xEA o n\xFAmero. Ao terminar, voc\xEA volta para c\xE1 e o pedido \xE9 criado.` : "Os dados do cart\xE3o s\xE3o digitados no ambiente seguro do provedor \u2014 a loja n\xE3o v\xEA o n\xFAmero. Ao terminar, voc\xEA volta para c\xE1 e o pedido \xE9 criado." }),
|
|
8098
|
+
total != null && /* @__PURE__ */ jsxs("p", { className: "text-sm", children: [
|
|
8099
|
+
"Valor: ",
|
|
8100
|
+
/* @__PURE__ */ jsx("strong", { "data-testid": TID.checkoutPaymentTotal, children: money(total) })
|
|
8101
|
+
] }),
|
|
8102
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
8103
|
+
/* @__PURE__ */ jsxs(
|
|
8104
|
+
"button",
|
|
8105
|
+
{
|
|
8106
|
+
type: "button",
|
|
8107
|
+
onClick: () => {
|
|
8108
|
+
if (sessionId) rememberSession(sessionId, provider);
|
|
8109
|
+
window.location.assign(redirectUrl);
|
|
8110
|
+
},
|
|
8111
|
+
className: "inline-flex min-h-11 items-center gap-2 rounded-lg bg-primary px-5 py-2.5 text-sm font-semibold text-primary-foreground transition hover:opacity-90",
|
|
8112
|
+
children: [
|
|
8113
|
+
/* @__PURE__ */ jsx(Lock, { className: "h-4 w-4" }),
|
|
8114
|
+
acquirer ? `Pagar com ${acquirer}` : "Pagar com cart\xE3o"
|
|
8115
|
+
]
|
|
8116
|
+
}
|
|
8117
|
+
),
|
|
8118
|
+
/* @__PURE__ */ jsx(
|
|
8119
|
+
"button",
|
|
8120
|
+
{
|
|
8121
|
+
type: "button",
|
|
8122
|
+
onClick: onBack,
|
|
8123
|
+
className: "inline-flex min-h-11 items-center rounded-lg border px-4 py-2.5 text-sm font-medium transition hover:bg-muted",
|
|
8124
|
+
children: "Voltar"
|
|
8125
|
+
}
|
|
8126
|
+
)
|
|
8127
|
+
] })
|
|
8128
|
+
] });
|
|
7747
8129
|
}
|
|
7748
8130
|
if (phase === "opening") {
|
|
7749
8131
|
return (
|
|
@@ -7805,6 +8187,30 @@ function CheckoutPayment({ input, onPaid, onBack, money, onUnavailable }) {
|
|
|
7805
8187
|
] })
|
|
7806
8188
|
] });
|
|
7807
8189
|
}
|
|
8190
|
+
if (!charge) {
|
|
8191
|
+
return /* @__PURE__ */ jsxs("div", { "data-testid": TID.checkoutPayment, className: "space-y-3 rounded-xl border bg-card p-6", "aria-live": "polite", children: [
|
|
8192
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
8193
|
+
/* @__PURE__ */ jsx(PulseDot, {}),
|
|
8194
|
+
/* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", children: "Confirmando seu pagamento\u2026" })
|
|
8195
|
+
] }),
|
|
8196
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Assim que o pagamento for confirmado, seu pedido aparece aqui. Pode deixar esta tela aberta." }),
|
|
8197
|
+
/* @__PURE__ */ jsxs(
|
|
8198
|
+
"button",
|
|
8199
|
+
{
|
|
8200
|
+
type: "button",
|
|
8201
|
+
onClick: () => {
|
|
8202
|
+
void confirmPaid();
|
|
8203
|
+
},
|
|
8204
|
+
disabled: checking,
|
|
8205
|
+
className: "inline-flex min-h-11 items-center gap-2 rounded-lg border border-primary px-4 py-2.5 text-sm font-semibold text-primary transition hover:bg-primary/5 disabled:opacity-60",
|
|
8206
|
+
children: [
|
|
8207
|
+
checking ? /* @__PURE__ */ jsx(PulseDot, {}) : /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" }),
|
|
8208
|
+
checking ? "Verificando\u2026" : "J\xE1 paguei"
|
|
8209
|
+
]
|
|
8210
|
+
}
|
|
8211
|
+
)
|
|
8212
|
+
] });
|
|
8213
|
+
}
|
|
7808
8214
|
return /* @__PURE__ */ jsxs("div", { "data-testid": TID.checkoutPayment, className: "space-y-4", "aria-live": "polite", children: [
|
|
7809
8215
|
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border bg-card p-6", children: [
|
|
7810
8216
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
@@ -7813,12 +8219,14 @@ function CheckoutPayment({ input, onPaid, onBack, money, onUnavailable }) {
|
|
|
7813
8219
|
] }),
|
|
7814
8220
|
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Seu pedido \xE9 criado assim que o pagamento entrar. Pode deixar esta tela aberta." }),
|
|
7815
8221
|
/* @__PURE__ */ jsxs("div", { className: "mt-5 grid gap-5 sm:grid-cols-[auto_minmax(0,1fr)] sm:items-start", children: [
|
|
7816
|
-
charge?.qrcodeBase64 && /* @__PURE__ */ jsx(
|
|
8222
|
+
(charge?.qrcodeBase64 || charge?.qrcodeUrl) && /* @__PURE__ */ jsx(
|
|
7817
8223
|
"img",
|
|
7818
8224
|
{
|
|
7819
|
-
src: `data:image/png;base64,${charge.qrcodeBase64}
|
|
8225
|
+
src: charge.qrcodeBase64 ? `data:image/png;base64,${charge.qrcodeBase64}` : charge.qrcodeUrl,
|
|
7820
8226
|
alt: "QR code do Pix",
|
|
7821
|
-
|
|
8227
|
+
width: 276,
|
|
8228
|
+
height: 276,
|
|
8229
|
+
className: "mx-auto box-content h-[276px] w-[276px] max-w-full rounded-lg border bg-white p-4"
|
|
7822
8230
|
}
|
|
7823
8231
|
),
|
|
7824
8232
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
@@ -7835,7 +8243,28 @@ function CheckoutPayment({ input, onPaid, onBack, money, onUnavailable }) {
|
|
|
7835
8243
|
children: charge?.emv
|
|
7836
8244
|
}
|
|
7837
8245
|
),
|
|
7838
|
-
/* @__PURE__ */ jsxs("
|
|
8246
|
+
expiry.secondsLeft !== null && !expiry.expired && /* @__PURE__ */ jsxs("p", { className: "mt-2 text-xs text-muted-foreground", children: [
|
|
8247
|
+
"Este c\xF3digo vale por mais",
|
|
8248
|
+
" ",
|
|
8249
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium tabular-nums text-foreground", children: formatCountdown(expiry.secondsLeft) })
|
|
8250
|
+
] }),
|
|
8251
|
+
expiry.expired && /* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-2", children: [
|
|
8252
|
+
/* @__PURE__ */ jsx("p", { "data-testid": TID.checkoutExpired, className: "text-sm text-muted-foreground", children: "O prazo deste c\xF3digo acabou. Gere outro para pagar." }),
|
|
8253
|
+
/* @__PURE__ */ jsx(
|
|
8254
|
+
"button",
|
|
8255
|
+
{
|
|
8256
|
+
type: "button",
|
|
8257
|
+
onClick: () => {
|
|
8258
|
+
opened.current = false;
|
|
8259
|
+
setCharge(null);
|
|
8260
|
+
void open();
|
|
8261
|
+
},
|
|
8262
|
+
className: "inline-flex min-h-11 items-center gap-2 rounded-lg bg-primary px-4 py-2.5 text-sm font-semibold text-primary-foreground transition hover:opacity-90",
|
|
8263
|
+
children: "Gerar novo c\xF3digo"
|
|
8264
|
+
}
|
|
8265
|
+
)
|
|
8266
|
+
] }),
|
|
8267
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-3", hidden: expiry.expired, children: [
|
|
7839
8268
|
/* @__PURE__ */ jsxs(
|
|
7840
8269
|
"button",
|
|
7841
8270
|
{
|
|
@@ -7914,8 +8343,52 @@ function SuccessMark() {
|
|
|
7914
8343
|
) })
|
|
7915
8344
|
] });
|
|
7916
8345
|
}
|
|
8346
|
+
function useKnownCustomer() {
|
|
8347
|
+
const customerId = useSessionStore((s2) => s2.customerId);
|
|
8348
|
+
const { orders, loading: ordersLoading } = useMyOrders();
|
|
8349
|
+
const [contact, setContact] = useState(null);
|
|
8350
|
+
const [checked, setChecked] = useState(false);
|
|
8351
|
+
useEffect(() => {
|
|
8352
|
+
if (!customerId) {
|
|
8353
|
+
setContact(null);
|
|
8354
|
+
setChecked(true);
|
|
8355
|
+
return;
|
|
8356
|
+
}
|
|
8357
|
+
let cancelled = false;
|
|
8358
|
+
const shop = getShopProvider();
|
|
8359
|
+
Promise.resolve(shop.getCustomer?.(customerId)).then((customer) => {
|
|
8360
|
+
if (cancelled) return;
|
|
8361
|
+
setContact(customer ? { phone: customer.phone ?? null, document: customer.document ?? null } : null);
|
|
8362
|
+
}).catch(() => {
|
|
8363
|
+
if (!cancelled) setContact(null);
|
|
8364
|
+
}).finally(() => {
|
|
8365
|
+
if (!cancelled) setChecked(true);
|
|
8366
|
+
});
|
|
8367
|
+
return () => {
|
|
8368
|
+
cancelled = true;
|
|
8369
|
+
};
|
|
8370
|
+
}, [customerId]);
|
|
8371
|
+
const lastAddress = pickLastAddress(orders);
|
|
8372
|
+
return {
|
|
8373
|
+
phone: contact?.phone ?? null,
|
|
8374
|
+
document: contact?.document ?? null,
|
|
8375
|
+
address: lastAddress,
|
|
8376
|
+
ready: checked && !ordersLoading
|
|
8377
|
+
};
|
|
8378
|
+
}
|
|
8379
|
+
function pickLastAddress(orders) {
|
|
8380
|
+
for (const order of orders) {
|
|
8381
|
+
const address = order.shippingAddress;
|
|
8382
|
+
if (address && (address.postalCode || address.street)) return address;
|
|
8383
|
+
}
|
|
8384
|
+
return null;
|
|
8385
|
+
}
|
|
7917
8386
|
var PAYMENT_LABELS = {
|
|
7918
8387
|
pix: { label: "Pix", hint: "Voc\xEA recebe a chave para pagar ap\xF3s confirmar o pedido" },
|
|
8388
|
+
// O cartão tem DOIS significados agora, e o texto muda com a loja: sem
|
|
8389
|
+
// adquirente é a maquininha do entregador; com adquirente é a página segura
|
|
8390
|
+
// dele. Ver PAYMENT_HINTS abaixo — prometer "maquininha" para quem vai ser
|
|
8391
|
+
// redirecionado é a loja mentindo sobre a própria entrega.
|
|
7919
8392
|
credit_card: { label: "Cart\xE3o de cr\xE9dito", hint: "Maquininha na entrega" },
|
|
7920
8393
|
debit_card: { label: "Cart\xE3o de d\xE9bito", hint: "Maquininha na entrega" },
|
|
7921
8394
|
boleto: { label: "Boleto", hint: "Enviado por e-mail ap\xF3s a confirma\xE7\xE3o" },
|
|
@@ -7964,12 +8437,26 @@ function CheckoutPage() {
|
|
|
7964
8437
|
const fieldPolicy = policy?.checkoutFields ?? {};
|
|
7965
8438
|
const gatewayCheckout = config.payments.mode === "gateway" || !!policy?.paymentProvider;
|
|
7966
8439
|
const shows = (key) => key === "document" ? gatewayCheckout || fieldPolicy.document?.visible === true : fieldPolicy[key]?.visible !== false;
|
|
7967
|
-
const requires = (key) => key === "document" ? gatewayCheckout || fieldPolicy
|
|
8440
|
+
const requires = (key) => key === "document" || key === "phone" ? gatewayCheckout || fieldPolicy[key]?.visible === true && fieldPolicy[key]?.required === true : fieldPolicy[key]?.visible !== false && fieldPolicy[key]?.required === true;
|
|
7968
8441
|
const [selectedAddressId, setSelectedAddressId] = useState("new");
|
|
7969
8442
|
const [savedAddresses, setSavedAddresses] = useState([]);
|
|
7970
8443
|
const [addressesLoading, setAddressesLoading] = useState(false);
|
|
7971
8444
|
const [addressMode, setAddressMode] = useState("new");
|
|
7972
|
-
const [
|
|
8445
|
+
const [resume] = useState(() => {
|
|
8446
|
+
if (typeof window === "undefined") return null;
|
|
8447
|
+
const params = new URLSearchParams(window.location.search);
|
|
8448
|
+
const sessionId = params.get("vindi_session") ?? params.get("pay_session");
|
|
8449
|
+
if (!sessionId) return null;
|
|
8450
|
+
return {
|
|
8451
|
+
sessionId,
|
|
8452
|
+
provider: recallSessionProvider(sessionId),
|
|
8453
|
+
chargeToken: params.get("token_transaction")
|
|
8454
|
+
};
|
|
8455
|
+
});
|
|
8456
|
+
const [paymentMethod, setPaymentMethod] = useState(
|
|
8457
|
+
resume ? "credit_card" : paymentMethods[0] ?? "pix"
|
|
8458
|
+
);
|
|
8459
|
+
const known = useKnownCustomer();
|
|
7973
8460
|
const [form, setForm] = useState({
|
|
7974
8461
|
email: session.email ?? "",
|
|
7975
8462
|
name: session.name ?? "",
|
|
@@ -7983,7 +8470,22 @@ function CheckoutPage() {
|
|
|
7983
8470
|
district: "",
|
|
7984
8471
|
state: ""
|
|
7985
8472
|
});
|
|
7986
|
-
|
|
8473
|
+
React4.useEffect(() => {
|
|
8474
|
+
if (!known.ready) return;
|
|
8475
|
+
setForm((current) => ({
|
|
8476
|
+
...current,
|
|
8477
|
+
phone: current.phone || known.phone || "",
|
|
8478
|
+
document: current.document || known.document || "",
|
|
8479
|
+
zip: current.zip || known.address?.postalCode || "",
|
|
8480
|
+
street: current.street || known.address?.street || "",
|
|
8481
|
+
number: current.number || known.address?.number || "",
|
|
8482
|
+
complement: current.complement || known.address?.complement || "",
|
|
8483
|
+
district: current.district || known.address?.district || "",
|
|
8484
|
+
city: current.city || known.address?.city || "",
|
|
8485
|
+
state: current.state || known.address?.state || ""
|
|
8486
|
+
}));
|
|
8487
|
+
}, [known.ready, known.phone, known.document, known.address]);
|
|
8488
|
+
const [step, setStep] = useState(resume ? 3 : 1);
|
|
7987
8489
|
const [paidOrderId, setPaidOrderId] = useState(null);
|
|
7988
8490
|
const [error, setError] = useState(null);
|
|
7989
8491
|
const [discountCode, setDiscountCode] = useState("");
|
|
@@ -8006,7 +8508,26 @@ function CheckoutPage() {
|
|
|
8006
8508
|
quantity: line.quantity,
|
|
8007
8509
|
optionsLabel: line.optionsLabel ?? null
|
|
8008
8510
|
})),
|
|
8009
|
-
|
|
8511
|
+
// The document and the phone travel WITH the buyer, not only inside the
|
|
8512
|
+
// address.
|
|
8513
|
+
//
|
|
8514
|
+
// The acquirer charges a PERSON: Vindi refuses a charge with no document
|
|
8515
|
+
// ("Informe o CPF ou CNPJ do comprador"), and AbacatePay's customer block is
|
|
8516
|
+
// all-or-nothing — name, email, taxId and cellphone, or no customer at all.
|
|
8517
|
+
// With two of the four it had been opening charges while registering nobody,
|
|
8518
|
+
// which is the "no client was created" the store saw in the provider account.
|
|
8519
|
+
//
|
|
8520
|
+
// The field was already asked for on screen: with an acquirer connected,
|
|
8521
|
+
// `requires('document')` is true and nobody gets past step 1 without filling
|
|
8522
|
+
// it in. What was missing was forwarding it to whoever charges. On the ORDER
|
|
8523
|
+
// it still travels inside the address, because of shop_place_order's
|
|
8524
|
+
// signature — different roads.
|
|
8525
|
+
customer: {
|
|
8526
|
+
name: form.name.trim(),
|
|
8527
|
+
email: form.email.trim(),
|
|
8528
|
+
document: documentDigits(form.document) || void 0,
|
|
8529
|
+
phone: form.phone.trim() || void 0
|
|
8530
|
+
},
|
|
8010
8531
|
shippingAddress: {
|
|
8011
8532
|
postalCode: form.zip.trim(),
|
|
8012
8533
|
street: form.street.trim(),
|
|
@@ -8026,12 +8547,21 @@ function CheckoutPage() {
|
|
|
8026
8547
|
provider: policy?.paymentProvider ?? null
|
|
8027
8548
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
8028
8549
|
}), [cart.lines, cart.discountCode, form, paymentMethod, policy?.paymentProvider]);
|
|
8029
|
-
const [
|
|
8030
|
-
const
|
|
8550
|
+
const [unavailable, setUnavailable] = useState([]);
|
|
8551
|
+
const cardIsCharged = !unavailable.includes("credit_card") && (!policy?.paymentProvider || isChargeableProvider(policy.paymentProvider)) && (!policy?.paymentProvider || supportsCard(policy.paymentProvider));
|
|
8552
|
+
const acquirerMissing = unavailable.includes(paymentMethod);
|
|
8553
|
+
const chargesOnline = (
|
|
8554
|
+
// Pix é cobrado dentro da loja; cartão é pago na página do adquirente e
|
|
8555
|
+
// volta para cá. Débito, dinheiro e "combinar" nunca foram cobrança online.
|
|
8556
|
+
// `cardIsCharged` rather than a bare `credit_card`: card is charged online
|
|
8557
|
+
// only where the acquirer charges cards. Where it does not, this screen
|
|
8558
|
+
// offers the order without a charge — the card-reader road, as it always was.
|
|
8559
|
+
(paymentMethod === "pix" || paymentMethod === "credit_card" && cardIsCharged) && !acquirerMissing && (!policy?.paymentProvider || isChargeableProvider(policy.paymentProvider))
|
|
8560
|
+
);
|
|
8031
8561
|
const money = (value) => formatMoney(value, config.currency, config.locale);
|
|
8032
8562
|
useEffect(() => {
|
|
8033
|
-
if (cart.lines.length === 0 && !paidOrderId && !leaving.current) navigateTo(config.catalogPath);
|
|
8034
|
-
}, [cart.lines.length, config.catalogPath, paidOrderId]);
|
|
8563
|
+
if (cart.lines.length === 0 && !paidOrderId && !leaving.current && !resume) navigateTo(config.catalogPath);
|
|
8564
|
+
}, [cart.lines.length, config.catalogPath, paidOrderId, resume]);
|
|
8035
8565
|
const set = (key) => (value) => {
|
|
8036
8566
|
setError(null);
|
|
8037
8567
|
setForm((current) => ({ ...current, [key]: value }));
|
|
@@ -8072,10 +8602,11 @@ function CheckoutPage() {
|
|
|
8072
8602
|
const appliedCode = discountCode.trim().toUpperCase();
|
|
8073
8603
|
const result = await validateDiscount2(discountCode);
|
|
8074
8604
|
if (result.valid) {
|
|
8075
|
-
cart.applyDiscount(appliedCode, result.percent);
|
|
8605
|
+
cart.applyDiscount(appliedCode, result.percent, { freeShipping: result.freeShipping });
|
|
8076
8606
|
setDiscountCode(appliedCode);
|
|
8077
|
-
|
|
8078
|
-
|
|
8607
|
+
const effect = result.freeShipping ? "frete gr\xE1tis" : `${result.percent}% de desconto`;
|
|
8608
|
+
setDiscountSuccess(`${appliedCode} aplicado: ${effect}.`);
|
|
8609
|
+
toast.success("Cupom aplicado!", `${appliedCode} \u2022 ${effect}`);
|
|
8079
8610
|
} else {
|
|
8080
8611
|
setDiscountError(result.message ?? "Cupom inv\xE1lido.");
|
|
8081
8612
|
toast.error("Cupom inv\xE1lido", result.message ?? "Verifique o c\xF3digo e tente novamente.");
|
|
@@ -8218,8 +8749,13 @@ function CheckoutPage() {
|
|
|
8218
8749
|
if (typeof window !== "undefined") window.scrollTo({ top: 0, behavior: "smooth" });
|
|
8219
8750
|
}
|
|
8220
8751
|
function advance() {
|
|
8221
|
-
if (step === 1 && validateContact())
|
|
8222
|
-
|
|
8752
|
+
if (step === 1 && validateContact()) {
|
|
8753
|
+
void getShopProvider().saveCustomerContact?.({
|
|
8754
|
+
phone: form.phone.trim() || null,
|
|
8755
|
+
document: documentDigits(form.document) || null
|
|
8756
|
+
});
|
|
8757
|
+
goToStep(2);
|
|
8758
|
+
} else if (step === 2 && validateDelivery()) goToStep(3);
|
|
8223
8759
|
}
|
|
8224
8760
|
async function confirmWithoutCharge() {
|
|
8225
8761
|
if (!validate()) return;
|
|
@@ -8491,7 +9027,8 @@ function CheckoutPage() {
|
|
|
8491
9027
|
step === 3 && !placing && /* @__PURE__ */ jsxs("section", { children: [
|
|
8492
9028
|
/* @__PURE__ */ jsx("h2", { className: "mb-3 text-xl font-semibold tracking-tight", children: "Pagamento" }),
|
|
8493
9029
|
/* @__PURE__ */ jsx("div", { className: "mb-3 grid gap-3", role: "radiogroup", "aria-label": "Forma de pagamento", children: paymentMethods.map((method) => {
|
|
8494
|
-
const
|
|
9030
|
+
const base = PAYMENT_LABELS[method];
|
|
9031
|
+
const copy = method === "credit_card" && cardIsCharged ? { ...base, hint: "Voc\xEA paga na p\xE1gina segura do provedor e volta para a loja" } : base;
|
|
8495
9032
|
const selected = paymentMethod === method;
|
|
8496
9033
|
return (
|
|
8497
9034
|
// Cada forma de pagamento abre o que ELA pede, embaixo dela
|
|
@@ -8524,8 +9061,10 @@ function CheckoutPage() {
|
|
|
8524
9061
|
{
|
|
8525
9062
|
input: checkoutSessionInput,
|
|
8526
9063
|
money,
|
|
9064
|
+
amount: total,
|
|
8527
9065
|
onBack: () => goToStep(2),
|
|
8528
|
-
|
|
9066
|
+
resume,
|
|
9067
|
+
onUnavailable: () => setUnavailable((list) => list.includes(method) ? list : [...list, method]),
|
|
8529
9068
|
onPaid: (orderId) => {
|
|
8530
9069
|
leaving.current = true;
|
|
8531
9070
|
setPaidOrderId(orderId);
|
|
@@ -8676,7 +9215,22 @@ function CheckoutPage() {
|
|
|
8676
9215
|
] })
|
|
8677
9216
|
] }),
|
|
8678
9217
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
|
|
8679
|
-
/* @__PURE__ */
|
|
9218
|
+
/* @__PURE__ */ jsxs("dt", { className: cart.discountFreeShipping ? "text-emerald-700" : "text-muted-foreground", children: [
|
|
9219
|
+
"Entrega",
|
|
9220
|
+
cart.discountFreeShipping && /* @__PURE__ */ jsxs(
|
|
9221
|
+
"button",
|
|
9222
|
+
{
|
|
9223
|
+
type: "button",
|
|
9224
|
+
onClick: clearDiscountCode,
|
|
9225
|
+
className: "ml-1 text-xs text-muted-foreground underline",
|
|
9226
|
+
children: [
|
|
9227
|
+
"(",
|
|
9228
|
+
cart.discountCode,
|
|
9229
|
+
" \xD7)"
|
|
9230
|
+
]
|
|
9231
|
+
}
|
|
9232
|
+
)
|
|
9233
|
+
] }),
|
|
8680
9234
|
/* @__PURE__ */ jsx("dd", { "data-price": shipping.toFixed(2), children: shipping === 0 ? "Gr\xE1tis" : money(shipping) })
|
|
8681
9235
|
] }),
|
|
8682
9236
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between border-t pt-5 text-lg font-bold", children: [
|
|
@@ -9133,45 +9687,11 @@ function OrderConfirmationPage({ orderId }) {
|
|
|
9133
9687
|
}
|
|
9134
9688
|
);
|
|
9135
9689
|
}
|
|
9136
|
-
function useMyOrders() {
|
|
9137
|
-
const customerId = useSessionStore((s2) => s2.customerId);
|
|
9138
|
-
const email = useSessionStore((s2) => s2.email);
|
|
9139
|
-
const [orders, setOrders] = useState([]);
|
|
9140
|
-
const [loading, setLoading] = useState(true);
|
|
9141
|
-
const [tick, setTick] = useState(0);
|
|
9142
|
-
const refresh = useCallback(() => setTick((t) => t + 1), []);
|
|
9143
|
-
useEffect(() => {
|
|
9144
|
-
let cancelled = false;
|
|
9145
|
-
const local = listLocalOrderIds();
|
|
9146
|
-
if (!customerId && !email) {
|
|
9147
|
-
if (local.length === 0) {
|
|
9148
|
-
setOrders([]);
|
|
9149
|
-
setLoading(false);
|
|
9150
|
-
return;
|
|
9151
|
-
}
|
|
9152
|
-
}
|
|
9153
|
-
setLoading(true);
|
|
9154
|
-
const query = customerId ? { customerId, limit: 50 } : { customerEmail: email, limit: 50 };
|
|
9155
|
-
getShopProvider().listOrders(query).then((data) => {
|
|
9156
|
-
if (!cancelled) setOrders(data);
|
|
9157
|
-
}).catch(async () => {
|
|
9158
|
-
const mine = await Promise.all(
|
|
9159
|
-
listLocalOrderIds().map((id) => getShopProvider().getOrder(id).catch(() => null))
|
|
9160
|
-
);
|
|
9161
|
-
if (!cancelled) setOrders(mine.filter((o) => !!o));
|
|
9162
|
-
}).finally(() => {
|
|
9163
|
-
if (!cancelled) setLoading(false);
|
|
9164
|
-
});
|
|
9165
|
-
return () => {
|
|
9166
|
-
cancelled = true;
|
|
9167
|
-
};
|
|
9168
|
-
}, [customerId, email, tick]);
|
|
9169
|
-
return { orders, loading, refresh };
|
|
9170
|
-
}
|
|
9171
9690
|
function AuthForm() {
|
|
9172
9691
|
const [mode, setMode] = useState("signin");
|
|
9173
9692
|
const [email, setEmail] = useState("");
|
|
9174
9693
|
const [password, setPassword] = useState("");
|
|
9694
|
+
const [confirmPassword, setConfirmPassword] = useState("");
|
|
9175
9695
|
const [name, setName] = useState("");
|
|
9176
9696
|
const [busy, setBusy] = useState(false);
|
|
9177
9697
|
const [error, setError] = useState(null);
|
|
@@ -9185,6 +9705,10 @@ function AuthForm() {
|
|
|
9185
9705
|
setError("Informe seu nome.");
|
|
9186
9706
|
return;
|
|
9187
9707
|
}
|
|
9708
|
+
if (mode === "signup" && password !== confirmPassword) {
|
|
9709
|
+
setError("As senhas n\xE3o s\xE3o iguais.");
|
|
9710
|
+
return;
|
|
9711
|
+
}
|
|
9188
9712
|
setBusy(true);
|
|
9189
9713
|
try {
|
|
9190
9714
|
if (mode === "signup") await signUpCustomer(email, password, name.trim());
|
|
@@ -9260,6 +9784,20 @@ function AuthForm() {
|
|
|
9260
9784
|
style: { borderRadius: "var(--sf-radius-input)" }
|
|
9261
9785
|
}
|
|
9262
9786
|
),
|
|
9787
|
+
mode === "signup" && /* @__PURE__ */ jsx(
|
|
9788
|
+
"input",
|
|
9789
|
+
{
|
|
9790
|
+
"data-testid": TID.signinPasswordConfirm,
|
|
9791
|
+
type: "password",
|
|
9792
|
+
required: true,
|
|
9793
|
+
placeholder: "Confirmar senha",
|
|
9794
|
+
value: confirmPassword,
|
|
9795
|
+
onChange: (e) => setConfirmPassword(e.target.value),
|
|
9796
|
+
"aria-invalid": confirmPassword.length > 0 && password !== confirmPassword,
|
|
9797
|
+
className: "w-full border bg-background px-3 py-2.5 text-sm",
|
|
9798
|
+
style: { borderRadius: "var(--sf-radius-input)" }
|
|
9799
|
+
}
|
|
9800
|
+
),
|
|
9263
9801
|
notice && /* @__PURE__ */ jsx("p", { "data-testid": TID.authNotice, className: "text-sm font-medium text-emerald-700", children: notice }),
|
|
9264
9802
|
error && /* @__PURE__ */ jsx("p", { "data-testid": TID.authError, className: "text-sm text-destructive", children: error }),
|
|
9265
9803
|
/* @__PURE__ */ jsx(
|
|
@@ -11123,5 +11661,5 @@ ${formatErrors(report.errors)}`;
|
|
|
11123
11661
|
}
|
|
11124
11662
|
|
|
11125
11663
|
export { BEFORE_PLACE_ORDER_VALVE, BLOCK_STRUCTURAL_KEYS, BenefitsRow, BlockDataError, CART_LINE_ANNOTATION_POINT, CATALOG_BODY_BLOCK, CHECKOUT_FIELD_POINT, CartDrawer, CatalogPage, CategoryShowcase, CheckoutPage, CollectionCta, CollectionHero, ContentPage, CountdownBand, EmailConfirmationRequiredError, EntityListBlock, FaqSection, FiltersPanel, FormBlock, HeroSection, ImageTiles, Link, ManifestoBlock, MediaCarousel, MotifStrip, MyPurchasesPage, NewsletterBand, ORDER_METADATA_POINT, OrderConfirmationPage, OrderTrackingTimeline, PAGE_DATA_SCRIPT_ID, PLACEHOLDER_ASPECTS, PRODUCT_BODY_BLOCK, PRODUCT_CARD_BADGE_POINT, PageDataScope, PaymentTerms, Price, ProductCard, ProductDetailPage, ProductEnquiryForm, ProductGallery, ProductGrid, ProductOptionSelector, ProductRail, ProductReviews, ProductSlider, ProductSpecs, ProductSpotlight, PromoBanner, QuantityInput, Reveal, STOREFRONT_COMPONENT_KEYS, STOREFRONT_PAGE_KINDS, STOREFRONT_SLOTS, STORE_BACKEND_PROVIDERS, STORE_COMMERCE_MODES, STORE_DOCUMENT_KIND, STORE_PAYMENT_METHOD_KINDS, STORE_PAYMENT_MODES, STORE_ROUTE_CHROMES, STORE_ROUTE_KINDS, STORE_SECTIONS, STORE_SECTION_NAMES, SealsBand, SearchOverlay, Slot, SmoothImage, StepsSection, StorefrontConfigHost, StorefrontConfigProvider, StorefrontFooter, StorefrontHeader, StorefrontPage, StorefrontRouterProvider, StorefrontShell, StorefrontThemeStyle, StoryQuote, THEME_SCALE_FIELDS, THEME_SCALE_VAR_PREFIX, TID, Testimonials, TierCards, applyStoreSettings, bannerPlaceholder, blockInstanceId, buildEnquiryFromForm, checkPageBlocks, collectDataNeeds, collectOrderMetadata, contentPagePath, createStorefront, createStorefrontApp, currentStaticRenderPass, defaultPageBlocks, entityListBlockMeta, establishCustomerSession, exportStore, formatMoney, formatProductOptionSelection, getCartLineAnnotations, getCheckoutFieldContributions, getCustomerAuthAdapter, getProductCardBadges, getProductOptionGroups, hydrateStoreDocument, hydratedEntriesFor, initStorefrontRuntime, isJsonValue, isKnownPath, isNestedBlockRef, isPublicPath, isRecord, listSlots, matchContentPage, matchPath, matchesFacets, mergeCollectionFacet, mergePageTheme, navigateTo, nextMilestone, normalizeProductOptionSelection, orderGalleryImages, overrideComponent, overrideProps, pageSeo, pageThemeSelector, pickProductCardImage, placeStorefrontOrder, prefersReducedMotion, primaryImageUrl, productCardComponentContract, productJsonLd, productOptionSelectionKey, productPlaceholder, productSeo, readHydratedPageData, registerStorefrontBlocks, registerStorefrontEntities, registerStorefrontExtensionPoints, registerStorefrontLoaders, resetPageDiagnostics, resetProductOptionsDeprecationWarnings, resetStorefrontExtensionPoints, resolveAuthAdapter, resolveConfig, resolveDataParams, resolveOverride, resolvePageData, resolvePageDataNeed, resolvePaymentTerms, resolveStorefrontProvider, resolveStorefrontRoute, resolveVariantForSelection, roundCents, routePathParams, runBeforePlaceOrderValve, sectionToJsonSchema, sectionsToBlocks, selectCount, selectDiscountTotal, selectRequiresShipping, selectShipping, selectSubtotal, selectTotal, selectionPrice, serializePageData, shellRouterAdapter, signInByEmail, signOutCustomer, signUpCustomer, slugifyStoreName, storefrontComponentContracts, storefrontPaths, themeToCss, toBlockNodes, toFacetMap, useBlockData, useCartStore, useCatalogStore, useCategories, useDeliveryStore, useDiscountValidator, useEnquiry, useHashPath, useInView, useLoader, useMyOrders, useNavigate, usePopOnChange, useProduct, useProducts, useRoutePath, useRouterAdapter, useScrollToTopOnNavigate, useScrolled, useSessionStore, useSlotContext, useStorefrontActions, useStorefrontConfig, useStorefrontConfigOptional, useStorefrontHead, useStorefrontPage, useStorefrontPageOptional, usedSlots, validateStore, withFacet, withStaticRenderPass };
|
|
11126
|
-
//# sourceMappingURL=chunk-
|
|
11127
|
-
//# sourceMappingURL=chunk-
|
|
11664
|
+
//# sourceMappingURL=chunk-STL6MATQ.js.map
|
|
11665
|
+
//# sourceMappingURL=chunk-STL6MATQ.js.map
|