@fayz-ai/storefront 0.79.1 → 0.81.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/app/prerender.d.ts +1 -9
- package/dist/app/prerender.d.ts.map +1 -1
- package/dist/app/serving.d.ts.map +1 -1
- package/dist/app/sitemap.d.ts +10 -0
- package/dist/app/sitemap.d.ts.map +1 -0
- package/dist/chunk-2KCORAVB.js +1183 -0
- package/dist/chunk-2KCORAVB.js.map +1 -0
- package/dist/{chunk-6H5VD6OB.js → chunk-CWHGBPRP.js} +165 -2558
- package/dist/chunk-CWHGBPRP.js.map +1 -0
- package/dist/chunk-OIPNINZQ.js +1336 -0
- package/dist/chunk-OIPNINZQ.js.map +1 -0
- package/dist/chunk-WCAQRATH.js +30 -0
- package/dist/chunk-WCAQRATH.js.map +1 -0
- package/dist/data/menu-needs.d.ts +30 -0
- package/dist/data/menu-needs.d.ts.map +1 -0
- package/dist/edge.d.ts +1 -0
- package/dist/edge.d.ts.map +1 -1
- package/dist/edge.js +80 -1
- package/dist/edge.js.map +1 -1
- package/dist/host/edge-handler.d.ts +38 -0
- package/dist/host/edge-handler.d.ts.map +1 -0
- package/dist/host/image-origin.d.ts +16 -0
- package/dist/host/image-origin.d.ts.map +1 -0
- package/dist/host/store-host.d.ts +131 -0
- package/dist/host/store-host.d.ts.map +1 -0
- package/dist/host.d.ts +7 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +223 -0
- package/dist/host.js.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/seo.d.ts +57 -1
- package/dist/lib/seo.d.ts.map +1 -1
- package/dist/render.js +6 -27
- package/dist/render.js.map +1 -1
- package/dist/tanstack.d.ts +35 -0
- package/dist/tanstack.d.ts.map +1 -0
- package/dist/tanstack.js +115 -0
- package/dist/tanstack.js.map +1 -0
- package/dist/views/MenuPage.d.ts +1 -0
- package/dist/views/MenuPage.d.ts.map +1 -1
- package/package.json +19 -4
- package/dist/chunk-6H5VD6OB.js.map +0 -1
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { Link, useStorefrontConfigOptional, useStorefrontConfig, useBlockData, BlockDataError, navigateTo, useRoutePath, toBlockNodes, defaultPageBlocks, PageDataScope, getStorefrontComponents, useLoader, currentStaticRenderPass, matchPath, translate, productSeo, StorefrontConfigProvider, mergePageTheme, pageThemeSelector, MENU_DATA_NEEDS, resolveConfig, useRouterAdapter, shellRouterAdapter, StorefrontRouterProvider, useScrollToTopOnNavigate, checkPageBlocks, normalizeLanguage, useHashPath, resolveStorefrontRoute, matchContentPage } from './chunk-2KCORAVB.js';
|
|
1
2
|
import { create } from 'zustand';
|
|
2
3
|
import { persist } from 'zustand/middleware';
|
|
3
|
-
import { normalizePostalCode, getCountrySchema, lookupPostalCode,
|
|
4
|
+
import { normalizePostalCode, getCountrySchema, lookupPostalCode, defineLoader, repairBlockTree, renderBlocks, clearExtensionPoints, defineExtensionPoint, runExtensionPoint, runEscapeValve, errorMessage, hasEntityDeclaration, resolveEntityDeclaration, defineBlock, formatPostalCode, countryName, defineEntity, defaultRouterAdapter, describeError, validateAddress } from '@fayz-ai/core';
|
|
4
5
|
import { getShopProvider, setShopProvider } from '@fayz-ai/shop/runtime';
|
|
5
|
-
import * as
|
|
6
|
-
import
|
|
6
|
+
import * as React36 from 'react';
|
|
7
|
+
import React36__default, { createContext, useRef, useState, useEffect, useMemo, useContext, useCallback } from 'react';
|
|
7
8
|
import { createMockAuthAdapter } from '@fayz-ai/auth';
|
|
8
9
|
import { createAuthRuntime } from '@fayz-ai/auth/lib/runtime';
|
|
9
10
|
import { setShopCarrierQuotesResolver, setShopAccessTokenResolver, setShopShippingItemsResolver } from '@fayz-ai/sdk/shop';
|
|
@@ -11,16 +12,15 @@ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
|
11
12
|
import { isStorageImageUrl, imageVariantUrl, imageSrcSet, IMAGE_SRCSET_WIDTHS, validateDiscount, documentDigits, isChargeableProvider, supportsCard, formatDocument, isValidDocument, gatewayLabel, isValidCpf } from '@fayz-ai/shop';
|
|
12
13
|
import { ChevronLeft, ChevronRight, ShoppingBag, X, Minus, Plus, Send, MessageCircle, Mail, Truck, RefreshCcw, ShieldCheck, ChevronDown, Check, Search, Menu, Trash2, MapPin, Lock, CreditCard, UserRound, Store, Bike, Clock, Pencil, Star, Phone, User, UserCircle, Package, LogOut, QrCode, Copy, XCircle, RotateCcw, PackageCheck, ChefHat, Info, AlertCircle } from 'lucide-react';
|
|
13
14
|
import { getLucideIcon } from '@fayz-ai/ui/icons';
|
|
14
|
-
import { storefrontDiscountToPromotion, previewCouponPercent, discountToPromotion
|
|
15
|
+
import { storefrontDiscountToPromotion, previewCouponPercent, discountToPromotion } from '@fayz-ai/shop/rules';
|
|
15
16
|
import { createMockShopProvider } from '@fayz-ai/shop/mock';
|
|
16
17
|
|
|
17
|
-
// src/stores/market.store.ts
|
|
18
18
|
var useMarketStore = create()((set) => ({
|
|
19
19
|
markets: [],
|
|
20
20
|
active: null,
|
|
21
21
|
prices: {},
|
|
22
22
|
setMarkets: (markets) => set({ markets }),
|
|
23
|
-
setActive: (
|
|
23
|
+
setActive: (active) => set({ active }),
|
|
24
24
|
setPrices: (code, list) => set((state) => ({
|
|
25
25
|
prices: {
|
|
26
26
|
...state.prices,
|
|
@@ -698,19 +698,19 @@ function StorefrontAnalytics({ config, path }) {
|
|
|
698
698
|
const metaPixel = pixelId && META_PIXEL_ID.test(pixelId) ? pixelId : null;
|
|
699
699
|
const reporting = Boolean(posthog || metaPixel);
|
|
700
700
|
const menuPath = config.delivery?.menuPath;
|
|
701
|
-
const previous =
|
|
702
|
-
|
|
701
|
+
const previous = React36.useRef(null);
|
|
702
|
+
React36.useEffect(() => {
|
|
703
703
|
if (!posthog) return;
|
|
704
704
|
startStorefrontPostHog(posthog, { storeName: config.name, commerceMode: config.commerceMode });
|
|
705
705
|
}, [posthog, config.name, config.commerceMode]);
|
|
706
|
-
|
|
706
|
+
React36.useEffect(() => {
|
|
707
707
|
if (!metaPixel) return;
|
|
708
708
|
startStorefrontMetaPixel({ pixelId: metaPixel }, { currency: config.currency ?? "BRL" });
|
|
709
709
|
}, [metaPixel, config.currency]);
|
|
710
|
-
|
|
710
|
+
React36.useEffect(() => {
|
|
711
711
|
if (metaPixel) trackMetaPageView();
|
|
712
712
|
}, [metaPixel, path]);
|
|
713
|
-
|
|
713
|
+
React36.useEffect(() => {
|
|
714
714
|
if (!reporting) return;
|
|
715
715
|
let ready = useCartStore.persist?.hasHydrated?.() ?? true;
|
|
716
716
|
const unhydrated = useCartStore.persist?.onFinishHydration?.(() => {
|
|
@@ -741,7 +741,7 @@ function StorefrontAnalytics({ config, path }) {
|
|
|
741
741
|
unhydrated?.();
|
|
742
742
|
};
|
|
743
743
|
}, [reporting]);
|
|
744
|
-
|
|
744
|
+
React36.useEffect(() => {
|
|
745
745
|
if (!reporting) return;
|
|
746
746
|
const from = previous.current;
|
|
747
747
|
previous.current = path;
|
|
@@ -1230,543 +1230,6 @@ function productPlaceholder(label, w = PLACEHOLDER_ASPECTS.product[0], h = PLACE
|
|
|
1230
1230
|
function escapeXml(text) {
|
|
1231
1231
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1232
1232
|
}
|
|
1233
|
-
|
|
1234
|
-
// src/locales/messages.ts
|
|
1235
|
-
var ptBR = {
|
|
1236
|
-
// Checkout shell
|
|
1237
|
-
"checkout.title": "Checkout \u2014 {{store}}",
|
|
1238
|
-
"checkout.backToStore": "Voltar \xE0 loja",
|
|
1239
|
-
"checkout.secure": "Checkout seguro",
|
|
1240
|
-
"checkout.help": "Ajuda",
|
|
1241
|
-
"checkout.steps.label": "Etapas do checkout",
|
|
1242
|
-
"checkout.steps.1": "Dados",
|
|
1243
|
-
"checkout.steps.2": "Entrega",
|
|
1244
|
-
"checkout.steps.3": "Pagamento",
|
|
1245
|
-
"checkout.steps.4": "Pronto",
|
|
1246
|
-
// Step 1 — contact
|
|
1247
|
-
"checkout.contact.title": "Informa\xE7\xF5es de contato",
|
|
1248
|
-
"checkout.contact.signedInAs": "Conectado como {{email}}",
|
|
1249
|
-
"checkout.contact.edit": "Alterar",
|
|
1250
|
-
"checkout.contact.notYou": "N\xE3o \xE9 voc\xEA?",
|
|
1251
|
-
"checkout.contact.signOut": "Sair",
|
|
1252
|
-
"checkout.contact.emailLocked": "O e-mail \xE9 o da sua conta.",
|
|
1253
|
-
"checkout.contact.haveAccount": "J\xE1 tem conta? Entrar",
|
|
1254
|
-
"checkout.contact.email": "E-mail",
|
|
1255
|
-
"checkout.contact.name": "Nome completo",
|
|
1256
|
-
"checkout.contact.phone": "Telefone",
|
|
1257
|
-
"checkout.contact.phoneOptional": "Telefone (opcional)",
|
|
1258
|
-
"checkout.contact.document": "CPF ou CNPJ",
|
|
1259
|
-
"checkout.contact.documentOptional": "CPF ou CNPJ (opcional)",
|
|
1260
|
-
"checkout.contact.requiresAccount": "Esta loja pede uma conta para finalizar a compra.",
|
|
1261
|
-
"checkout.contact.signInOrCreate": "Entrar ou criar conta",
|
|
1262
|
-
// Step 2 — address
|
|
1263
|
-
"checkout.address.title": "Endere\xE7o de entrega",
|
|
1264
|
-
"checkout.address.loadingSaved": "Buscando seus endere\xE7os salvos",
|
|
1265
|
-
"checkout.address.selected": "Selecionado",
|
|
1266
|
-
"checkout.address.addNew": "+ Adicionar novo endere\xE7o",
|
|
1267
|
-
"checkout.address.enter": "Informe o endere\xE7o de entrega",
|
|
1268
|
-
"checkout.address.enterHint": "Preencher outro endere\xE7o para esta compra",
|
|
1269
|
-
"checkout.address.lookingUp": "Buscando o endere\xE7o deste CEP",
|
|
1270
|
-
"checkout.address.notFound": "CEP n\xE3o encontrado \u2014 preencha o endere\xE7o \xE0 m\xE3o.",
|
|
1271
|
-
"checkout.address.filled": "Preenchemos o endere\xE7o para voc\xEA.",
|
|
1272
|
-
"checkout.address.regionFromPostal": "Prov\xEDncia preenchida pelo c\xF3digo postal.",
|
|
1273
|
-
"checkout.address.optional": "{{label}} (opcional)",
|
|
1274
|
-
"checkout.address.choose": "Selecione",
|
|
1275
|
-
"checkout.address.shipTo": "Enviar para",
|
|
1276
|
-
// Step 3 — payment
|
|
1277
|
-
"checkout.confirming.title": "Confirmando seu pedido",
|
|
1278
|
-
"checkout.confirming.label": "Criando seu pedido",
|
|
1279
|
-
"checkout.confirming.keepOpen": "N\xE3o feche esta p\xE1gina \u2014 estamos registrando seu pedido na loja.",
|
|
1280
|
-
"checkout.payment.title": "Pagamento",
|
|
1281
|
-
"checkout.payment.label": "Forma de pagamento",
|
|
1282
|
-
"checkout.payment.cardOnline": "Voc\xEA paga na p\xE1gina segura do provedor e volta para a loja",
|
|
1283
|
-
"checkout.payment.placeOrder": "Fazer pedido - {{total}}",
|
|
1284
|
-
"checkout.payment.pendingNote": "O pedido fica aguardando pagamento at\xE9 a loja confirmar.",
|
|
1285
|
-
"checkout.payment.unavailableCountry": "Esta forma de pagamento n\xE3o est\xE1 dispon\xEDvel para {{country}}.",
|
|
1286
|
-
"payment.pix.label": "Pix",
|
|
1287
|
-
"payment.pix.hint": "Voc\xEA recebe a chave para pagar ap\xF3s confirmar o pedido",
|
|
1288
|
-
"payment.credit_card.label": "Cart\xE3o de cr\xE9dito",
|
|
1289
|
-
"payment.credit_card.hint": "Maquininha na entrega",
|
|
1290
|
-
"payment.debit_card.label": "Cart\xE3o de d\xE9bito",
|
|
1291
|
-
"payment.debit_card.hint": "Maquininha na entrega",
|
|
1292
|
-
"payment.boleto.label": "Boleto",
|
|
1293
|
-
"payment.boleto.hint": "Enviado por e-mail ap\xF3s a confirma\xE7\xE3o",
|
|
1294
|
-
"payment.cash.label": "Dinheiro",
|
|
1295
|
-
"payment.cash.hint": "Pagamento na entrega",
|
|
1296
|
-
"payment.other.label": "Combinar com a loja",
|
|
1297
|
-
"payment.other.hint": "A loja entra em contato para acertar o pagamento",
|
|
1298
|
-
// Step 4
|
|
1299
|
-
"checkout.done.title": "Pagamento confirmado!",
|
|
1300
|
-
"checkout.done.text": "Seu pedido foi criado e a loja j\xE1 foi avisada.",
|
|
1301
|
-
"checkout.done.viewOrder": "Ver meu pedido",
|
|
1302
|
-
// Navigation
|
|
1303
|
-
"checkout.continueToDelivery": "Continuar para a entrega",
|
|
1304
|
-
"checkout.goToPayment": "Ir para o pagamento - {{total}}",
|
|
1305
|
-
"checkout.backToContact": "Voltar aos dados",
|
|
1306
|
-
"checkout.backToCart": "Voltar ao carrinho",
|
|
1307
|
-
// Summary
|
|
1308
|
-
"summary.title": "Resumo do pedido",
|
|
1309
|
-
"summary.subtotal": "Subtotal",
|
|
1310
|
-
"summary.discount": "Desconto",
|
|
1311
|
-
"summary.delivery": "Entrega",
|
|
1312
|
-
"summary.pickup": "Retirada na loja",
|
|
1313
|
-
"summary.noFee": "Sem taxa",
|
|
1314
|
-
"summary.free": "Gr\xE1tis",
|
|
1315
|
-
"summary.total": "Total",
|
|
1316
|
-
"summary.protected": "Compra protegida e dados criptografados.",
|
|
1317
|
-
"summary.shipping": "Frete",
|
|
1318
|
-
// Discount
|
|
1319
|
-
"discount.placeholder": "Cupom de desconto",
|
|
1320
|
-
"discount.apply": "Aplicar",
|
|
1321
|
-
"discount.freeShipping": "frete gr\xE1tis",
|
|
1322
|
-
"discount.percentOff": "{{percent}}% de desconto",
|
|
1323
|
-
"discount.applied": "{{code}} aplicado: {{effect}}.",
|
|
1324
|
-
"discount.appliedToast": "Cupom aplicado!",
|
|
1325
|
-
"discount.invalid": "Cupom inv\xE1lido.",
|
|
1326
|
-
"discount.invalidToast": "Cupom inv\xE1lido",
|
|
1327
|
-
"discount.checkCode": "Verifique o c\xF3digo e tente novamente.",
|
|
1328
|
-
"discount.cannotValidate": "N\xE3o conseguimos validar esse cupom agora.",
|
|
1329
|
-
"discount.cannotValidateToast": "N\xE3o conseguimos validar o cupom",
|
|
1330
|
-
"discount.tryLater": "Tente de novo em alguns instantes.",
|
|
1331
|
-
// Legal
|
|
1332
|
-
"legal.privacy": "Privacidade",
|
|
1333
|
-
"legal.terms": "Termos",
|
|
1334
|
-
"legal.refunds": "Trocas e devolu\xE7\xF5es",
|
|
1335
|
-
// Validation
|
|
1336
|
-
"error.requiresAccount": "Esta loja pede uma conta para finalizar a compra. Entre ou crie a sua.",
|
|
1337
|
-
"error.email": "Informe um e-mail v\xE1lido.",
|
|
1338
|
-
"error.name": "Informe seu nome completo.",
|
|
1339
|
-
"error.phone": "Informe um telefone de contato.",
|
|
1340
|
-
"error.documentInvalid": "CPF ou CNPJ inv\xE1lido \u2014 confira os n\xFAmeros.",
|
|
1341
|
-
"error.documentMissing": "Informe o CPF ou CNPJ do comprador.",
|
|
1342
|
-
"error.taxIdInvalid": "NIF/NIE inv\xE1lido \u2014 confira o n\xFAmero.",
|
|
1343
|
-
"error.address": "Preencha ou selecione o endere\xE7o de entrega.",
|
|
1344
|
-
"error.number": "Falta o n\xFAmero do endere\xE7o.",
|
|
1345
|
-
"error.complement": "Informe o complemento (apto, bloco).",
|
|
1346
|
-
"error.state": "Informe a UF com duas letras (ex.: RJ).",
|
|
1347
|
-
"error.postalInvalid": "Confira o c\xF3digo postal (ex.: {{example}}).",
|
|
1348
|
-
"error.region": "Selecione a {{label}}.",
|
|
1349
|
-
"error.refusedZone": "Esta loja n\xE3o entrega nesse endere\xE7o. Tente outro.",
|
|
1350
|
-
"error.unserved": "Ainda n\xE3o entregamos nesse CEP. Tente outro endere\xE7o.",
|
|
1351
|
-
"error.sessionMismatch": "Sua sess\xE3o ficou presa a outro cadastro. Recarregue a p\xE1gina e tente de novo.",
|
|
1352
|
-
"error.outOfStock": "Um item do carrinho ficou sem estoque. Revise o carrinho e tente de novo.",
|
|
1353
|
-
"error.placeOrder": "N\xE3o foi poss\xEDvel concluir o pedido.",
|
|
1354
|
-
// Delivery estimator
|
|
1355
|
-
"delivery.title": "Calcular entrega",
|
|
1356
|
-
"delivery.calculate": "Calcular",
|
|
1357
|
-
"delivery.postalLabel": "CEP",
|
|
1358
|
-
"delivery.change": "Trocar CEP",
|
|
1359
|
-
"delivery.unserved": "Ainda n\xE3o entregamos nesse CEP.",
|
|
1360
|
-
"delivery.refused": "Esta loja n\xE3o entrega nesse endere\xE7o.",
|
|
1361
|
-
"delivery.review": "Entregamos nessa regi\xE3o, mas confirmamos com voc\xEA antes de sair.",
|
|
1362
|
-
"delivery.etaSoon": "hoje ou amanh\xE3",
|
|
1363
|
-
"delivery.etaRange": "{{min}} a {{max}} dias \xFAteis",
|
|
1364
|
-
"delivery.etaDays": "{{days}} dia(s) \xFAtil(eis)",
|
|
1365
|
-
"delivery.flatRate": "O frete \xE9 calculado no checkout.",
|
|
1366
|
-
"delivery.error.digits": "Digite os 8 d\xEDgitos do CEP.",
|
|
1367
|
-
"delivery.error.postal": "Confira o c\xF3digo postal (ex.: {{example}}).",
|
|
1368
|
-
"delivery.error.quote": "N\xE3o foi poss\xEDvel calcular o frete agora. Tente de novo.",
|
|
1369
|
-
"delivery.error.notFound": "CEP n\xE3o encontrado. Confira os n\xFAmeros.",
|
|
1370
|
-
// Cart
|
|
1371
|
-
"cart.title": "Carrinho",
|
|
1372
|
-
"cart.close": "Fechar carrinho",
|
|
1373
|
-
"cart.empty": "Seu carrinho est\xE1 vazio.",
|
|
1374
|
-
"cart.remove": "Remover {{name}}",
|
|
1375
|
-
"cart.checkout": "Finalizar compra",
|
|
1376
|
-
"cart.missingForFree": "Faltam {{amount}} para frete gr\xE1tis",
|
|
1377
|
-
"cart.wonFree": "Voc\xEA ganhou frete gr\xE1tis!",
|
|
1378
|
-
"cart.minimumOrder": "Pedido m\xEDnimo para entrega: {{amount}}. Faltam {{missing}}.",
|
|
1379
|
-
"delivery.eta": "Entrega em ~{{duration}}",
|
|
1380
|
-
"delivery.etaUpTo": "Entrega em at\xE9 {{duration}}",
|
|
1381
|
-
"delivery.paused": "Delivery fechado no momento",
|
|
1382
|
-
"cart.deliveryPaused": "O delivery est\xE1 fechado no momento. Volte mais tarde para finalizar.",
|
|
1383
|
-
// Deliver to
|
|
1384
|
-
"country.deliverTo": "Enviar para",
|
|
1385
|
-
"country.change": "Trocar pa\xEDs",
|
|
1386
|
-
"country.label": "Pa\xEDs de entrega"
|
|
1387
|
-
};
|
|
1388
|
-
var en = {
|
|
1389
|
-
"checkout.backToStore": "Back to store",
|
|
1390
|
-
"checkout.secure": "Secure checkout",
|
|
1391
|
-
"checkout.help": "Help",
|
|
1392
|
-
"checkout.steps.label": "Checkout steps",
|
|
1393
|
-
"checkout.steps.1": "Details",
|
|
1394
|
-
"checkout.steps.2": "Delivery",
|
|
1395
|
-
"checkout.steps.3": "Payment",
|
|
1396
|
-
"checkout.steps.4": "Done",
|
|
1397
|
-
"checkout.contact.title": "Contact information",
|
|
1398
|
-
"checkout.contact.signedInAs": "Signed in as {{email}}",
|
|
1399
|
-
"checkout.contact.edit": "Change",
|
|
1400
|
-
"checkout.contact.notYou": "Not you?",
|
|
1401
|
-
"checkout.contact.signOut": "Sign out",
|
|
1402
|
-
"checkout.contact.emailLocked": "This is your account e-mail.",
|
|
1403
|
-
"checkout.contact.haveAccount": "Have an account? Sign in",
|
|
1404
|
-
"checkout.contact.email": "Email",
|
|
1405
|
-
"checkout.contact.name": "Full name",
|
|
1406
|
-
"checkout.contact.phone": "Phone",
|
|
1407
|
-
"checkout.contact.phoneOptional": "Phone (optional)",
|
|
1408
|
-
"checkout.contact.document": "Tax ID",
|
|
1409
|
-
"checkout.contact.documentOptional": "Tax ID (optional)",
|
|
1410
|
-
"checkout.contact.requiresAccount": "This store needs an account to complete the purchase.",
|
|
1411
|
-
"checkout.contact.signInOrCreate": "Sign in or create an account",
|
|
1412
|
-
"checkout.address.title": "Delivery address",
|
|
1413
|
-
"checkout.address.loadingSaved": "Loading your saved addresses",
|
|
1414
|
-
"checkout.address.selected": "Selected",
|
|
1415
|
-
"checkout.address.addNew": "+ Add a new address",
|
|
1416
|
-
"checkout.address.enter": "Enter the delivery address",
|
|
1417
|
-
"checkout.address.enterHint": "Use a different address for this order",
|
|
1418
|
-
"checkout.address.lookingUp": "Looking up this postal code",
|
|
1419
|
-
"checkout.address.notFound": "Postal code not found \u2014 fill in the address by hand.",
|
|
1420
|
-
"checkout.address.filled": "We filled in the address for you.",
|
|
1421
|
-
"checkout.address.regionFromPostal": "Province filled in from the postcode.",
|
|
1422
|
-
"checkout.address.optional": "{{label}} (optional)",
|
|
1423
|
-
"checkout.address.choose": "Select",
|
|
1424
|
-
"checkout.address.shipTo": "Ship to",
|
|
1425
|
-
"checkout.confirming.title": "Confirming your order",
|
|
1426
|
-
"checkout.confirming.label": "Creating your order",
|
|
1427
|
-
"checkout.confirming.keepOpen": "Don\u2019t close this page \u2014 we\u2019re registering your order with the store.",
|
|
1428
|
-
"checkout.payment.title": "Payment",
|
|
1429
|
-
"checkout.payment.label": "Payment method",
|
|
1430
|
-
"checkout.payment.cardOnline": "You pay on the provider\u2019s secure page and come back to the store",
|
|
1431
|
-
"checkout.payment.placeOrder": "Place order - {{total}}",
|
|
1432
|
-
"checkout.payment.pendingNote": "The order awaits payment until the store confirms it.",
|
|
1433
|
-
"checkout.payment.unavailableCountry": "This payment method isn\u2019t available for {{country}}.",
|
|
1434
|
-
"payment.pix.hint": "You get the key to pay after confirming the order",
|
|
1435
|
-
"payment.credit_card.label": "Credit card",
|
|
1436
|
-
"payment.credit_card.hint": "Card machine on delivery",
|
|
1437
|
-
"payment.debit_card.label": "Debit card",
|
|
1438
|
-
"payment.debit_card.hint": "Card machine on delivery",
|
|
1439
|
-
"payment.boleto.hint": "Sent by email after confirmation",
|
|
1440
|
-
"payment.cash.label": "Cash",
|
|
1441
|
-
"payment.cash.hint": "Pay on delivery",
|
|
1442
|
-
"payment.other.label": "Arrange with the store",
|
|
1443
|
-
"payment.other.hint": "The store will contact you to arrange payment",
|
|
1444
|
-
"checkout.done.title": "Payment confirmed!",
|
|
1445
|
-
"checkout.done.text": "Your order was created and the store has been notified.",
|
|
1446
|
-
"checkout.done.viewOrder": "View my order",
|
|
1447
|
-
"checkout.continueToDelivery": "Continue to delivery",
|
|
1448
|
-
"checkout.goToPayment": "Go to payment - {{total}}",
|
|
1449
|
-
"checkout.backToContact": "Back to details",
|
|
1450
|
-
"checkout.backToCart": "Back to cart",
|
|
1451
|
-
"summary.title": "Order summary",
|
|
1452
|
-
"summary.discount": "Discount",
|
|
1453
|
-
"summary.delivery": "Delivery",
|
|
1454
|
-
"summary.pickup": "Store pickup",
|
|
1455
|
-
"summary.noFee": "No fee",
|
|
1456
|
-
"summary.free": "Free",
|
|
1457
|
-
"summary.protected": "Protected purchase, encrypted data.",
|
|
1458
|
-
"summary.shipping": "Shipping",
|
|
1459
|
-
"discount.placeholder": "Discount code",
|
|
1460
|
-
"discount.apply": "Apply",
|
|
1461
|
-
"discount.freeShipping": "free shipping",
|
|
1462
|
-
"discount.percentOff": "{{percent}}% off",
|
|
1463
|
-
"discount.applied": "{{code}} applied: {{effect}}.",
|
|
1464
|
-
"discount.appliedToast": "Code applied!",
|
|
1465
|
-
"discount.invalid": "Invalid code.",
|
|
1466
|
-
"discount.invalidToast": "Invalid code",
|
|
1467
|
-
"discount.checkCode": "Check the code and try again.",
|
|
1468
|
-
"discount.cannotValidate": "We couldn\u2019t check this code right now.",
|
|
1469
|
-
"discount.cannotValidateToast": "We couldn\u2019t check the code",
|
|
1470
|
-
"discount.tryLater": "Try again in a moment.",
|
|
1471
|
-
"legal.privacy": "Privacy",
|
|
1472
|
-
"legal.terms": "Terms",
|
|
1473
|
-
"legal.refunds": "Returns",
|
|
1474
|
-
"error.requiresAccount": "This store needs an account to complete the purchase. Sign in or create one.",
|
|
1475
|
-
"error.email": "Enter a valid email.",
|
|
1476
|
-
"error.name": "Enter your full name.",
|
|
1477
|
-
"error.phone": "Enter a contact phone number.",
|
|
1478
|
-
"error.documentInvalid": "Invalid tax ID \u2014 check the numbers.",
|
|
1479
|
-
"error.documentMissing": "Enter the buyer\u2019s tax ID.",
|
|
1480
|
-
"error.taxIdInvalid": "Invalid NIF/NIE \u2014 check the number.",
|
|
1481
|
-
"error.address": "Fill in or select the delivery address.",
|
|
1482
|
-
"error.number": "The street number is missing.",
|
|
1483
|
-
"error.complement": "Enter the apartment or unit.",
|
|
1484
|
-
"error.state": "Enter the two-letter state code (e.g. RJ).",
|
|
1485
|
-
"error.postalInvalid": "Check the postal code (e.g. {{example}}).",
|
|
1486
|
-
"error.region": "Select the {{label}}.",
|
|
1487
|
-
"error.refusedZone": "This store doesn\u2019t deliver to this address. Try another.",
|
|
1488
|
-
"error.unserved": "We don\u2019t deliver to this postal code yet. Try another address.",
|
|
1489
|
-
"error.sessionMismatch": "Your session got attached to another account. Reload the page and try again.",
|
|
1490
|
-
"error.outOfStock": "An item in your cart is out of stock. Review the cart and try again.",
|
|
1491
|
-
"error.placeOrder": "We couldn\u2019t complete the order.",
|
|
1492
|
-
"delivery.title": "Estimate delivery",
|
|
1493
|
-
"delivery.calculate": "Estimate",
|
|
1494
|
-
"delivery.postalLabel": "Postal code",
|
|
1495
|
-
"delivery.change": "Change postal code",
|
|
1496
|
-
"delivery.unserved": "We don\u2019t deliver to this postal code yet.",
|
|
1497
|
-
"delivery.refused": "This store doesn\u2019t deliver to this address.",
|
|
1498
|
-
"delivery.review": "We deliver to this area, but we\u2019ll confirm with you before shipping.",
|
|
1499
|
-
"delivery.etaSoon": "today or tomorrow",
|
|
1500
|
-
"delivery.etaRange": "{{min}} to {{max}} business days",
|
|
1501
|
-
"delivery.etaDays": "{{days}} business day(s)",
|
|
1502
|
-
"delivery.flatRate": "Shipping is calculated at checkout.",
|
|
1503
|
-
"delivery.error.digits": "Enter all 8 digits of the CEP.",
|
|
1504
|
-
"delivery.error.postal": "Check the postal code (e.g. {{example}}).",
|
|
1505
|
-
"delivery.error.quote": "We couldn\u2019t calculate shipping right now. Try again.",
|
|
1506
|
-
"delivery.error.notFound": "Postal code not found. Check the numbers.",
|
|
1507
|
-
"cart.title": "Cart",
|
|
1508
|
-
"cart.close": "Close cart",
|
|
1509
|
-
"cart.empty": "Your cart is empty.",
|
|
1510
|
-
"cart.remove": "Remove {{name}}",
|
|
1511
|
-
"cart.checkout": "Checkout",
|
|
1512
|
-
"cart.missingForFree": "{{amount}} away from free shipping",
|
|
1513
|
-
"cart.wonFree": "You got free shipping!",
|
|
1514
|
-
"cart.minimumOrder": "Minimum order for delivery: {{amount}}. {{missing}} to go.",
|
|
1515
|
-
"delivery.eta": "Delivery in ~{{duration}}",
|
|
1516
|
-
"delivery.etaUpTo": "Delivery within {{duration}}",
|
|
1517
|
-
"delivery.paused": "Delivery closed right now",
|
|
1518
|
-
"cart.deliveryPaused": "Delivery is closed right now. Come back later to check out.",
|
|
1519
|
-
"country.deliverTo": "Deliver to",
|
|
1520
|
-
"country.change": "Change country",
|
|
1521
|
-
"country.label": "Delivery country"
|
|
1522
|
-
};
|
|
1523
|
-
var es = {
|
|
1524
|
-
"checkout.backToStore": "Volver a la tienda",
|
|
1525
|
-
"checkout.secure": "Pago seguro",
|
|
1526
|
-
"checkout.help": "Ayuda",
|
|
1527
|
-
"checkout.steps.label": "Pasos del pago",
|
|
1528
|
-
"checkout.steps.1": "Datos",
|
|
1529
|
-
"checkout.steps.2": "Env\xEDo",
|
|
1530
|
-
"checkout.steps.3": "Pago",
|
|
1531
|
-
"checkout.steps.4": "Listo",
|
|
1532
|
-
"checkout.contact.title": "Datos de contacto",
|
|
1533
|
-
"checkout.contact.signedInAs": "Has iniciado sesi\xF3n como {{email}}",
|
|
1534
|
-
"checkout.contact.edit": "Cambiar",
|
|
1535
|
-
"checkout.contact.notYou": "\xBFNo eres t\xFA?",
|
|
1536
|
-
"checkout.contact.signOut": "Salir",
|
|
1537
|
-
"checkout.contact.emailLocked": "Es el correo de tu cuenta.",
|
|
1538
|
-
"checkout.contact.haveAccount": "\xBFYa tienes cuenta? Entrar",
|
|
1539
|
-
"checkout.contact.email": "Email",
|
|
1540
|
-
"checkout.contact.name": "Nombre completo",
|
|
1541
|
-
"checkout.contact.phone": "Tel\xE9fono",
|
|
1542
|
-
"checkout.contact.phoneOptional": "Tel\xE9fono (opcional)",
|
|
1543
|
-
"checkout.contact.document": "NIF/NIE",
|
|
1544
|
-
"checkout.contact.documentOptional": "NIF/NIE (opcional)",
|
|
1545
|
-
"checkout.contact.requiresAccount": "Esta tienda pide una cuenta para finalizar la compra.",
|
|
1546
|
-
"checkout.contact.signInOrCreate": "Entrar o crear cuenta",
|
|
1547
|
-
"checkout.address.title": "Direcci\xF3n de env\xEDo",
|
|
1548
|
-
"checkout.address.loadingSaved": "Buscando tus direcciones guardadas",
|
|
1549
|
-
"checkout.address.selected": "Seleccionada",
|
|
1550
|
-
"checkout.address.addNew": "+ A\xF1adir una direcci\xF3n nueva",
|
|
1551
|
-
"checkout.address.enter": "Indica la direcci\xF3n de env\xEDo",
|
|
1552
|
-
"checkout.address.enterHint": "Usar otra direcci\xF3n para este pedido",
|
|
1553
|
-
"checkout.address.lookingUp": "Buscando este c\xF3digo postal",
|
|
1554
|
-
"checkout.address.notFound": "C\xF3digo postal no encontrado: rellena la direcci\xF3n a mano.",
|
|
1555
|
-
"checkout.address.filled": "Hemos rellenado la direcci\xF3n por ti.",
|
|
1556
|
-
"checkout.address.regionFromPostal": "Provincia rellenada a partir del c\xF3digo postal.",
|
|
1557
|
-
"checkout.address.optional": "{{label}} (opcional)",
|
|
1558
|
-
"checkout.address.choose": "Selecciona",
|
|
1559
|
-
"checkout.address.shipTo": "Enviar a",
|
|
1560
|
-
"checkout.confirming.title": "Confirmando tu pedido",
|
|
1561
|
-
"checkout.confirming.label": "Creando tu pedido",
|
|
1562
|
-
"checkout.confirming.keepOpen": "No cierres esta p\xE1gina: estamos registrando tu pedido en la tienda.",
|
|
1563
|
-
"checkout.payment.title": "Pago",
|
|
1564
|
-
"checkout.payment.label": "Forma de pago",
|
|
1565
|
-
"checkout.payment.cardOnline": "Pagas en la p\xE1gina segura del proveedor y vuelves a la tienda",
|
|
1566
|
-
"checkout.payment.placeOrder": "Hacer pedido - {{total}}",
|
|
1567
|
-
"checkout.payment.pendingNote": "El pedido queda pendiente de pago hasta que la tienda lo confirme.",
|
|
1568
|
-
"checkout.payment.unavailableCountry": "Esta forma de pago no est\xE1 disponible para {{country}}.",
|
|
1569
|
-
"payment.pix.hint": "Recibes la clave para pagar al confirmar el pedido",
|
|
1570
|
-
"payment.credit_card.label": "Tarjeta de cr\xE9dito",
|
|
1571
|
-
"payment.credit_card.hint": "Dat\xE1fono en la entrega",
|
|
1572
|
-
"payment.debit_card.label": "Tarjeta de d\xE9bito",
|
|
1573
|
-
"payment.debit_card.hint": "Dat\xE1fono en la entrega",
|
|
1574
|
-
"payment.boleto.hint": "Enviado por email tras la confirmaci\xF3n",
|
|
1575
|
-
"payment.cash.label": "Efectivo",
|
|
1576
|
-
"payment.cash.hint": "Pago en la entrega",
|
|
1577
|
-
"payment.other.label": "Acordar con la tienda",
|
|
1578
|
-
"payment.other.hint": "La tienda te contactar\xE1 para acordar el pago",
|
|
1579
|
-
"checkout.done.title": "\xA1Pago confirmado!",
|
|
1580
|
-
"checkout.done.text": "Tu pedido se ha creado y la tienda ya ha sido avisada.",
|
|
1581
|
-
"checkout.done.viewOrder": "Ver mi pedido",
|
|
1582
|
-
"checkout.continueToDelivery": "Continuar al env\xEDo",
|
|
1583
|
-
"checkout.goToPayment": "Ir al pago - {{total}}",
|
|
1584
|
-
"checkout.backToContact": "Volver a los datos",
|
|
1585
|
-
"checkout.backToCart": "Volver al carrito",
|
|
1586
|
-
"summary.title": "Resumen del pedido",
|
|
1587
|
-
"summary.discount": "Descuento",
|
|
1588
|
-
"summary.delivery": "Env\xEDo",
|
|
1589
|
-
"summary.pickup": "Recogida en tienda",
|
|
1590
|
-
"summary.noFee": "Sin coste",
|
|
1591
|
-
"summary.free": "Gratis",
|
|
1592
|
-
"summary.protected": "Compra protegida y datos cifrados.",
|
|
1593
|
-
"summary.shipping": "Env\xEDo",
|
|
1594
|
-
"discount.placeholder": "C\xF3digo de descuento",
|
|
1595
|
-
"discount.apply": "Aplicar",
|
|
1596
|
-
"discount.freeShipping": "env\xEDo gratis",
|
|
1597
|
-
"discount.percentOff": "{{percent}}% de descuento",
|
|
1598
|
-
"discount.applied": "{{code}} aplicado: {{effect}}.",
|
|
1599
|
-
"discount.appliedToast": "\xA1C\xF3digo aplicado!",
|
|
1600
|
-
"discount.invalid": "C\xF3digo no v\xE1lido.",
|
|
1601
|
-
"discount.invalidToast": "C\xF3digo no v\xE1lido",
|
|
1602
|
-
"discount.checkCode": "Revisa el c\xF3digo e int\xE9ntalo de nuevo.",
|
|
1603
|
-
"discount.cannotValidate": "No hemos podido validar este c\xF3digo ahora.",
|
|
1604
|
-
"discount.cannotValidateToast": "No hemos podido validar el c\xF3digo",
|
|
1605
|
-
"discount.tryLater": "Int\xE9ntalo de nuevo en unos instantes.",
|
|
1606
|
-
"legal.privacy": "Privacidad",
|
|
1607
|
-
"legal.terms": "T\xE9rminos",
|
|
1608
|
-
"legal.refunds": "Devoluciones",
|
|
1609
|
-
"error.requiresAccount": "Esta tienda pide una cuenta para finalizar la compra. Entra o crea la tuya.",
|
|
1610
|
-
"error.email": "Indica un email v\xE1lido.",
|
|
1611
|
-
"error.name": "Indica tu nombre completo.",
|
|
1612
|
-
"error.phone": "Indica un tel\xE9fono de contacto.",
|
|
1613
|
-
"error.documentInvalid": "Documento no v\xE1lido: revisa los n\xFAmeros.",
|
|
1614
|
-
"error.documentMissing": "Indica el documento del comprador.",
|
|
1615
|
-
"error.taxIdInvalid": "NIF/NIE no v\xE1lido: revisa el n\xFAmero.",
|
|
1616
|
-
"error.address": "Rellena o selecciona la direcci\xF3n de env\xEDo.",
|
|
1617
|
-
"error.number": "Falta el n\xFAmero de la direcci\xF3n.",
|
|
1618
|
-
"error.complement": "Indica el piso o la puerta.",
|
|
1619
|
-
"error.state": "Indica el estado con dos letras (ej.: RJ).",
|
|
1620
|
-
"error.postalInvalid": "Revisa el c\xF3digo postal (ej.: {{example}}).",
|
|
1621
|
-
"error.region": "Selecciona la {{label}}.",
|
|
1622
|
-
"error.refusedZone": "Esta tienda no env\xEDa a esta direcci\xF3n. Prueba con otra.",
|
|
1623
|
-
"error.unserved": "Todav\xEDa no enviamos a este c\xF3digo postal. Prueba con otra direcci\xF3n.",
|
|
1624
|
-
"error.sessionMismatch": "Tu sesi\xF3n qued\xF3 vinculada a otra cuenta. Recarga la p\xE1gina e int\xE9ntalo de nuevo.",
|
|
1625
|
-
"error.outOfStock": "Un producto del carrito se ha agotado. Revisa el carrito e int\xE9ntalo de nuevo.",
|
|
1626
|
-
"error.placeOrder": "No se ha podido completar el pedido.",
|
|
1627
|
-
"delivery.title": "Calcular env\xEDo",
|
|
1628
|
-
"delivery.calculate": "Calcular",
|
|
1629
|
-
"delivery.postalLabel": "C\xF3digo postal",
|
|
1630
|
-
"delivery.change": "Cambiar c\xF3digo postal",
|
|
1631
|
-
"delivery.unserved": "Todav\xEDa no enviamos a este c\xF3digo postal.",
|
|
1632
|
-
"delivery.refused": "Esta tienda no env\xEDa a esta direcci\xF3n.",
|
|
1633
|
-
"delivery.review": "Enviamos a esta zona, pero lo confirmamos contigo antes de salir.",
|
|
1634
|
-
"delivery.etaSoon": "hoy o ma\xF1ana",
|
|
1635
|
-
"delivery.etaRange": "de {{min}} a {{max}} d\xEDas laborables",
|
|
1636
|
-
"delivery.etaDays": "{{days}} d\xEDa(s) laborable(s)",
|
|
1637
|
-
"delivery.flatRate": "El env\xEDo se calcula en el pago.",
|
|
1638
|
-
"delivery.error.digits": "Escribe los 8 d\xEDgitos del CEP.",
|
|
1639
|
-
"delivery.error.postal": "Revisa el c\xF3digo postal (ej.: {{example}}).",
|
|
1640
|
-
"delivery.error.quote": "No hemos podido calcular el env\xEDo ahora. Int\xE9ntalo de nuevo.",
|
|
1641
|
-
"delivery.error.notFound": "C\xF3digo postal no encontrado. Revisa los n\xFAmeros.",
|
|
1642
|
-
"cart.title": "Carrito",
|
|
1643
|
-
"cart.close": "Cerrar carrito",
|
|
1644
|
-
"cart.empty": "Tu carrito est\xE1 vac\xEDo.",
|
|
1645
|
-
"cart.remove": "Quitar {{name}}",
|
|
1646
|
-
"cart.checkout": "Finalizar compra",
|
|
1647
|
-
"cart.missingForFree": "Te faltan {{amount}} para el env\xEDo gratis",
|
|
1648
|
-
"cart.wonFree": "\xA1Tienes env\xEDo gratis!",
|
|
1649
|
-
"cart.minimumOrder": "Pedido m\xEDnimo para entrega: {{amount}}. Te faltan {{missing}}.",
|
|
1650
|
-
"delivery.eta": "Entrega en ~{{minutes}} min",
|
|
1651
|
-
"country.deliverTo": "Enviar a",
|
|
1652
|
-
"country.change": "Cambiar pa\xEDs",
|
|
1653
|
-
"country.label": "Pa\xEDs de env\xEDo"
|
|
1654
|
-
};
|
|
1655
|
-
var MESSAGES = { "pt-BR": ptBR, en, es };
|
|
1656
|
-
function normalizeLanguage(value) {
|
|
1657
|
-
const base = (value || "").toLowerCase().split(/[-_]/)[0];
|
|
1658
|
-
if (base === "pt") return "pt-BR";
|
|
1659
|
-
if (base === "en") return "en";
|
|
1660
|
-
if (base === "es") return "es";
|
|
1661
|
-
return null;
|
|
1662
|
-
}
|
|
1663
|
-
function translate(language, key, vars, overrides) {
|
|
1664
|
-
let text = overrides?.[language]?.[key] ?? MESSAGES[language]?.[key] ?? overrides?.["pt-BR"]?.[key] ?? ptBR[key];
|
|
1665
|
-
if (vars) for (const [name, value] of Object.entries(vars)) text = text.split(`{{${name}}}`).join(String(value));
|
|
1666
|
-
return text;
|
|
1667
|
-
}
|
|
1668
|
-
function resolveCountries(config) {
|
|
1669
|
-
const countries = [...new Set((config.countries ?? []).map((c) => c.trim().toUpperCase()).filter(Boolean))];
|
|
1670
|
-
if (countries.length === 0) countries.push("BR");
|
|
1671
|
-
const wanted = config.defaultCountry?.trim().toUpperCase();
|
|
1672
|
-
return { countries, defaultCountry: wanted && countries.includes(wanted) ? wanted : countries[0] };
|
|
1673
|
-
}
|
|
1674
|
-
function resolveConfig(config) {
|
|
1675
|
-
const homePage = config.pages?.home ?? (config.home ? { blocks: config.home.sections } : void 0);
|
|
1676
|
-
const commerceMode = config.commerceMode ?? "checkout";
|
|
1677
|
-
const catalogPath = commerceMode === "delivery" ? config.delivery?.menuPath ?? "/menu" : homePage ? "/catalog" : "/";
|
|
1678
|
-
const checkoutEnabled = commerceMode === "checkout" || commerceMode === "delivery";
|
|
1679
|
-
return {
|
|
1680
|
-
...config,
|
|
1681
|
-
pages: { ...config.pages, ...homePage ? { home: homePage } : {} },
|
|
1682
|
-
currency: config.currency ?? "BRL",
|
|
1683
|
-
locale: config.locale ?? "pt-BR",
|
|
1684
|
-
language: normalizeLanguage(config.language) ?? "pt-BR",
|
|
1685
|
-
...resolveCountries(config),
|
|
1686
|
-
shipping: { flatRate: config.shipping?.flatRate ?? 0, freeAbove: config.shipping?.freeAbove },
|
|
1687
|
-
payments: {
|
|
1688
|
-
mode: config.payments?.mode ?? "mock",
|
|
1689
|
-
methods: config.payments?.methods?.length ? config.payments.methods : ["pix", "credit_card", "cash"],
|
|
1690
|
-
// Rebuilding `payments` key by key silently dropped `terms`, so the Pix
|
|
1691
|
-
// price and the instalment line never reached a component even when the
|
|
1692
|
-
// store had configured them.
|
|
1693
|
-
terms: config.payments?.terms
|
|
1694
|
-
},
|
|
1695
|
-
commerceMode,
|
|
1696
|
-
// Só existe no modo delivery. Fora dele o objeto inteiro é undefined, e é
|
|
1697
|
-
// isso que a rota /menu consulta para decidir se existe.
|
|
1698
|
-
delivery: commerceMode === "delivery" ? {
|
|
1699
|
-
menuPath: config.delivery?.menuPath ?? "/menu",
|
|
1700
|
-
coverImage: config.delivery?.coverImage,
|
|
1701
|
-
logoImage: config.delivery?.logoImage,
|
|
1702
|
-
locality: config.delivery?.locality,
|
|
1703
|
-
highlightSlugs: config.delivery?.highlightSlugs,
|
|
1704
|
-
// A ORDEM é a do seletor na tela. Um Set aqui perderia isso.
|
|
1705
|
-
fulfillmentModes: config.delivery?.fulfillmentModes?.length ? config.delivery.fulfillmentModes : ["delivery"].slice(),
|
|
1706
|
-
// Agendamento é opt-in duas vezes: aqui e na loja (0094 devolve zero
|
|
1707
|
-
// slots quando scheduling_enabled é falso). A tela só oferece quando
|
|
1708
|
-
// as duas concordam.
|
|
1709
|
-
scheduling: config.delivery?.scheduling ?? false,
|
|
1710
|
-
pickupAddress: config.delivery?.pickupAddress
|
|
1711
|
-
} : void 0,
|
|
1712
|
-
enquiry: {
|
|
1713
|
-
label: config.enquiry?.label ?? "Contact me",
|
|
1714
|
-
successMessage: config.enquiry?.successMessage ?? "Thanks. We received your enquiry.",
|
|
1715
|
-
subjectPrefix: config.enquiry?.subjectPrefix ?? "Product enquiry",
|
|
1716
|
-
email: config.enquiry?.email,
|
|
1717
|
-
whatsappUrl: config.enquiry?.whatsappUrl,
|
|
1718
|
-
requirePhone: config.enquiry?.requirePhone
|
|
1719
|
-
},
|
|
1720
|
-
features: {
|
|
1721
|
-
// Auto-enable the coupon UI when the store actually ships discount codes
|
|
1722
|
-
// (config.discounts, a seeded catalog, or a rule-engine promotion with a
|
|
1723
|
-
// code — M6), unless explicitly overridden — otherwise a store can
|
|
1724
|
-
// advertise a coupon with no field to enter it, which is exactly the
|
|
1725
|
-
// figurinhas pilot failure this milestone exists to end.
|
|
1726
|
-
discounts: config.features?.discounts ?? Boolean(
|
|
1727
|
-
config.discounts?.length || config.catalog?.discounts?.length || config.promotions?.some((p) => p.code) || config.catalog?.promotions?.some((p) => p.code)
|
|
1728
|
-
),
|
|
1729
|
-
accounts: config.features?.accounts ?? checkoutEnabled,
|
|
1730
|
-
cart: config.features?.cart ?? checkoutEnabled,
|
|
1731
|
-
checkout: config.features?.checkout ?? checkoutEnabled
|
|
1732
|
-
},
|
|
1733
|
-
imageLoading: {
|
|
1734
|
-
mode: config.imageLoading?.mode ?? "fade",
|
|
1735
|
-
durationMs: config.imageLoading?.durationMs ?? 420,
|
|
1736
|
-
easing: config.imageLoading?.easing ?? "cubic-bezier(0.22, 1, 0.36, 1)",
|
|
1737
|
-
blur: config.imageLoading?.blur ?? true,
|
|
1738
|
-
transform: config.imageLoading?.transform ?? "none"
|
|
1739
|
-
},
|
|
1740
|
-
catalogPath,
|
|
1741
|
-
search: {
|
|
1742
|
-
mode: config.search?.mode ?? "inline",
|
|
1743
|
-
placeholder: config.search?.placeholder ?? "Buscar produtos...",
|
|
1744
|
-
resultsPath: config.search?.resultsPath ?? "/search",
|
|
1745
|
-
suggestionsLimit: config.search?.suggestionsLimit ?? 4,
|
|
1746
|
-
minChars: config.search?.minChars ?? 2,
|
|
1747
|
-
ctaLabel: config.search?.ctaLabel ?? "Ver todos resultados",
|
|
1748
|
-
emptyLabel: config.search?.emptyLabel ?? "Nada encontrado para",
|
|
1749
|
-
renderSuggestion: config.search?.renderSuggestion
|
|
1750
|
-
},
|
|
1751
|
-
nav: config.nav ?? (homePage ? [
|
|
1752
|
-
{ label: "In\xEDcio", to: "/" },
|
|
1753
|
-
{ label: "Loja", to: "/catalog" }
|
|
1754
|
-
] : [{ label: "Loja", to: "/" }])
|
|
1755
|
-
};
|
|
1756
|
-
}
|
|
1757
|
-
var StorefrontConfigContext = createContext(null);
|
|
1758
|
-
var StorefrontConfigProvider = StorefrontConfigContext.Provider;
|
|
1759
|
-
function useStorefrontConfig() {
|
|
1760
|
-
const ctx = useContext(StorefrontConfigContext);
|
|
1761
|
-
if (!ctx) throw new Error("useStorefrontConfig must be used inside createStorefrontApp");
|
|
1762
|
-
return ctx;
|
|
1763
|
-
}
|
|
1764
|
-
function useStorefrontConfigOptional() {
|
|
1765
|
-
return useContext(StorefrontConfigContext);
|
|
1766
|
-
}
|
|
1767
|
-
function getStorefrontComponents(config) {
|
|
1768
|
-
return config.components ?? {};
|
|
1769
|
-
}
|
|
1770
1233
|
function prefersReducedMotion() {
|
|
1771
1234
|
if (typeof window === "undefined" || !window.matchMedia) return false;
|
|
1772
1235
|
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
@@ -1858,84 +1321,6 @@ function usePopOnChange(value) {
|
|
|
1858
1321
|
});
|
|
1859
1322
|
return pop;
|
|
1860
1323
|
}
|
|
1861
|
-
var RouterAdapterContext = createContext(null);
|
|
1862
|
-
var StorefrontRouterProvider = RouterAdapterContext.Provider;
|
|
1863
|
-
var _activeAdapter = null;
|
|
1864
|
-
var _fallback = null;
|
|
1865
|
-
function fallbackAdapter() {
|
|
1866
|
-
if (!_fallback) _fallback = defaultRouterAdapter("hash");
|
|
1867
|
-
return _fallback;
|
|
1868
|
-
}
|
|
1869
|
-
function useRouterAdapter() {
|
|
1870
|
-
const injected = useContext(RouterAdapterContext);
|
|
1871
|
-
const adapter = injected ?? fallbackAdapter();
|
|
1872
|
-
useEffect(() => {
|
|
1873
|
-
if (injected) _activeAdapter = injected;
|
|
1874
|
-
}, [injected]);
|
|
1875
|
-
return adapter;
|
|
1876
|
-
}
|
|
1877
|
-
function useRoutePath() {
|
|
1878
|
-
const adapter = useRouterAdapter();
|
|
1879
|
-
return useSyncExternalStore(
|
|
1880
|
-
(onChange) => adapter.onPathChange(onChange),
|
|
1881
|
-
() => adapter.getCurrentPath() || "/",
|
|
1882
|
-
() => adapter.getCurrentPath() || "/"
|
|
1883
|
-
);
|
|
1884
|
-
}
|
|
1885
|
-
function useScrollToTopOnNavigate(path) {
|
|
1886
|
-
const mounted = useRef(false);
|
|
1887
|
-
useEffect(() => {
|
|
1888
|
-
if (!mounted.current) {
|
|
1889
|
-
mounted.current = true;
|
|
1890
|
-
return;
|
|
1891
|
-
}
|
|
1892
|
-
if (typeof window !== "undefined") window.scrollTo(0, 0);
|
|
1893
|
-
}, [path]);
|
|
1894
|
-
}
|
|
1895
|
-
function useNavigate() {
|
|
1896
|
-
const adapter = useRouterAdapter();
|
|
1897
|
-
return adapter.navigate.bind(adapter);
|
|
1898
|
-
}
|
|
1899
|
-
var useHashPath = useRoutePath;
|
|
1900
|
-
function navigateTo(to) {
|
|
1901
|
-
(_activeAdapter ?? fallbackAdapter()).navigate(to);
|
|
1902
|
-
}
|
|
1903
|
-
function shellRouterAdapter(pathOverride, live) {
|
|
1904
|
-
if (pathOverride == null) return live;
|
|
1905
|
-
return staticRouterAdapter(pathOverride, { href: (to) => live.href(to) });
|
|
1906
|
-
}
|
|
1907
|
-
function matchPath(pattern, path) {
|
|
1908
|
-
const cleanPath = (path.split("?")[0] ?? "").replace(/\/+$/, "") || "/";
|
|
1909
|
-
const patternParts = pattern.split("/").filter(Boolean);
|
|
1910
|
-
const pathParts = cleanPath.split("/").filter(Boolean);
|
|
1911
|
-
if (patternParts.length !== pathParts.length) return null;
|
|
1912
|
-
const params = {};
|
|
1913
|
-
for (let i = 0; i < patternParts.length; i++) {
|
|
1914
|
-
const pat = patternParts[i];
|
|
1915
|
-
const part = pathParts[i];
|
|
1916
|
-
if (pat.startsWith(":")) params[pat.slice(1)] = decodeURIComponent(part);
|
|
1917
|
-
else if (pat !== part) return null;
|
|
1918
|
-
}
|
|
1919
|
-
return params;
|
|
1920
|
-
}
|
|
1921
|
-
function Link({ to, children, onClick, target, ...rest }) {
|
|
1922
|
-
const adapter = useRouterAdapter();
|
|
1923
|
-
const handleClick = (event) => {
|
|
1924
|
-
onClick?.(event);
|
|
1925
|
-
if (!adapter.interceptsLinkClicks) return;
|
|
1926
|
-
if (event.defaultPrevented) return;
|
|
1927
|
-
if (target && target !== "_self") return;
|
|
1928
|
-
if (event.button !== 0) return;
|
|
1929
|
-
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
1930
|
-
event.preventDefault();
|
|
1931
|
-
adapter.navigate(to);
|
|
1932
|
-
};
|
|
1933
|
-
return React39__default.createElement(
|
|
1934
|
-
"a",
|
|
1935
|
-
{ href: adapter.href(to), onClick: handleClick, target, ...rest },
|
|
1936
|
-
children
|
|
1937
|
-
);
|
|
1938
|
-
}
|
|
1939
1324
|
|
|
1940
1325
|
// src/lib/testids.ts
|
|
1941
1326
|
var TID = {
|
|
@@ -2170,9 +1555,9 @@ function SmoothImage({
|
|
|
2170
1555
|
const easing = resolved.easing ?? "cubic-bezier(0.22, 1, 0.36, 1)";
|
|
2171
1556
|
const blur = resolved.blur ?? true;
|
|
2172
1557
|
const transform = resolved.transform ?? "none";
|
|
2173
|
-
const ref =
|
|
2174
|
-
const [loaded, setLoaded] =
|
|
2175
|
-
const delivered =
|
|
1558
|
+
const ref = React36__default.useRef(null);
|
|
1559
|
+
const [loaded, setLoaded] = React36__default.useState(() => mode === "none" || !clientMounted);
|
|
1560
|
+
const delivered = React36__default.useMemo(() => {
|
|
2176
1561
|
if (transform !== "supabase" || !src || srcSet || !isStorageImageUrl(src)) return { src, srcSet, sizes };
|
|
2177
1562
|
if (variant?.width) {
|
|
2178
1563
|
const w = variant.width;
|
|
@@ -2190,10 +1575,10 @@ function SmoothImage({
|
|
|
2190
1575
|
sizes: variant?.sizes ?? sizes ?? "100vw"
|
|
2191
1576
|
};
|
|
2192
1577
|
}, [transform, src, srcSet, sizes, variant?.width, variant?.sizes, variant?.widths, variant?.quality]);
|
|
2193
|
-
|
|
1578
|
+
React36__default.useEffect(() => {
|
|
2194
1579
|
clientMounted = true;
|
|
2195
1580
|
}, []);
|
|
2196
|
-
|
|
1581
|
+
React36__default.useEffect(() => {
|
|
2197
1582
|
if (mode === "none") {
|
|
2198
1583
|
setLoaded(true);
|
|
2199
1584
|
return;
|
|
@@ -2227,8 +1612,8 @@ function SmoothImage({
|
|
|
2227
1612
|
function slideImage(slide, w = 1600, h = 700) {
|
|
2228
1613
|
return slide.image ?? bannerPlaceholder(slide.title, slide.hue ?? 200, (slide.hue ?? 200) + 40, w, h);
|
|
2229
1614
|
}
|
|
2230
|
-
function SlideCopy({ slide, active
|
|
2231
|
-
const stagger = (i) =>
|
|
1615
|
+
function SlideCopy({ slide, active }) {
|
|
1616
|
+
const stagger = (i) => active ? { className: "animate-fade-up", style: { animationDelay: `${i * 120}ms` } } : { className: "opacity-0" };
|
|
2232
1617
|
const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2233
1618
|
/* @__PURE__ */ jsx("h2", { className: `sf-heading text-3xl font-bold leading-tight tracking-tight sm:text-5xl ${stagger(0).className}`, style: stagger(0).style, children: slide.title }),
|
|
2234
1619
|
slide.subtitle && /* @__PURE__ */ jsx("p", { className: `mt-3 max-w-md text-base sm:text-lg ${stagger(1).className}`, style: stagger(1).style, children: slide.subtitle }),
|
|
@@ -2309,7 +1694,7 @@ function HeroSection({
|
|
|
2309
1694
|
i
|
|
2310
1695
|
)) });
|
|
2311
1696
|
}
|
|
2312
|
-
const
|
|
1697
|
+
const active = slides[Math.min(index, slides.length - 1)];
|
|
2313
1698
|
return /* @__PURE__ */ jsxs("section", { "data-testid": TID.hero, className: `relative w-full overflow-hidden ${hClass}`, children: [
|
|
2314
1699
|
slides.map((slide, i) => /* @__PURE__ */ jsx(
|
|
2315
1700
|
"img",
|
|
@@ -2328,8 +1713,8 @@ function HeroSection({
|
|
|
2328
1713
|
/* @__PURE__ */ jsx(
|
|
2329
1714
|
"div",
|
|
2330
1715
|
{
|
|
2331
|
-
className: `absolute inset-0 flex items-end p-6 sm:p-12 ${
|
|
2332
|
-
children: /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-7xl", children: /* @__PURE__ */ jsx("div", { className: "max-w-xl", children: /* @__PURE__ */ jsx(SlideCopy, { slide:
|
|
1716
|
+
className: `absolute inset-0 flex items-end p-6 sm:p-12 ${active.boxed ? "" : "bg-gradient-to-t from-black/60 via-black/20 to-transparent"}`,
|
|
1717
|
+
children: /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-7xl", children: /* @__PURE__ */ jsx("div", { className: "max-w-xl", children: /* @__PURE__ */ jsx(SlideCopy, { slide: active, active: true }, index) }) })
|
|
2333
1718
|
}
|
|
2334
1719
|
),
|
|
2335
1720
|
variant === "slider" && slides.length > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -2495,196 +1880,6 @@ var useCatalogStore = create()((set) => ({
|
|
|
2495
1880
|
setSort: (sort) => set({ sort }),
|
|
2496
1881
|
reset: () => set(initial)
|
|
2497
1882
|
}));
|
|
2498
|
-
|
|
2499
|
-
// src/app/static-render.ts
|
|
2500
|
-
var active = null;
|
|
2501
|
-
function currentStaticRenderPass() {
|
|
2502
|
-
return active;
|
|
2503
|
-
}
|
|
2504
|
-
function withStaticRenderPass(pass, render) {
|
|
2505
|
-
const previous = active;
|
|
2506
|
-
active = pass;
|
|
2507
|
-
try {
|
|
2508
|
-
return render();
|
|
2509
|
-
} finally {
|
|
2510
|
-
active = previous;
|
|
2511
|
-
}
|
|
2512
|
-
}
|
|
2513
|
-
function resolveDataParams(need, context) {
|
|
2514
|
-
const out = {};
|
|
2515
|
-
for (const [name, value] of Object.entries(need.params ?? {})) {
|
|
2516
|
-
let resolved = value;
|
|
2517
|
-
if (isLoaderParamRef(value)) resolved = context.params[value.$param];
|
|
2518
|
-
else if (isLoaderPropRef(value)) resolved = context.props[value.$prop];
|
|
2519
|
-
if (resolved !== void 0) out[name] = resolved;
|
|
2520
|
-
}
|
|
2521
|
-
return out;
|
|
2522
|
-
}
|
|
2523
|
-
function needsForNode(node) {
|
|
2524
|
-
const meta = getBlockMeta(node.type);
|
|
2525
|
-
return { ...meta?.data, ...node.data };
|
|
2526
|
-
}
|
|
2527
|
-
function collectDataNeeds(nodes, routeParams = {}) {
|
|
2528
|
-
const found = /* @__PURE__ */ new Map();
|
|
2529
|
-
const visit = (node) => {
|
|
2530
|
-
const meta = getBlockMeta(node.type);
|
|
2531
|
-
const needs = needsForNode(node);
|
|
2532
|
-
if (Object.keys(needs).length > 0) {
|
|
2533
|
-
const props = { ...defaultPropsFromSettings(meta?.settings), ...node.props };
|
|
2534
|
-
for (const need of Object.values(needs)) {
|
|
2535
|
-
if (!need || typeof need.loader !== "string" || !need.loader) continue;
|
|
2536
|
-
const params = resolveDataParams(need, { params: routeParams, props });
|
|
2537
|
-
const key = dataNeedKey(need.loader, params);
|
|
2538
|
-
if (!found.has(key)) found.set(key, { key, loader: need.loader, params });
|
|
2539
|
-
}
|
|
2540
|
-
}
|
|
2541
|
-
for (const child of node.children ?? []) visit(child);
|
|
2542
|
-
};
|
|
2543
|
-
for (const node of nodes) visit(node);
|
|
2544
|
-
return [...found.values()];
|
|
2545
|
-
}
|
|
2546
|
-
async function resolvePageDataNeed(need) {
|
|
2547
|
-
try {
|
|
2548
|
-
const impl = resolveLoader(need.loader);
|
|
2549
|
-
const data = await impl(need.params, { shop: getShopProvider() });
|
|
2550
|
-
return { status: "ready", data };
|
|
2551
|
-
} catch (err) {
|
|
2552
|
-
const message = errorMessage(err);
|
|
2553
|
-
console.error(`[storefront] loader "${need.loader}" failed:`, err);
|
|
2554
|
-
return { status: "error", error: message };
|
|
2555
|
-
}
|
|
2556
|
-
}
|
|
2557
|
-
async function resolvePageData(needs) {
|
|
2558
|
-
const settled = await Promise.all(
|
|
2559
|
-
needs.map(async (need) => [need.key, await resolvePageDataNeed(need)])
|
|
2560
|
-
);
|
|
2561
|
-
return Object.fromEntries(settled);
|
|
2562
|
-
}
|
|
2563
|
-
var PageDataContext = createContext(null);
|
|
2564
|
-
function PageDataScope({ nodes, params, initial: initial2, children }) {
|
|
2565
|
-
const parent = useContext(PageDataContext);
|
|
2566
|
-
const routeParams = useMemo(() => params ?? parent?.params ?? {}, [params, parent]);
|
|
2567
|
-
const needs = useMemo(() => collectDataNeeds(nodes, routeParams), [nodes, routeParams]);
|
|
2568
|
-
const own = useMemo(
|
|
2569
|
-
() => needs.filter((need) => !parent || !(need.key in parent.entries)),
|
|
2570
|
-
[needs, parent]
|
|
2571
|
-
);
|
|
2572
|
-
const staticPass = currentStaticRenderPass();
|
|
2573
|
-
if (staticPass) {
|
|
2574
|
-
staticPass.tree(nodes);
|
|
2575
|
-
staticPass.needs(own);
|
|
2576
|
-
}
|
|
2577
|
-
const [entries, setEntries] = useState(() => ({
|
|
2578
|
-
// Everything handed in is published, not only the needs THIS scope
|
|
2579
|
-
// collected. That is what lets a host framework resolve a page's data in
|
|
2580
|
-
// its own loader and wrap the shell in a seeding scope: the page's own
|
|
2581
|
-
// scope then finds those keys already answered on its parent and fetches
|
|
2582
|
-
// nothing. Without it, seeding only works when the seeding scope happens to
|
|
2583
|
-
// render the same block tree.
|
|
2584
|
-
...initial2,
|
|
2585
|
-
...Object.fromEntries(
|
|
2586
|
-
own.map((need) => [
|
|
2587
|
-
need.key,
|
|
2588
|
-
initial2?.[need.key] ?? staticPass?.entries[need.key] ?? { status: "loading" }
|
|
2589
|
-
])
|
|
2590
|
-
)
|
|
2591
|
-
}));
|
|
2592
|
-
const signature = own.map((need) => need.key).join("\n");
|
|
2593
|
-
useEffect(() => {
|
|
2594
|
-
const pending2 = own.filter((need) => initial2?.[need.key]?.status !== "ready");
|
|
2595
|
-
if (pending2.length === 0) return;
|
|
2596
|
-
let cancelled = false;
|
|
2597
|
-
setEntries((prev) => {
|
|
2598
|
-
const next = { ...prev };
|
|
2599
|
-
for (const need of pending2) {
|
|
2600
|
-
if (next[need.key]?.status !== "ready") next[need.key] = { status: "loading" };
|
|
2601
|
-
}
|
|
2602
|
-
return next;
|
|
2603
|
-
});
|
|
2604
|
-
for (const need of pending2) {
|
|
2605
|
-
void resolvePageDataNeed(need).then((entry) => {
|
|
2606
|
-
if (!cancelled) setEntries((prev) => ({ ...prev, [need.key]: entry }));
|
|
2607
|
-
});
|
|
2608
|
-
}
|
|
2609
|
-
return () => {
|
|
2610
|
-
cancelled = true;
|
|
2611
|
-
};
|
|
2612
|
-
}, [signature]);
|
|
2613
|
-
const value = useMemo(
|
|
2614
|
-
() => ({ entries: { ...parent?.entries, ...entries, ...initial2 }, params: routeParams }),
|
|
2615
|
-
[parent, entries, initial2, routeParams]
|
|
2616
|
-
);
|
|
2617
|
-
return /* @__PURE__ */ jsx(PageDataContext.Provider, { value, children });
|
|
2618
|
-
}
|
|
2619
|
-
function useLoader(loader, params) {
|
|
2620
|
-
const scope = useContext(PageDataContext);
|
|
2621
|
-
const key = params === null ? null : dataNeedKey(loader, params);
|
|
2622
|
-
const [nonce, setNonce] = useState(0);
|
|
2623
|
-
const scoped = nonce === 0 && key !== null && scope ? scope.entries[key] : void 0;
|
|
2624
|
-
const [local, setLocal] = useState(null);
|
|
2625
|
-
const staticPass = currentStaticRenderPass();
|
|
2626
|
-
const staticEntry = staticPass && key !== null && scoped === void 0 ? staticPass.entries[key] : void 0;
|
|
2627
|
-
if (staticPass && key !== null && scoped === void 0 && staticEntry === void 0) {
|
|
2628
|
-
staticPass.needs([{ key, loader, params }]);
|
|
2629
|
-
}
|
|
2630
|
-
const paramsKey = params === null ? null : JSON.stringify(params);
|
|
2631
|
-
useEffect(() => {
|
|
2632
|
-
if (key === null || scoped !== void 0) return;
|
|
2633
|
-
let cancelled = false;
|
|
2634
|
-
setLocal({ key, entry: { status: "loading" } });
|
|
2635
|
-
void resolvePageDataNeed({ loader, params }).then((entry2) => {
|
|
2636
|
-
if (!cancelled) setLocal({ key, entry: entry2 });
|
|
2637
|
-
});
|
|
2638
|
-
return () => {
|
|
2639
|
-
cancelled = true;
|
|
2640
|
-
};
|
|
2641
|
-
}, [loader, paramsKey, nonce, scoped !== void 0]);
|
|
2642
|
-
const entry = scoped ?? staticEntry ?? (local && local.key === key ? local.entry : key !== null ? { status: "loading" } : null);
|
|
2643
|
-
return {
|
|
2644
|
-
status: entry?.status ?? "idle",
|
|
2645
|
-
data: entry?.status === "ready" ? entry.data : null,
|
|
2646
|
-
error: entry?.status === "error" ? entry.error ?? "unknown error" : null,
|
|
2647
|
-
reload: () => setNonce((n) => n + 1)
|
|
2648
|
-
};
|
|
2649
|
-
}
|
|
2650
|
-
function useBlockData(node, name, fallback) {
|
|
2651
|
-
const scope = useContext(PageDataContext);
|
|
2652
|
-
let loader = fallback.loader;
|
|
2653
|
-
let params = fallback.params;
|
|
2654
|
-
if (node) {
|
|
2655
|
-
const need = needsForNode(node)[name];
|
|
2656
|
-
if (need && typeof need.loader === "string" && need.loader) {
|
|
2657
|
-
const meta = getBlockMeta(node.type);
|
|
2658
|
-
loader = need.loader;
|
|
2659
|
-
params = resolveDataParams(need, {
|
|
2660
|
-
params: scope?.params ?? {},
|
|
2661
|
-
props: { ...defaultPropsFromSettings(meta?.settings), ...node.props }
|
|
2662
|
-
});
|
|
2663
|
-
}
|
|
2664
|
-
}
|
|
2665
|
-
const result = useLoader(loader, params);
|
|
2666
|
-
return { ...result, loader };
|
|
2667
|
-
}
|
|
2668
|
-
function BlockDataError({ loader, message }) {
|
|
2669
|
-
if (getBlockErrorVisibility() === "silent") return null;
|
|
2670
|
-
return /* @__PURE__ */ jsxs(
|
|
2671
|
-
"div",
|
|
2672
|
-
{
|
|
2673
|
-
"data-block-error": `loader:${loader}`,
|
|
2674
|
-
style: {
|
|
2675
|
-
border: "1px dashed #dc2626",
|
|
2676
|
-
color: "#b91c1c",
|
|
2677
|
-
padding: "8px 12px",
|
|
2678
|
-
font: "12px ui-monospace, monospace",
|
|
2679
|
-
borderRadius: 6
|
|
2680
|
-
},
|
|
2681
|
-
children: [
|
|
2682
|
-
`Data for this block failed (loader "${loader}")`,
|
|
2683
|
-
message ? /* @__PURE__ */ jsx("div", { style: { opacity: 0.8, marginTop: 4 }, children: message }) : null
|
|
2684
|
-
]
|
|
2685
|
-
}
|
|
2686
|
-
);
|
|
2687
|
-
}
|
|
2688
1883
|
function CategoryShowcase({
|
|
2689
1884
|
style,
|
|
2690
1885
|
title,
|
|
@@ -2801,11 +1996,11 @@ function useStorefrontActions() {
|
|
|
2801
1996
|
};
|
|
2802
1997
|
}
|
|
2803
1998
|
function useMarketProduct(product) {
|
|
2804
|
-
const
|
|
1999
|
+
const active = useMarketStore((s2) => s2.active);
|
|
2805
2000
|
const prices = useMarketStore((s2) => s2.prices);
|
|
2806
2001
|
return useMemo(
|
|
2807
|
-
() => product ? withMarketPrice(product, { active
|
|
2808
|
-
[product,
|
|
2002
|
+
() => product ? withMarketPrice(product, { active, prices }) : product,
|
|
2003
|
+
[product, active, prices]
|
|
2809
2004
|
);
|
|
2810
2005
|
}
|
|
2811
2006
|
function Price({ value, compareAt, testId, compareTestId, className }) {
|
|
@@ -2845,12 +2040,12 @@ function PaymentTerms({ price, metadata, variant = "card", className = "" }) {
|
|
|
2845
2040
|
if (terms.pixPrice == null && terms.installments === 0) return null;
|
|
2846
2041
|
const currency = config.currency;
|
|
2847
2042
|
const locale = config.locale;
|
|
2848
|
-
const
|
|
2043
|
+
const compact = variant === "card";
|
|
2849
2044
|
return /* @__PURE__ */ jsxs(
|
|
2850
2045
|
"div",
|
|
2851
2046
|
{
|
|
2852
2047
|
"data-testid": "payment-terms",
|
|
2853
|
-
className: `${
|
|
2048
|
+
className: `${compact ? "mt-0.5 space-y-0.5 text-[11px]" : "mt-3 space-y-1 text-sm"} leading-tight text-muted-foreground ${className}`,
|
|
2854
2049
|
children: [
|
|
2855
2050
|
terms.pixPrice != null && /* @__PURE__ */ jsxs("p", { "data-testid": "payment-terms-pix", children: [
|
|
2856
2051
|
/* @__PURE__ */ jsx("strong", { className: "font-semibold text-foreground", children: formatMoney(terms.pixPrice, currency, locale) }),
|
|
@@ -2890,150 +2085,6 @@ var storefrontComponentContracts = {
|
|
|
2890
2085
|
enquiryForm: { "data-testid": TID.enquiryForm }
|
|
2891
2086
|
}
|
|
2892
2087
|
};
|
|
2893
|
-
function mergePageTheme(base, overlay) {
|
|
2894
|
-
if (!base && !overlay) return void 0;
|
|
2895
|
-
if (!overlay) return base;
|
|
2896
|
-
const name = overlay.name ?? (base ? `${base.name}-page` : "page");
|
|
2897
|
-
const font = base?.font ? { ...base.font, ...overlay.font } : overlay.font;
|
|
2898
|
-
return {
|
|
2899
|
-
...base,
|
|
2900
|
-
...overlay,
|
|
2901
|
-
name,
|
|
2902
|
-
colors: { ...base?.colors, ...overlay.colors },
|
|
2903
|
-
font,
|
|
2904
|
-
tokens: { ...base?.tokens, ...overlay.tokens },
|
|
2905
|
-
header: { ...base?.header, ...overlay.header },
|
|
2906
|
-
productCard: { ...base?.productCard, ...overlay.productCard }
|
|
2907
|
-
};
|
|
2908
|
-
}
|
|
2909
|
-
function pageThemeSelector(slug) {
|
|
2910
|
-
return `[data-page="${slug}"]`;
|
|
2911
|
-
}
|
|
2912
|
-
function routePathParams(path) {
|
|
2913
|
-
return path.split("/").filter((segment) => segment.startsWith(":")).map((segment) => segment.slice(1));
|
|
2914
|
-
}
|
|
2915
|
-
function contentPagePath(slug, page) {
|
|
2916
|
-
return page.path ?? `/${slug}`;
|
|
2917
|
-
}
|
|
2918
|
-
function matchContentPage(pages, path) {
|
|
2919
|
-
for (const [slug, page] of Object.entries(pages?.content ?? {})) {
|
|
2920
|
-
const params = matchPath(contentPagePath(slug, page), path);
|
|
2921
|
-
if (params) return { slug, page, params };
|
|
2922
|
-
}
|
|
2923
|
-
return null;
|
|
2924
|
-
}
|
|
2925
|
-
var CATALOG_BODY_BLOCK = "catalogBody";
|
|
2926
|
-
var PRODUCT_BODY_BLOCK = "productBody";
|
|
2927
|
-
var BODY_BLOCK_BY_KIND = {
|
|
2928
|
-
catalog: CATALOG_BODY_BLOCK,
|
|
2929
|
-
product: PRODUCT_BODY_BLOCK
|
|
2930
|
-
};
|
|
2931
|
-
var BLOCK_STRUCTURAL_KEYS = /* @__PURE__ */ new Set([
|
|
2932
|
-
"type",
|
|
2933
|
-
"id",
|
|
2934
|
-
"props",
|
|
2935
|
-
"children",
|
|
2936
|
-
"data"
|
|
2937
|
-
]);
|
|
2938
|
-
var STRUCTURAL_KEYS = BLOCK_STRUCTURAL_KEYS;
|
|
2939
|
-
function isNestedBlockRef(entry) {
|
|
2940
|
-
return isNestedRef(entry);
|
|
2941
|
-
}
|
|
2942
|
-
function isNestedRef(entry) {
|
|
2943
|
-
const record = entry;
|
|
2944
|
-
if ("props" in record) return true;
|
|
2945
|
-
return Object.keys(record).every((key) => STRUCTURAL_KEYS.has(key));
|
|
2946
|
-
}
|
|
2947
|
-
function blockInstanceId(entry, index) {
|
|
2948
|
-
const record = entry;
|
|
2949
|
-
if (record && typeof record.id === "string" && record.id) return record.id;
|
|
2950
|
-
return `${String(record?.type)}-${index}`;
|
|
2951
|
-
}
|
|
2952
|
-
function toBlockNode(entry, index) {
|
|
2953
|
-
const record = entry;
|
|
2954
|
-
const type = String(record.type);
|
|
2955
|
-
const id = blockInstanceId(entry, index);
|
|
2956
|
-
const data = record.data;
|
|
2957
|
-
if (isNestedRef(entry)) {
|
|
2958
|
-
const children = record.children ?? [];
|
|
2959
|
-
return {
|
|
2960
|
-
type,
|
|
2961
|
-
id,
|
|
2962
|
-
props: record.props ?? {},
|
|
2963
|
-
...children.length ? { children: children.map((child, i) => toBlockNode(child, i)) } : {},
|
|
2964
|
-
...data ? { data } : {}
|
|
2965
|
-
};
|
|
2966
|
-
}
|
|
2967
|
-
const props = {};
|
|
2968
|
-
for (const [key, value] of Object.entries(record)) {
|
|
2969
|
-
if (!STRUCTURAL_KEYS.has(key)) props[key] = value;
|
|
2970
|
-
}
|
|
2971
|
-
return { type, id, props, ...data ? { data } : {} };
|
|
2972
|
-
}
|
|
2973
|
-
function toBlockNodes(blocks) {
|
|
2974
|
-
return blocks.map(toBlockNode);
|
|
2975
|
-
}
|
|
2976
|
-
function defaultPageBlocks(kind) {
|
|
2977
|
-
const body = BODY_BLOCK_BY_KIND[kind];
|
|
2978
|
-
return body ? [{ type: body, id: body, props: {} }] : [];
|
|
2979
|
-
}
|
|
2980
|
-
function checkPageBlocks(kind, nodes) {
|
|
2981
|
-
const found = [];
|
|
2982
|
-
const seenIds = /* @__PURE__ */ new Set();
|
|
2983
|
-
const expectedBody = BODY_BLOCK_BY_KIND[kind];
|
|
2984
|
-
let hasBody = false;
|
|
2985
|
-
for (const node of nodes) {
|
|
2986
|
-
if (node.type === expectedBody) hasBody = true;
|
|
2987
|
-
if (node.id) {
|
|
2988
|
-
if (seenIds.has(node.id)) {
|
|
2989
|
-
found.push({
|
|
2990
|
-
level: "warning",
|
|
2991
|
-
rule: "duplicate-block-id",
|
|
2992
|
-
detail: `two blocks on the ${kind} page share the id "${node.id}" \u2014 an editor or a generated diff cannot tell them apart`
|
|
2993
|
-
});
|
|
2994
|
-
}
|
|
2995
|
-
seenIds.add(node.id);
|
|
2996
|
-
}
|
|
2997
|
-
const meta = getBlockMeta(node.type);
|
|
2998
|
-
if (!meta) {
|
|
2999
|
-
found.push({
|
|
3000
|
-
level: "error",
|
|
3001
|
-
rule: "unknown-block",
|
|
3002
|
-
detail: `the ${kind} page references block "${node.type}", which is not registered \u2014 register it before the storefront mounts`
|
|
3003
|
-
});
|
|
3004
|
-
continue;
|
|
3005
|
-
}
|
|
3006
|
-
if (!isBlockEnabledOn({ enabledOn: meta.enabledOn ?? [] }, kind)) {
|
|
3007
|
-
found.push({
|
|
3008
|
-
level: "warning",
|
|
3009
|
-
rule: "block-not-enabled-on-page",
|
|
3010
|
-
detail: `block "${node.type}" declares enabledOn [${(meta.enabledOn ?? []).join(", ")}] and is placed on the ${kind} page`
|
|
3011
|
-
});
|
|
3012
|
-
}
|
|
3013
|
-
}
|
|
3014
|
-
if (expectedBody && !hasBody) {
|
|
3015
|
-
found.push({
|
|
3016
|
-
level: "warning",
|
|
3017
|
-
rule: "missing-page-body",
|
|
3018
|
-
detail: `the ${kind} page tree omits "${expectedBody}", so the page renders no ${kind === "product" ? "product detail" : "product list"} \u2014 add it back unless the replacement is deliberate`
|
|
3019
|
-
});
|
|
3020
|
-
}
|
|
3021
|
-
for (const violation of checkBlockConstraints(nodes)) {
|
|
3022
|
-
found.push({
|
|
3023
|
-
level: "error",
|
|
3024
|
-
rule: violation.rule,
|
|
3025
|
-
detail: `${kind} page ${violation.path}: ${violation.detail}`
|
|
3026
|
-
});
|
|
3027
|
-
}
|
|
3028
|
-
for (const finding of checkBlockContext(nodes)) {
|
|
3029
|
-
found.push({
|
|
3030
|
-
level: "warning",
|
|
3031
|
-
rule: "context-not-provided",
|
|
3032
|
-
detail: `block "${finding.type}" at ${kind} page ${finding.path} uses context [${finding.missing.join(", ")}] that no ancestor provides`
|
|
3033
|
-
});
|
|
3034
|
-
}
|
|
3035
|
-
return found;
|
|
3036
|
-
}
|
|
3037
2088
|
|
|
3038
2089
|
// src/app/hydration.ts
|
|
3039
2090
|
var PAGE_DATA_SCRIPT_ID = "__fayz_page_data__";
|
|
@@ -3469,8 +2520,8 @@ var BADGE_TONE_CLASSES = {
|
|
|
3469
2520
|
warning: "bg-amber-500 text-white"
|
|
3470
2521
|
};
|
|
3471
2522
|
function useExtensionBadges(product) {
|
|
3472
|
-
const [badges, setBadges] =
|
|
3473
|
-
|
|
2523
|
+
const [badges, setBadges] = React36__default.useState([]);
|
|
2524
|
+
React36__default.useEffect(() => {
|
|
3474
2525
|
let cancelled = false;
|
|
3475
2526
|
getProductCardBadges(product).then((next) => {
|
|
3476
2527
|
if (!cancelled && next.length > 0) setBadges(next);
|
|
@@ -3792,7 +2843,7 @@ function MediaCarousel({
|
|
|
3792
2843
|
return () => clearInterval(timer);
|
|
3793
2844
|
}, [autoplayMs, items.length]);
|
|
3794
2845
|
if (items.length === 0) return null;
|
|
3795
|
-
const
|
|
2846
|
+
const active = items[Math.min(index, items.length - 1)];
|
|
3796
2847
|
const goTo = (next) => {
|
|
3797
2848
|
interacted.current = true;
|
|
3798
2849
|
setIndex((next + items.length) % items.length);
|
|
@@ -3814,16 +2865,16 @@ function MediaCarousel({
|
|
|
3814
2865
|
`${item.title}-${i}`
|
|
3815
2866
|
)),
|
|
3816
2867
|
/* @__PURE__ */ jsx("div", { className: `absolute inset-0 -z-10 ${overlayClass}` }),
|
|
3817
|
-
/* @__PURE__ */ jsx("div", { className: `flex h-full px-5 py-16 sm:px-10 lg:px-16 ${alignClass[
|
|
3818
|
-
|
|
3819
|
-
/* @__PURE__ */ jsx("h1", { className: "sf-heading text-5xl font-normal leading-[0.95] sm:text-7xl lg:text-8xl", children:
|
|
3820
|
-
|
|
3821
|
-
|
|
2868
|
+
/* @__PURE__ */ jsx("div", { className: `flex h-full px-5 py-16 sm:px-10 lg:px-16 ${alignClass[active.align ?? "start"]}`, children: /* @__PURE__ */ jsxs("div", { className: "my-auto max-w-2xl text-white drop-shadow-md", children: [
|
|
2869
|
+
active.eyebrow && /* @__PURE__ */ jsx("p", { className: "mb-4 text-xs font-semibold uppercase tracking-[0.24em] text-white/80", children: active.eyebrow }),
|
|
2870
|
+
/* @__PURE__ */ jsx("h1", { className: "sf-heading text-5xl font-normal leading-[0.95] sm:text-7xl lg:text-8xl", children: active.title }),
|
|
2871
|
+
active.subtitle && /* @__PURE__ */ jsx("p", { className: "mt-5 max-w-xl text-base leading-8 text-white/88 sm:text-lg", children: active.subtitle }),
|
|
2872
|
+
active.cta && /* @__PURE__ */ jsx(
|
|
3822
2873
|
Link,
|
|
3823
2874
|
{
|
|
3824
|
-
to:
|
|
2875
|
+
to: active.href ?? "/catalog",
|
|
3825
2876
|
className: "mt-8 inline-flex border border-white/75 px-6 py-3 text-xs font-semibold uppercase tracking-[0.18em] text-white transition hover:bg-white hover:text-black",
|
|
3826
|
-
children:
|
|
2877
|
+
children: active.cta
|
|
3827
2878
|
}
|
|
3828
2879
|
)
|
|
3829
2880
|
] }) }),
|
|
@@ -4232,12 +3283,12 @@ function FiltersPanel() {
|
|
|
4232
3283
|
] })
|
|
4233
3284
|
] }),
|
|
4234
3285
|
facets.map((facet) => {
|
|
4235
|
-
const
|
|
3286
|
+
const active = catalog.facets[facet.key];
|
|
4236
3287
|
const swatched = facet.values.some((v) => v.swatch);
|
|
4237
3288
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
4238
3289
|
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: facet.label }),
|
|
4239
3290
|
/* @__PURE__ */ jsx("div", { className: swatched ? "flex flex-wrap gap-2" : "space-y-1", children: facet.values.map((v) => {
|
|
4240
|
-
const on =
|
|
3291
|
+
const on = active === v.value;
|
|
4241
3292
|
const label = v.label ?? v.value;
|
|
4242
3293
|
const toggle = () => catalog.setFacet(facet.key, on ? null : v.value);
|
|
4243
3294
|
if (v.swatch) {
|
|
@@ -4486,63 +3537,6 @@ function useProduct(slug) {
|
|
|
4486
3537
|
error
|
|
4487
3538
|
};
|
|
4488
3539
|
}
|
|
4489
|
-
function absolute(ctx, path = ctx.path) {
|
|
4490
|
-
const origin = (ctx.origin ?? currentStaticRenderPass()?.origin ?? seoOrigin()).replace(/\/$/, "");
|
|
4491
|
-
if (!origin) return void 0;
|
|
4492
|
-
return `${origin}${path.startsWith("/") ? path : `/${path}`}`;
|
|
4493
|
-
}
|
|
4494
|
-
function primaryImageUrl(product) {
|
|
4495
|
-
return (product.images?.find((i) => i.isPrimary) ?? product.images?.[0])?.url;
|
|
4496
|
-
}
|
|
4497
|
-
function shareImageUrl(product, ctx) {
|
|
4498
|
-
const url = primaryImageUrl(product);
|
|
4499
|
-
if (!url) return void 0;
|
|
4500
|
-
return ctx.config.imageLoading.transform === "supabase" ? imageVariantUrl(url, { width: 1200, quality: 82 }) : url;
|
|
4501
|
-
}
|
|
4502
|
-
function productJsonLd(product, ctx) {
|
|
4503
|
-
const url = absolute(ctx);
|
|
4504
|
-
const image = shareImageUrl(product, ctx);
|
|
4505
|
-
return {
|
|
4506
|
-
"@context": "https://schema.org",
|
|
4507
|
-
"@type": "Product",
|
|
4508
|
-
name: product.name,
|
|
4509
|
-
...product.description ? { description: product.description } : {},
|
|
4510
|
-
...product.sku ? { sku: product.sku } : {},
|
|
4511
|
-
...image ? { image: [image] } : {},
|
|
4512
|
-
offers: {
|
|
4513
|
-
"@type": "Offer",
|
|
4514
|
-
...url ? { url } : {},
|
|
4515
|
-
price: product.price,
|
|
4516
|
-
priceCurrency: product.currency ?? ctx.config.currency,
|
|
4517
|
-
availability: (product.inventoryCount ?? 0) > 0 ? "https://schema.org/InStock" : "https://schema.org/OutOfStock"
|
|
4518
|
-
}
|
|
4519
|
-
};
|
|
4520
|
-
}
|
|
4521
|
-
function productSeo(product, ctx) {
|
|
4522
|
-
const url = absolute(ctx);
|
|
4523
|
-
const home = absolute(ctx, "/");
|
|
4524
|
-
const catalog = absolute(ctx, ctx.config.catalogPath);
|
|
4525
|
-
return {
|
|
4526
|
-
title: `${product.name} \u2014 ${ctx.config.name}`,
|
|
4527
|
-
description: product.description?.slice(0, 160),
|
|
4528
|
-
canonical: url,
|
|
4529
|
-
image: shareImageUrl(product, ctx),
|
|
4530
|
-
type: "product",
|
|
4531
|
-
jsonLd: [
|
|
4532
|
-
productJsonLd(product, ctx),
|
|
4533
|
-
...home && catalog && url ? [
|
|
4534
|
-
breadcrumbJsonLd([
|
|
4535
|
-
{ name: ctx.config.name, url: home },
|
|
4536
|
-
{ name: "Loja", url: catalog },
|
|
4537
|
-
{ name: product.name, url }
|
|
4538
|
-
])
|
|
4539
|
-
] : []
|
|
4540
|
-
]
|
|
4541
|
-
};
|
|
4542
|
-
}
|
|
4543
|
-
function pageSeo(ctx, input) {
|
|
4544
|
-
return { ...input, canonical: absolute(ctx), type: "website" };
|
|
4545
|
-
}
|
|
4546
3540
|
function QuantityInput({ value, onChange, min = 1, max, testId, incTestId, decTestId }) {
|
|
4547
3541
|
const clamp = (n) => Math.max(min, max != null ? Math.min(n, max) : n);
|
|
4548
3542
|
return /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center rounded-lg border", children: [
|
|
@@ -4667,7 +3661,7 @@ function scalarToString(value) {
|
|
|
4667
3661
|
}
|
|
4668
3662
|
function ProductSpecs({ product }) {
|
|
4669
3663
|
const config = useStorefrontConfig();
|
|
4670
|
-
const extraExcluded =
|
|
3664
|
+
const extraExcluded = React36__default.useMemo(
|
|
4671
3665
|
() => new Set(config.productSpecs?.exclude ?? []),
|
|
4672
3666
|
[config.productSpecs?.exclude]
|
|
4673
3667
|
);
|
|
@@ -5170,7 +4164,7 @@ function RelatedProducts({ product }) {
|
|
|
5170
4164
|
)) })
|
|
5171
4165
|
] });
|
|
5172
4166
|
}
|
|
5173
|
-
function DeliveryEstimator({ compact
|
|
4167
|
+
function DeliveryEstimator({ compact = false }) {
|
|
5174
4168
|
const config = useStorefrontConfig();
|
|
5175
4169
|
const cart = useCartStore();
|
|
5176
4170
|
const delivery = useDeliveryStore();
|
|
@@ -5197,7 +4191,7 @@ function DeliveryEstimator({ compact: compact2 = false }) {
|
|
|
5197
4191
|
"section",
|
|
5198
4192
|
{
|
|
5199
4193
|
"data-testid": TID.deliveryEstimator,
|
|
5200
|
-
className:
|
|
4194
|
+
className: compact ? "rounded-lg border p-3" : "mt-6 rounded-lg border p-4",
|
|
5201
4195
|
children: [
|
|
5202
4196
|
!resolved && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5203
4197
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm font-semibold", children: [
|
|
@@ -5533,11 +4527,11 @@ function ProductDetailPage({ slug }) {
|
|
|
5533
4527
|
] });
|
|
5534
4528
|
}
|
|
5535
4529
|
function buildEnquiryFromForm(fields, values, subject, sourceUrl) {
|
|
5536
|
-
const emailField = fields.find((
|
|
5537
|
-
const phoneField = fields.find((
|
|
5538
|
-
const nameField = fields.find((
|
|
4530
|
+
const emailField = fields.find((f) => f.type === "email");
|
|
4531
|
+
const phoneField = fields.find((f) => f.type === "phone");
|
|
4532
|
+
const nameField = fields.find((f) => f.id === "name") ?? fields.find((f) => (f.type ?? "text") === "text" && f !== emailField && f !== phoneField);
|
|
5539
4533
|
const identity = /* @__PURE__ */ new Set([emailField?.id, phoneField?.id, nameField?.id]);
|
|
5540
|
-
const lines = fields.filter((
|
|
4534
|
+
const lines = fields.filter((f) => !identity.has(f.id)).map((f) => ({ field: f, value: (values[f.id] ?? "").trim() })).filter((entry) => entry.value).map(({ field: field2, value }) => field2.type === "textarea" ? value : `${field2.label}: ${value}`);
|
|
5541
4535
|
return {
|
|
5542
4536
|
productName: subject,
|
|
5543
4537
|
customerName: nameField && values[nameField.id]?.trim() || "Visitante",
|
|
@@ -6392,7 +5386,7 @@ function CollectionHero({
|
|
|
6392
5386
|
{
|
|
6393
5387
|
className: `absolute inset-0 flex flex-col justify-center p-6 text-white sm:p-12 ${OVERLAY_CLASS[overlay]} ${centered ? "items-center text-center" : "items-start text-left"}`,
|
|
6394
5388
|
children: /* @__PURE__ */ jsxs(Reveal, { className: centered ? "max-w-3xl" : "max-w-2xl", children: [
|
|
6395
|
-
logos && logos.length > 0 && /* @__PURE__ */ jsx("div", { className: `mb-6 flex items-center gap-5 ${centered ? "justify-center" : ""}`, children: logos.map((logo, i) => /* @__PURE__ */ jsxs(
|
|
5389
|
+
logos && logos.length > 0 && /* @__PURE__ */ jsx("div", { className: `mb-6 flex items-center gap-5 ${centered ? "justify-center" : ""}`, children: logos.map((logo, i) => /* @__PURE__ */ jsxs(React36__default.Fragment, { children: [
|
|
6396
5390
|
i > 0 && /* @__PURE__ */ jsx("span", { className: "text-2xl font-light opacity-60", "aria-hidden": true, children: "\xD7" }),
|
|
6397
5391
|
/* @__PURE__ */ jsx("img", { src: logo.src, alt: logo.alt, className: "h-10 w-auto object-contain sm:h-14" })
|
|
6398
5392
|
] }, logo.src)) }),
|
|
@@ -7174,10 +6168,10 @@ function StorefrontConfigHost({
|
|
|
7174
6168
|
buyer,
|
|
7175
6169
|
children
|
|
7176
6170
|
}) {
|
|
7177
|
-
const [policy, setPolicy] =
|
|
7178
|
-
const [shipping, setShipping] =
|
|
7179
|
-
const [delivery, setDelivery] =
|
|
7180
|
-
|
|
6171
|
+
const [policy, setPolicy] = React36__default.useState(null);
|
|
6172
|
+
const [shipping, setShipping] = React36__default.useState(null);
|
|
6173
|
+
const [delivery, setDelivery] = React36__default.useState(null);
|
|
6174
|
+
React36__default.useEffect(() => {
|
|
7181
6175
|
let cancelled = false;
|
|
7182
6176
|
let provider;
|
|
7183
6177
|
try {
|
|
@@ -7214,7 +6208,7 @@ function StorefrontConfigHost({
|
|
|
7214
6208
|
cancelled = true;
|
|
7215
6209
|
};
|
|
7216
6210
|
}, [config]);
|
|
7217
|
-
const resolved =
|
|
6211
|
+
const resolved = React36__default.useMemo(
|
|
7218
6212
|
() => applyBuyer(applyDeliveryPolicy(applyShippingSettings(applyStoreSettings(config, policy), shipping), delivery), buyer),
|
|
7219
6213
|
[config, policy, shipping, delivery, buyer?.language, buyer?.country]
|
|
7220
6214
|
);
|
|
@@ -7226,7 +6220,7 @@ function MarketScope({ children }) {
|
|
|
7226
6220
|
const markets = useMarketStore((s2) => s2.markets);
|
|
7227
6221
|
const market = markets.length ? marketForCountry(markets, country) : null;
|
|
7228
6222
|
const prices = useMarketStore((s2) => market ? s2.prices[market.code] : void 0);
|
|
7229
|
-
|
|
6223
|
+
React36__default.useEffect(() => {
|
|
7230
6224
|
useMarketStore.getState().setActive(market);
|
|
7231
6225
|
if (!market || market.isDefault || prices) return;
|
|
7232
6226
|
let provider;
|
|
@@ -7238,11 +6232,11 @@ function MarketScope({ children }) {
|
|
|
7238
6232
|
void provider.getMarketPrices?.(market.code).then((list) => useMarketStore.getState().setPrices(market.code, list)).catch(() => {
|
|
7239
6233
|
});
|
|
7240
6234
|
}, [market?.code, prices]);
|
|
7241
|
-
|
|
6235
|
+
React36__default.useEffect(() => {
|
|
7242
6236
|
if (!market || !market.isDefault && !prices) return;
|
|
7243
6237
|
useCartStore.getState().repriceForMarket();
|
|
7244
6238
|
}, [market?.code, prices]);
|
|
7245
|
-
const value =
|
|
6239
|
+
const value = React36__default.useMemo(() => {
|
|
7246
6240
|
if (!market) return base;
|
|
7247
6241
|
return {
|
|
7248
6242
|
...base,
|
|
@@ -7345,10 +6339,10 @@ function themeToCss(theme, options = {}) {
|
|
|
7345
6339
|
function googleFontsHref(theme) {
|
|
7346
6340
|
if (!theme.font) return null;
|
|
7347
6341
|
const families = theme.font.googleFonts ?? [theme.font.heading, theme.font.body, theme.font.display, theme.font.serif].filter(
|
|
7348
|
-
(
|
|
6342
|
+
(f) => Boolean(f)
|
|
7349
6343
|
);
|
|
7350
6344
|
const unique = [...new Set(families)];
|
|
7351
|
-
const params = unique.map((
|
|
6345
|
+
const params = unique.map((f) => `family=${encodeURIComponent(f).replace(/%20/g, "+")}:wght@300;400;500;600;700`).join("&");
|
|
7352
6346
|
return `https://fonts.googleapis.com/css2?${params}&display=swap`;
|
|
7353
6347
|
}
|
|
7354
6348
|
function StorefrontThemeStyle({
|
|
@@ -7372,7 +6366,7 @@ function StorefrontThemeStyle({
|
|
|
7372
6366
|
document.getElementById(linkId)?.remove();
|
|
7373
6367
|
};
|
|
7374
6368
|
}, [fontsHref, linkId, selector]);
|
|
7375
|
-
return
|
|
6369
|
+
return React36__default.createElement(
|
|
7376
6370
|
"style",
|
|
7377
6371
|
{ "data-sf-theme": theme.name },
|
|
7378
6372
|
themeToCss(theme, { selector })
|
|
@@ -7400,13 +6394,13 @@ function SearchOverlay({ onClose }) {
|
|
|
7400
6394
|
const id = setTimeout(() => setQuery(term.trim()), 220);
|
|
7401
6395
|
return () => clearTimeout(id);
|
|
7402
6396
|
}, [term]);
|
|
7403
|
-
const
|
|
6397
|
+
const active = query.length >= searchConfig.minChars;
|
|
7404
6398
|
const { products, loading } = useProducts(
|
|
7405
|
-
|
|
6399
|
+
active ? { status: "active", search: query, limit: searchConfig.suggestionsLimit } : { status: "active", limit: 0 }
|
|
7406
6400
|
);
|
|
7407
6401
|
const suggestions = useMemo(
|
|
7408
|
-
() =>
|
|
7409
|
-
[
|
|
6402
|
+
() => active ? products.slice(0, searchConfig.suggestionsLimit) : [],
|
|
6403
|
+
[active, products, searchConfig.suggestionsLimit]
|
|
7410
6404
|
);
|
|
7411
6405
|
const submit = (value) => {
|
|
7412
6406
|
const q = value.trim();
|
|
@@ -7464,14 +6458,14 @@ function SearchOverlay({ onClose }) {
|
|
|
7464
6458
|
}
|
|
7465
6459
|
)
|
|
7466
6460
|
] }),
|
|
7467
|
-
|
|
6461
|
+
active && /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-5xl px-4 pb-4 sm:px-6", children: loading && suggestions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "grid gap-4 pb-2 sm:grid-cols-2 lg:grid-cols-4", children: Array.from({ length: Math.min(searchConfig.suggestionsLimit, 4) }).map((_, i) => /* @__PURE__ */ jsx("div", { className: "h-40 animate-pulse rounded-xl bg-muted" }, i)) }) : suggestions.length === 0 ? /* @__PURE__ */ jsxs("p", { className: "py-6 text-center text-sm text-muted-foreground", children: [
|
|
7468
6462
|
searchConfig.emptyLabel,
|
|
7469
6463
|
" \u201C",
|
|
7470
6464
|
query,
|
|
7471
6465
|
"\u201D."
|
|
7472
6466
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7473
6467
|
/* @__PURE__ */ jsx("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4", children: suggestions.map(
|
|
7474
|
-
(product) => searchConfig.renderSuggestion ? /* @__PURE__ */ jsx(
|
|
6468
|
+
(product) => searchConfig.renderSuggestion ? /* @__PURE__ */ jsx(React36__default.Fragment, { children: searchConfig.renderSuggestion(product) }, product.id) : /* @__PURE__ */ jsx(SuggestionCard, { product, onNavigate: onClose }, product.id)
|
|
7475
6469
|
) }),
|
|
7476
6470
|
/* @__PURE__ */ jsx(
|
|
7477
6471
|
"button",
|
|
@@ -7678,11 +6672,11 @@ function HeaderActions({ onMenuClick }) {
|
|
|
7678
6672
|
const openDrawer = useCartStore((s2) => s2.openDrawer);
|
|
7679
6673
|
const session = useSessionStore();
|
|
7680
6674
|
const [accountOpen, setAccountOpen] = useState(false);
|
|
7681
|
-
const accountRef =
|
|
6675
|
+
const accountRef = React36__default.useRef(null);
|
|
7682
6676
|
const pop = usePopOnChange(count);
|
|
7683
6677
|
const firstName = session.name?.split(/\s+/)[0];
|
|
7684
6678
|
const initial2 = (firstName ?? session.email ?? "C").slice(0, 1).toUpperCase();
|
|
7685
|
-
|
|
6679
|
+
React36__default.useEffect(() => {
|
|
7686
6680
|
if (!accountOpen) return;
|
|
7687
6681
|
const onPointerDown = (event) => {
|
|
7688
6682
|
if (!accountRef.current?.contains(event.target)) setAccountOpen(false);
|
|
@@ -7849,7 +6843,7 @@ function MobileMenuDrawer({ open, onClose }) {
|
|
|
7849
6843
|
navigateTo(config.catalogPath);
|
|
7850
6844
|
onClose();
|
|
7851
6845
|
};
|
|
7852
|
-
|
|
6846
|
+
React36__default.useEffect(() => {
|
|
7853
6847
|
if (!open) return;
|
|
7854
6848
|
const onKey = (e) => {
|
|
7855
6849
|
if (e.key === "Escape") onClose();
|
|
@@ -7921,7 +6915,7 @@ function MobileMenuDrawer({ open, onClose }) {
|
|
|
7921
6915
|
}
|
|
7922
6916
|
function StorefrontHeader({ chrome } = {}) {
|
|
7923
6917
|
const config = useStorefrontConfig();
|
|
7924
|
-
const
|
|
6918
|
+
const compact = chrome === "minimal";
|
|
7925
6919
|
const variant = config.theme?.header?.variant ?? "classic";
|
|
7926
6920
|
const scrolled = useScrolled();
|
|
7927
6921
|
const showSearch = config.theme?.header?.showSearch !== false;
|
|
@@ -7935,8 +6929,8 @@ function StorefrontHeader({ chrome } = {}) {
|
|
|
7935
6929
|
style: headerStyle,
|
|
7936
6930
|
children: [
|
|
7937
6931
|
/* @__PURE__ */ jsx(AnnouncementBar, {}),
|
|
7938
|
-
!
|
|
7939
|
-
|
|
6932
|
+
!compact && /* @__PURE__ */ jsx(UtilityBar, {}),
|
|
6933
|
+
compact ? (
|
|
7940
6934
|
// O cabeçalho de um app de pedido: marca, busca, carrinho — e o resto da
|
|
7941
6935
|
// navegação atrás do menu, alcançável e fora do caminho.
|
|
7942
6936
|
/* @__PURE__ */ jsxs("div", { className: "mx-auto flex h-14 max-w-7xl items-center gap-3 px-4 sm:px-6", children: [
|
|
@@ -8518,65 +7512,6 @@ function ContentPage({ slug, page, params }) {
|
|
|
8518
7512
|
] });
|
|
8519
7513
|
}
|
|
8520
7514
|
|
|
8521
|
-
// src/app/serving.ts
|
|
8522
|
-
function resolveStorefrontRoute(config, rawPath) {
|
|
8523
|
-
const resolved = ensureResolved(config);
|
|
8524
|
-
const path = rawPath.split("?")[0] || "/";
|
|
8525
|
-
for (const route of resolved.routes ?? []) {
|
|
8526
|
-
const params = matchPath(route.path, path);
|
|
8527
|
-
if (params) return { kind: "custom", route, params };
|
|
8528
|
-
}
|
|
8529
|
-
const product = matchPath("/product/:slug", path);
|
|
8530
|
-
if (product?.slug) return { kind: "product", params: product };
|
|
8531
|
-
const order = matchPath("/order/:id", path);
|
|
8532
|
-
if (order?.id) return { kind: "order", params: order };
|
|
8533
|
-
if (matchPath("/checkout", path)) return { kind: "checkout" };
|
|
8534
|
-
if (matchPath("/account", path)) return { kind: "account" };
|
|
8535
|
-
if (matchPath("/catalog", path)) return { kind: "catalog" };
|
|
8536
|
-
if (resolved.delivery && matchPath(resolved.delivery.menuPath, path)) return { kind: "menu" };
|
|
8537
|
-
if (resolved.search.mode === "overlay" && matchPath(resolved.search.resultsPath, path)) {
|
|
8538
|
-
return { kind: "searchResults" };
|
|
8539
|
-
}
|
|
8540
|
-
if (matchPath("/privacy", path)) return { kind: "policy", policy: "privacy" };
|
|
8541
|
-
if (matchPath("/terms", path)) return { kind: "policy", policy: "terms" };
|
|
8542
|
-
if (matchPath("/refunds", path)) return { kind: "policy", policy: "returns" };
|
|
8543
|
-
const content = matchContentPage(resolved.pages, path);
|
|
8544
|
-
if (content) return { kind: "content", slug: content.slug, params: content.params };
|
|
8545
|
-
if (path === "/" || path === "") return { kind: "home" };
|
|
8546
|
-
return { kind: "notFound" };
|
|
8547
|
-
}
|
|
8548
|
-
function isKnownPath(config, path) {
|
|
8549
|
-
return resolveStorefrontRoute(config, path).kind !== "notFound";
|
|
8550
|
-
}
|
|
8551
|
-
var STATIC_PATTERNS = ["/", "/catalog", "/menu", "/privacy", "/terms", "/refunds"];
|
|
8552
|
-
function ensureResolved(config) {
|
|
8553
|
-
return "features" in config && "pages" in config ? config : resolveConfig(config);
|
|
8554
|
-
}
|
|
8555
|
-
function isPublicPath(config, path) {
|
|
8556
|
-
const match = resolveStorefrontRoute(config, path);
|
|
8557
|
-
switch (match.kind) {
|
|
8558
|
-
case "checkout":
|
|
8559
|
-
case "account":
|
|
8560
|
-
case "order":
|
|
8561
|
-
return false;
|
|
8562
|
-
case "custom":
|
|
8563
|
-
return match.route.kind !== "checkout" && match.route.kind !== "account" && match.route.chrome !== "focused";
|
|
8564
|
-
default:
|
|
8565
|
-
return true;
|
|
8566
|
-
}
|
|
8567
|
-
}
|
|
8568
|
-
async function storefrontPaths(input) {
|
|
8569
|
-
const resolved = ensureResolved(input.config);
|
|
8570
|
-
const paths = [...STATIC_PATTERNS];
|
|
8571
|
-
for (const route of resolved.routes ?? []) {
|
|
8572
|
-
if (!route.path.includes(":")) paths.push(route.path);
|
|
8573
|
-
}
|
|
8574
|
-
const products = await input.provider.listProducts({ status: "active" });
|
|
8575
|
-
for (const product of products) paths.push(`/product/${product.slug}`);
|
|
8576
|
-
const unique = Array.from(new Set(paths));
|
|
8577
|
-
return input.includePrivate ? unique : unique.filter((p) => isPublicPath(resolved, p));
|
|
8578
|
-
}
|
|
8579
|
-
|
|
8580
7515
|
// src/data/local-orders.ts
|
|
8581
7516
|
var KEY = "fayz.storefront.orders.v1";
|
|
8582
7517
|
var MAX = 25;
|
|
@@ -8602,7 +7537,7 @@ function listLocalOrderIds() {
|
|
|
8602
7537
|
}
|
|
8603
7538
|
|
|
8604
7539
|
// src/lib/errors.ts
|
|
8605
|
-
function
|
|
7540
|
+
function errorMessage4(err) {
|
|
8606
7541
|
if (err instanceof Error) return err.message;
|
|
8607
7542
|
if (err && typeof err === "object" && typeof err.message === "string") {
|
|
8608
7543
|
return err.message;
|
|
@@ -8619,7 +7554,7 @@ function formatDeliveryNotes(address, shippingAddress) {
|
|
|
8619
7554
|
return parts.length > 0 ? `Entrega: ${parts.join(", ")}` : void 0;
|
|
8620
7555
|
}
|
|
8621
7556
|
function isStaleCustomerError(err) {
|
|
8622
|
-
const message =
|
|
7557
|
+
const message = errorMessage4(err).toLowerCase();
|
|
8623
7558
|
return message.includes("customer email mismatch") || message.includes("customer does not belong to this store") || message.includes("customer belongs to another account");
|
|
8624
7559
|
}
|
|
8625
7560
|
async function placeStorefrontOrder({
|
|
@@ -8882,8 +7817,8 @@ function AddressForm({ country, language, value, onChange, onPostalCode, lookup,
|
|
|
8882
7817
|
postalHint()
|
|
8883
7818
|
] }, "postalCode");
|
|
8884
7819
|
}
|
|
8885
|
-
if (row.length === 1) return /* @__PURE__ */ jsx(
|
|
8886
|
-
return /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3", children: cells.map((key) => /* @__PURE__ */ jsx(
|
|
7820
|
+
if (row.length === 1) return /* @__PURE__ */ jsx(React36__default.Fragment, { children: input(specs.get(cells[0])) }, cells[0]);
|
|
7821
|
+
return /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3", children: cells.map((key) => /* @__PURE__ */ jsx(React36__default.Fragment, { children: input(specs.get(key)) }, key)) }, cells.join("-"));
|
|
8887
7822
|
}) });
|
|
8888
7823
|
}
|
|
8889
7824
|
function flag(iso2) {
|
|
@@ -9059,7 +7994,7 @@ function CheckoutSteps({ current, onGoBackTo, omit }) {
|
|
|
9059
7994
|
return /* @__PURE__ */ jsxs("nav", { "data-testid": TID.checkoutSteps, "aria-label": t("checkout.steps.label"), className: "mb-8", children: [
|
|
9060
7995
|
/* @__PURE__ */ jsx("ol", { className: "flex items-center gap-1.5 sm:gap-2", children: steps.map((step, index) => {
|
|
9061
7996
|
const done = step < current;
|
|
9062
|
-
const
|
|
7997
|
+
const active = step === current;
|
|
9063
7998
|
const canGoBack = done && !!onGoBackTo;
|
|
9064
7999
|
const Tag = canGoBack ? "button" : "div";
|
|
9065
8000
|
return (
|
|
@@ -9078,12 +8013,12 @@ function CheckoutSteps({ current, onGoBackTo, omit }) {
|
|
|
9078
8013
|
{
|
|
9079
8014
|
...canGoBack ? { type: "button", onClick: () => onGoBackTo(step) } : {},
|
|
9080
8015
|
"data-testid": TID.checkoutStep(step),
|
|
9081
|
-
"data-state": done ? "done" :
|
|
9082
|
-
"aria-current":
|
|
8016
|
+
"data-state": done ? "done" : active ? "current" : "pending",
|
|
8017
|
+
"aria-current": active ? "step" : void 0,
|
|
9083
8018
|
className: [
|
|
9084
8019
|
"flex min-w-0 items-center gap-2 rounded-lg px-2 py-1.5 text-left transition",
|
|
9085
8020
|
canGoBack ? "hover:bg-muted" : "",
|
|
9086
|
-
|
|
8021
|
+
active ? "text-foreground" : done ? "text-foreground" : "text-muted-foreground"
|
|
9087
8022
|
].join(" "),
|
|
9088
8023
|
children: [
|
|
9089
8024
|
/* @__PURE__ */ jsx(
|
|
@@ -9091,12 +8026,12 @@ function CheckoutSteps({ current, onGoBackTo, omit }) {
|
|
|
9091
8026
|
{
|
|
9092
8027
|
className: [
|
|
9093
8028
|
"grid h-7 w-7 shrink-0 place-items-center rounded-full border text-xs font-semibold",
|
|
9094
|
-
done ? "border-primary bg-primary text-primary-foreground" :
|
|
8029
|
+
done ? "border-primary bg-primary text-primary-foreground" : active ? "border-primary bg-background text-primary" : "border-muted-foreground/30 bg-background"
|
|
9095
8030
|
].join(" "),
|
|
9096
8031
|
children: done ? /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5" }) : index + 1
|
|
9097
8032
|
}
|
|
9098
8033
|
),
|
|
9099
|
-
/* @__PURE__ */ jsx("span", { className: `hidden truncate text-sm sm:inline ${
|
|
8034
|
+
/* @__PURE__ */ jsx("span", { className: `hidden truncate text-sm sm:inline ${active ? "font-semibold" : ""}`, children: t(LABELS2[step]) })
|
|
9100
8035
|
]
|
|
9101
8036
|
}
|
|
9102
8037
|
),
|
|
@@ -9239,13 +8174,13 @@ function CardBrick({ publicKey, amount, email, onSubmit, onError }) {
|
|
|
9239
8174
|
var POLL_MS = 3e3;
|
|
9240
8175
|
var RESUME_KEY = "fz.checkout.resume";
|
|
9241
8176
|
function useExpiry(expiresAt) {
|
|
9242
|
-
const target =
|
|
8177
|
+
const target = React36__default.useMemo(() => {
|
|
9243
8178
|
if (!expiresAt) return null;
|
|
9244
8179
|
const t = new Date(expiresAt).getTime();
|
|
9245
8180
|
return Number.isFinite(t) ? t : null;
|
|
9246
8181
|
}, [expiresAt]);
|
|
9247
|
-
const [now, setNow] =
|
|
9248
|
-
|
|
8182
|
+
const [now, setNow] = React36__default.useState(() => Date.now());
|
|
8183
|
+
React36__default.useEffect(() => {
|
|
9249
8184
|
if (target === null) return;
|
|
9250
8185
|
const id = setInterval(() => setNow(Date.now()), 1e3);
|
|
9251
8186
|
return () => clearInterval(id);
|
|
@@ -9835,7 +8770,7 @@ function ContactSummary({ name, email, phone, document: document2, onEdit, onSig
|
|
|
9835
8770
|
function toShippingAddress(form, country) {
|
|
9836
8771
|
const schema = getCountrySchema(country);
|
|
9837
8772
|
const isBrazil = schema.iso2 === "BR";
|
|
9838
|
-
const has = (key) => schema.fields.some((
|
|
8773
|
+
const has = (key) => schema.fields.some((f) => f.key === key);
|
|
9839
8774
|
return {
|
|
9840
8775
|
postalCode: isBrazil ? form.zip.trim() : normalizePostalCode(form.zip, country),
|
|
9841
8776
|
street: form.street.trim(),
|
|
@@ -9864,7 +8799,7 @@ var PAYMENT_LABELS = {
|
|
|
9864
8799
|
};
|
|
9865
8800
|
var BRAZIL_ONLY = ["pix", "boleto"];
|
|
9866
8801
|
function placeOrderMessage(err, t) {
|
|
9867
|
-
const message =
|
|
8802
|
+
const message = errorMessage4(err);
|
|
9868
8803
|
if (/customer (email mismatch|does not belong|belongs to another)/i.test(message)) {
|
|
9869
8804
|
return t("error.sessionMismatch");
|
|
9870
8805
|
}
|
|
@@ -9941,7 +8876,7 @@ function CheckoutPage() {
|
|
|
9941
8876
|
district: "",
|
|
9942
8877
|
state: ""
|
|
9943
8878
|
});
|
|
9944
|
-
|
|
8879
|
+
React36__default.useEffect(() => {
|
|
9945
8880
|
if (!known.ready) return;
|
|
9946
8881
|
setForm((current) => ({
|
|
9947
8882
|
...current,
|
|
@@ -9957,7 +8892,7 @@ function CheckoutPage() {
|
|
|
9957
8892
|
}));
|
|
9958
8893
|
}, [known.ready, known.phone, known.document, known.address]);
|
|
9959
8894
|
const [step, setStep] = useState(resume ? 3 : 1);
|
|
9960
|
-
const reportedStart =
|
|
8895
|
+
const reportedStart = React36__default.useRef(false);
|
|
9961
8896
|
useEffect(() => {
|
|
9962
8897
|
if (reportedStart.current) return;
|
|
9963
8898
|
reportedStart.current = true;
|
|
@@ -9970,7 +8905,7 @@ function CheckoutPage() {
|
|
|
9970
8905
|
});
|
|
9971
8906
|
}
|
|
9972
8907
|
}, []);
|
|
9973
|
-
const reportedStep =
|
|
8908
|
+
const reportedStep = React36__default.useRef(null);
|
|
9974
8909
|
useEffect(() => {
|
|
9975
8910
|
if (reportedStep.current === step) return;
|
|
9976
8911
|
reportedStep.current = step;
|
|
@@ -9979,7 +8914,7 @@ function CheckoutPage() {
|
|
|
9979
8914
|
}, [step]);
|
|
9980
8915
|
const [contactKnown, setContactKnown] = useState(false);
|
|
9981
8916
|
const [editingContact, setEditingContact] = useState(false);
|
|
9982
|
-
const skippedContact =
|
|
8917
|
+
const skippedContact = React36__default.useRef(false);
|
|
9983
8918
|
const fulfillmentType = useDeliveryStore((s2) => s2.fulfillmentType);
|
|
9984
8919
|
const scheduledFor = useDeliveryStore((s2) => s2.scheduledFor);
|
|
9985
8920
|
const deliveryReference = useDeliveryStore((s2) => {
|
|
@@ -10008,7 +8943,7 @@ function CheckoutPage() {
|
|
|
10008
8943
|
const [applyingDiscount, setApplyingDiscount] = useState(false);
|
|
10009
8944
|
const [showSignin, setShowSignin] = useState(false);
|
|
10010
8945
|
const [placing, setPlacing] = useState(false);
|
|
10011
|
-
const leaving =
|
|
8946
|
+
const leaving = React36__default.useRef(false);
|
|
10012
8947
|
const [zipLookup, setZipLookup] = useState("idle");
|
|
10013
8948
|
const subtotal = selectSubtotal(cart);
|
|
10014
8949
|
const discountTotal = selectDiscountTotal(cart);
|
|
@@ -10016,7 +8951,7 @@ function CheckoutPage() {
|
|
|
10016
8951
|
const shipping = isPickup ? 0 : shippingRaw;
|
|
10017
8952
|
const total = selectTotal(cart, config) - (isPickup ? shippingRaw : 0);
|
|
10018
8953
|
const checkoutSlotContext = { subtotal, total };
|
|
10019
|
-
const checkoutSessionInput =
|
|
8954
|
+
const checkoutSessionInput = React36__default.useMemo(() => ({
|
|
10020
8955
|
items: cart.lines.map((line) => ({
|
|
10021
8956
|
productId: line.productId,
|
|
10022
8957
|
variantId: line.variantId ?? null,
|
|
@@ -10193,7 +9128,7 @@ function CheckoutPage() {
|
|
|
10193
9128
|
cancelled = true;
|
|
10194
9129
|
};
|
|
10195
9130
|
}, [session.customerId]);
|
|
10196
|
-
const shownCountry =
|
|
9131
|
+
const shownCountry = React36__default.useRef(country);
|
|
10197
9132
|
useEffect(() => {
|
|
10198
9133
|
if (shownCountry.current === country) return;
|
|
10199
9134
|
shownCountry.current = country;
|
|
@@ -10344,7 +9279,7 @@ function CheckoutPage() {
|
|
|
10344
9279
|
if (errors.postalCode || errors.street || errors.city) return fail(t("error.address"), errors.postalCode ? TID.checkoutZip : TID.checkoutStreet);
|
|
10345
9280
|
if (errors.complement) return fail(t("error.complement"), "checkout-complement");
|
|
10346
9281
|
if (errors.region) {
|
|
10347
|
-
const label = countrySchema.fields.find((
|
|
9282
|
+
const label = countrySchema.fields.find((f) => f.key === "region")?.label[config.language] ?? "";
|
|
10348
9283
|
return fail(t("error.region", { label: label.toLowerCase() }), "checkout-state");
|
|
10349
9284
|
}
|
|
10350
9285
|
return true;
|
|
@@ -11060,15 +9995,15 @@ function StoreCover({ onShowHours, onOpenAccount }) {
|
|
|
11060
9995
|
] })
|
|
11061
9996
|
] }),
|
|
11062
9997
|
modes.length > 1 && /* @__PURE__ */ jsx("div", { className: "mt-4 flex gap-1", children: modes.map((mode) => {
|
|
11063
|
-
const
|
|
9998
|
+
const active = type === mode;
|
|
11064
9999
|
return /* @__PURE__ */ jsx(
|
|
11065
10000
|
"button",
|
|
11066
10001
|
{
|
|
11067
10002
|
type: "button",
|
|
11068
10003
|
"data-testid": TID.fulfillmentMode(mode),
|
|
11069
|
-
"aria-pressed":
|
|
10004
|
+
"aria-pressed": active,
|
|
11070
10005
|
onClick: () => choose(mode),
|
|
11071
|
-
className: `rounded-full px-5 py-2 text-sm font-semibold transition ${
|
|
10006
|
+
className: `rounded-full px-5 py-2 text-sm font-semibold transition ${active ? "bg-white text-neutral-900" : "text-white/80"}`,
|
|
11072
10007
|
children: mode === "pickup" ? "Retirada" : "Entrega"
|
|
11073
10008
|
},
|
|
11074
10009
|
mode
|
|
@@ -11106,8 +10041,8 @@ function AddressStrip({
|
|
|
11106
10041
|
const money = (v) => formatMoney(v, config.currency, config.locale);
|
|
11107
10042
|
const subtotal = selectSubtotal(useCartStore());
|
|
11108
10043
|
const resolve = useDeliveryStore((s2) => s2.resolve);
|
|
11109
|
-
const quotedOnce =
|
|
11110
|
-
|
|
10044
|
+
const quotedOnce = React36__default.useRef(false);
|
|
10045
|
+
React36__default.useEffect(() => {
|
|
11111
10046
|
if (quotedOnce.current || isPickup) return;
|
|
11112
10047
|
if (delivery.status !== "idle" || delivery.options.length > 0 || !delivery.postalCode) return;
|
|
11113
10048
|
quotedOnce.current = true;
|
|
@@ -11169,17 +10104,17 @@ function MenuToolbar({
|
|
|
11169
10104
|
onQuery,
|
|
11170
10105
|
autoFocusSearch
|
|
11171
10106
|
}) {
|
|
11172
|
-
const inputRef =
|
|
11173
|
-
const [
|
|
11174
|
-
|
|
10107
|
+
const inputRef = React36__default.useRef(null);
|
|
10108
|
+
const [active, setActive] = React36__default.useState(null);
|
|
10109
|
+
React36__default.useEffect(() => {
|
|
11175
10110
|
setActive(
|
|
11176
10111
|
(current) => current && sections.some((s2) => s2.slug === current) ? current : sections[0]?.slug ?? null
|
|
11177
10112
|
);
|
|
11178
10113
|
}, [sections]);
|
|
11179
|
-
|
|
10114
|
+
React36__default.useEffect(() => {
|
|
11180
10115
|
if (autoFocusSearch) inputRef.current?.focus();
|
|
11181
10116
|
}, [autoFocusSearch]);
|
|
11182
|
-
|
|
10117
|
+
React36__default.useEffect(() => {
|
|
11183
10118
|
if (typeof IntersectionObserver === "undefined") return;
|
|
11184
10119
|
const seen = /* @__PURE__ */ new Map();
|
|
11185
10120
|
const observer = new IntersectionObserver(
|
|
@@ -11247,7 +10182,7 @@ function MenuToolbar({
|
|
|
11247
10182
|
"aria-label": "Categorias",
|
|
11248
10183
|
className: "mx-auto w-full max-w-3xl overflow-x-auto pb-3 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
11249
10184
|
children: /* @__PURE__ */ jsx("ul", { className: "flex w-max gap-2 px-4", children: sections.map((section) => {
|
|
11250
|
-
const on =
|
|
10185
|
+
const on = active === section.slug;
|
|
11251
10186
|
return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
|
|
11252
10187
|
"button",
|
|
11253
10188
|
{
|
|
@@ -11366,10 +10301,10 @@ function ItemSheet({
|
|
|
11366
10301
|
}) {
|
|
11367
10302
|
const config = useStorefrontConfig();
|
|
11368
10303
|
const money = (v) => formatMoney(v, config.currency, config.locale);
|
|
11369
|
-
const groups =
|
|
11370
|
-
const [options, setOptions] =
|
|
11371
|
-
const [notes, setNotes] =
|
|
11372
|
-
const [quantity, setQuantity] =
|
|
10304
|
+
const groups = React36__default.useMemo(() => getProductOptionGroups(product), [product]);
|
|
10305
|
+
const [options, setOptions] = React36__default.useState({});
|
|
10306
|
+
const [notes, setNotes] = React36__default.useState("");
|
|
10307
|
+
const [quantity, setQuantity] = React36__default.useState(1);
|
|
11373
10308
|
const image = product.images?.find((i) => i.isPrimary) ?? product.images?.[0];
|
|
11374
10309
|
const stock = product.inventoryCount;
|
|
11375
10310
|
const missing = groups.filter((g) => !options[g.label]);
|
|
@@ -11563,8 +10498,8 @@ function ScheduleSheet({ onClose }) {
|
|
|
11563
10498
|
const scheduledFor = useDeliveryStore((s2) => s2.scheduledFor);
|
|
11564
10499
|
const setScheduledFor = useDeliveryStore((s2) => s2.setScheduledFor);
|
|
11565
10500
|
const timezone = useServiceStore((s2) => s2.service?.timezone) ?? "America/Sao_Paulo";
|
|
11566
|
-
const [slots, setSlots] =
|
|
11567
|
-
|
|
10501
|
+
const [slots, setSlots] = React36__default.useState(null);
|
|
10502
|
+
React36__default.useEffect(() => {
|
|
11568
10503
|
let alive = true;
|
|
11569
10504
|
void (async () => {
|
|
11570
10505
|
const rows = await getShopProvider()?.listScheduleSlots?.(fulfillmentType) ?? [];
|
|
@@ -11574,7 +10509,7 @@ function ScheduleSheet({ onClose }) {
|
|
|
11574
10509
|
alive = false;
|
|
11575
10510
|
};
|
|
11576
10511
|
}, [fulfillmentType]);
|
|
11577
|
-
const days =
|
|
10512
|
+
const days = React36__default.useMemo(() => {
|
|
11578
10513
|
const fmtDay = new Intl.DateTimeFormat("pt-BR", {
|
|
11579
10514
|
weekday: "long",
|
|
11580
10515
|
day: "2-digit",
|
|
@@ -11627,18 +10562,18 @@ function ScheduleSheet({ onClose }) {
|
|
|
11627
10562
|
days.map(([day, daySlots]) => /* @__PURE__ */ jsxs("div", { className: "mb-5", children: [
|
|
11628
10563
|
/* @__PURE__ */ jsx("h3", { className: "mb-2 text-sm font-semibold capitalize", children: day }),
|
|
11629
10564
|
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-2", children: daySlots.map((slot) => {
|
|
11630
|
-
const
|
|
10565
|
+
const active = scheduledFor === slot.startsAt;
|
|
11631
10566
|
return /* @__PURE__ */ jsxs(
|
|
11632
10567
|
"button",
|
|
11633
10568
|
{
|
|
11634
10569
|
type: "button",
|
|
11635
10570
|
"data-testid": TID.scheduleSlot(slot.startsAt),
|
|
11636
|
-
"aria-pressed":
|
|
10571
|
+
"aria-pressed": active,
|
|
11637
10572
|
onClick: () => {
|
|
11638
10573
|
setScheduledFor(slot.startsAt);
|
|
11639
10574
|
onClose();
|
|
11640
10575
|
},
|
|
11641
|
-
className: `rounded-lg border px-3 py-2 text-sm ${
|
|
10576
|
+
className: `rounded-lg border px-3 py-2 text-sm ${active ? "border-primary font-medium" : "border-border"}`,
|
|
11642
10577
|
children: [
|
|
11643
10578
|
fmtTime.format(new Date(slot.startsAt)),
|
|
11644
10579
|
" \u2013 ",
|
|
@@ -11660,8 +10595,8 @@ function hhmm(time) {
|
|
|
11660
10595
|
}
|
|
11661
10596
|
function ServiceHoursModal({ onClose }) {
|
|
11662
10597
|
const fulfillmentType = useServiceStore((s2) => s2.fulfillmentType);
|
|
11663
|
-
const [hours, setHours] =
|
|
11664
|
-
|
|
10598
|
+
const [hours, setHours] = React36__default.useState(null);
|
|
10599
|
+
React36__default.useEffect(() => {
|
|
11665
10600
|
let alive = true;
|
|
11666
10601
|
void (async () => {
|
|
11667
10602
|
const rows = await getShopProvider()?.listServiceHours?.(fulfillmentType) ?? [];
|
|
@@ -11671,7 +10606,7 @@ function ServiceHoursModal({ onClose }) {
|
|
|
11671
10606
|
alive = false;
|
|
11672
10607
|
};
|
|
11673
10608
|
}, [fulfillmentType]);
|
|
11674
|
-
const byDay =
|
|
10609
|
+
const byDay = React36__default.useMemo(() => {
|
|
11675
10610
|
const map = /* @__PURE__ */ new Map();
|
|
11676
10611
|
for (const h of hours ?? []) {
|
|
11677
10612
|
const list = map.get(h.weekday) ?? [];
|
|
@@ -11756,7 +10691,7 @@ function AddressSheet({ onClose, onSignIn }) {
|
|
|
11756
10691
|
const unsavedCurrent = current && !saved.some((a) => a.id === selectedId) ? current : null;
|
|
11757
10692
|
const fromAccount = accountBook.filter((a) => !saved.some((b) => normalizePostalCode(b.postalCode) === normalizePostalCode(a.postalCode) && b.number.trim().toLowerCase() === (a.number ?? "").trim().toLowerCase()));
|
|
11758
10693
|
const nothingToList = saved.length === 0 && !unsavedCurrent && fromAccount.length === 0 && !customerId;
|
|
11759
|
-
const [editing, setEditing] =
|
|
10694
|
+
const [editing, setEditing] = React36__default.useState(
|
|
11760
10695
|
nothingToList && !onSignIn ? {} : null
|
|
11761
10696
|
);
|
|
11762
10697
|
function pickAccountAddress(a) {
|
|
@@ -11775,13 +10710,13 @@ function AddressSheet({ onClose, onSignIn }) {
|
|
|
11775
10710
|
void selectAddress(id, subtotal);
|
|
11776
10711
|
onClose();
|
|
11777
10712
|
}
|
|
11778
|
-
const closeRef =
|
|
10713
|
+
const closeRef = React36__default.useRef(() => {
|
|
11779
10714
|
});
|
|
11780
10715
|
closeRef.current = () => {
|
|
11781
10716
|
if (editing && !nothingToList) setEditing(null);
|
|
11782
10717
|
else onClose();
|
|
11783
10718
|
};
|
|
11784
|
-
|
|
10719
|
+
React36__default.useEffect(() => {
|
|
11785
10720
|
const onKey = (e) => {
|
|
11786
10721
|
if (e.key === "Escape") closeRef.current();
|
|
11787
10722
|
};
|
|
@@ -11962,8 +10897,8 @@ function AddressLines({ address }) {
|
|
|
11962
10897
|
] });
|
|
11963
10898
|
}
|
|
11964
10899
|
function useAccountAddresses(customerId) {
|
|
11965
|
-
const [rows, setRows] =
|
|
11966
|
-
|
|
10900
|
+
const [rows, setRows] = React36__default.useState([]);
|
|
10901
|
+
React36__default.useEffect(() => {
|
|
11967
10902
|
if (!customerId) {
|
|
11968
10903
|
setRows([]);
|
|
11969
10904
|
return;
|
|
@@ -11991,24 +10926,24 @@ function AddressForm2({ onDone, initial: initial2, replaces }) {
|
|
|
11991
10926
|
const storeError = useDeliveryStore((s2) => s2.error);
|
|
11992
10927
|
const refusedZone = useDeliveryStore((s2) => s2.refusedZone);
|
|
11993
10928
|
const subtotal = selectSubtotal(useCartStore());
|
|
11994
|
-
const [cep, setCep] =
|
|
11995
|
-
const [number, setNumber] =
|
|
11996
|
-
const [complement, setComplement] =
|
|
11997
|
-
const [reference, setReference] =
|
|
11998
|
-
const [label, setLabel] =
|
|
11999
|
-
const [touched, setTouched] =
|
|
12000
|
-
const numberRef =
|
|
10929
|
+
const [cep, setCep] = React36__default.useState(initial2?.postalCode ? formatPostalCode(initial2.postalCode) : "");
|
|
10930
|
+
const [number, setNumber] = React36__default.useState(initial2?.number ?? "");
|
|
10931
|
+
const [complement, setComplement] = React36__default.useState(initial2?.complement ?? "");
|
|
10932
|
+
const [reference, setReference] = React36__default.useState(initial2?.reference ?? "");
|
|
10933
|
+
const [label, setLabel] = React36__default.useState(initial2?.label ?? "");
|
|
10934
|
+
const [touched, setTouched] = React36__default.useState(false);
|
|
10935
|
+
const numberRef = React36__default.useRef(null);
|
|
12001
10936
|
const digits = normalizePostalCode(cep);
|
|
12002
10937
|
const found = Boolean(looked) && normalizePostalCode(looked.postalCode) === digits;
|
|
12003
|
-
|
|
10938
|
+
React36__default.useEffect(() => {
|
|
12004
10939
|
if (found) numberRef.current?.focus();
|
|
12005
10940
|
}, [found]);
|
|
12006
10941
|
async function lookUp() {
|
|
12007
10942
|
if (digits.length !== 8) return;
|
|
12008
10943
|
await resolve(digits, subtotal);
|
|
12009
10944
|
}
|
|
12010
|
-
const prefilled =
|
|
12011
|
-
|
|
10945
|
+
const prefilled = React36__default.useRef(false);
|
|
10946
|
+
React36__default.useEffect(() => {
|
|
12012
10947
|
if (prefilled.current || !initial2?.postalCode) return;
|
|
12013
10948
|
prefilled.current = true;
|
|
12014
10949
|
if (!found) void lookUp();
|
|
@@ -12224,7 +11159,7 @@ function AccountDrawer({ onClose, onSignIn, onAddresses, onShowHours }) {
|
|
|
12224
11159
|
const session = useSessionStore();
|
|
12225
11160
|
const signedIn = Boolean(session.email);
|
|
12226
11161
|
const name = session.name || session.email?.split("@")[0] || "";
|
|
12227
|
-
|
|
11162
|
+
React36__default.useEffect(() => {
|
|
12228
11163
|
const onKey = (event) => {
|
|
12229
11164
|
if (event.key === "Escape") onClose();
|
|
12230
11165
|
};
|
|
@@ -12308,8 +11243,8 @@ function AccountDrawer({ onClose, onSignIn, onAddresses, onShowHours }) {
|
|
|
12308
11243
|
function MenuPage() {
|
|
12309
11244
|
const config = useStorefrontConfig();
|
|
12310
11245
|
const addItem = useCartStore((s2) => s2.addItem);
|
|
12311
|
-
const [openProduct, setOpenProduct] =
|
|
12312
|
-
|
|
11246
|
+
const [openProduct, setOpenProduct] = React36__default.useState(null);
|
|
11247
|
+
React36__default.useEffect(() => {
|
|
12313
11248
|
if (!openProduct) return;
|
|
12314
11249
|
trackStorefront("product_viewed", {
|
|
12315
11250
|
product_id: openProduct.id,
|
|
@@ -12320,18 +11255,18 @@ function MenuPage() {
|
|
|
12320
11255
|
surface: "menu_sheet"
|
|
12321
11256
|
});
|
|
12322
11257
|
}, [openProduct?.id]);
|
|
12323
|
-
const [showHours, setShowHours] =
|
|
12324
|
-
const [showClosed, setShowClosed] =
|
|
12325
|
-
const [showAddress, setShowAddress] =
|
|
12326
|
-
const [showAccount, setShowAccount] =
|
|
12327
|
-
const [showSignIn, setShowSignIn] =
|
|
12328
|
-
const [showSchedule, setShowSchedule] =
|
|
12329
|
-
const [query, setQuery] =
|
|
11258
|
+
const [showHours, setShowHours] = React36__default.useState(false);
|
|
11259
|
+
const [showClosed, setShowClosed] = React36__default.useState(false);
|
|
11260
|
+
const [showAddress, setShowAddress] = React36__default.useState(false);
|
|
11261
|
+
const [showAccount, setShowAccount] = React36__default.useState(false);
|
|
11262
|
+
const [showSignIn, setShowSignIn] = React36__default.useState(false);
|
|
11263
|
+
const [showSchedule, setShowSchedule] = React36__default.useState(false);
|
|
11264
|
+
const [query, setQuery] = React36__default.useState("");
|
|
12330
11265
|
const serviceState = useServiceStore();
|
|
12331
11266
|
const refreshService = useServiceStore((s2) => s2.refresh);
|
|
12332
11267
|
const paused = Boolean(config.delivery?.paused);
|
|
12333
11268
|
const isOpen = selectIsOpen(serviceState) && !paused;
|
|
12334
|
-
|
|
11269
|
+
React36__default.useEffect(() => {
|
|
12335
11270
|
void refreshService();
|
|
12336
11271
|
}, [refreshService]);
|
|
12337
11272
|
const cart = useCartStore();
|
|
@@ -12346,14 +11281,14 @@ function MenuPage() {
|
|
|
12346
11281
|
}
|
|
12347
11282
|
run();
|
|
12348
11283
|
}
|
|
12349
|
-
const products = useLoader(
|
|
12350
|
-
const categories = useLoader(
|
|
12351
|
-
const featured = useLoader(
|
|
11284
|
+
const products = useLoader(MENU_DATA_NEEDS.products.loader, MENU_DATA_NEEDS.products.params);
|
|
11285
|
+
const categories = useLoader(MENU_DATA_NEEDS.categories.loader, MENU_DATA_NEEDS.categories.params);
|
|
11286
|
+
const featured = useLoader(MENU_DATA_NEEDS.featured.loader, MENU_DATA_NEEDS.featured.params);
|
|
12352
11287
|
const featuredPending = featured.status === "loading" || featured.status === "idle";
|
|
12353
11288
|
const loading = products.status === "loading" || products.status === "idle";
|
|
12354
11289
|
const items = products.data ?? [];
|
|
12355
11290
|
const cats = categories.data ?? [];
|
|
12356
|
-
const allSections =
|
|
11291
|
+
const allSections = React36__default.useMemo(() => {
|
|
12357
11292
|
const byCategory = /* @__PURE__ */ new Map();
|
|
12358
11293
|
const loose = [];
|
|
12359
11294
|
for (const p of items) {
|
|
@@ -12381,7 +11316,7 @@ function MenuPage() {
|
|
|
12381
11316
|
}
|
|
12382
11317
|
return ordered;
|
|
12383
11318
|
}, [items, cats]);
|
|
12384
|
-
const highlights =
|
|
11319
|
+
const highlights = React36__default.useMemo(
|
|
12385
11320
|
() => pickHighlights(items, {
|
|
12386
11321
|
listingFeaturedIds: featured.data?.listing,
|
|
12387
11322
|
menuFeaturedIds: featured.data?.menu,
|
|
@@ -12390,7 +11325,7 @@ function MenuPage() {
|
|
|
12390
11325
|
[items, featured.data, config.delivery?.highlightSlugs]
|
|
12391
11326
|
);
|
|
12392
11327
|
const normalized = query.trim().toLowerCase();
|
|
12393
|
-
const sections =
|
|
11328
|
+
const sections = React36__default.useMemo(() => {
|
|
12394
11329
|
if (!normalized) return allSections;
|
|
12395
11330
|
return allSections.map((section) => ({
|
|
12396
11331
|
...section,
|
|
@@ -12563,7 +11498,7 @@ function MenuPage() {
|
|
|
12563
11498
|
);
|
|
12564
11499
|
}
|
|
12565
11500
|
function BottomBarSpace() {
|
|
12566
|
-
|
|
11501
|
+
React36__default.useEffect(() => {
|
|
12567
11502
|
const root = document.documentElement;
|
|
12568
11503
|
root.style.setProperty("--fayz-bottom-bar", "4.5rem");
|
|
12569
11504
|
return () => {
|
|
@@ -12704,20 +11639,20 @@ var GRID_COLS = {
|
|
|
12704
11639
|
3: "sm:grid-cols-3",
|
|
12705
11640
|
4: "sm:grid-cols-4"
|
|
12706
11641
|
};
|
|
12707
|
-
function OrderTrackingTimeline({ order, compact
|
|
11642
|
+
function OrderTrackingTimeline({ order, compact = false }) {
|
|
12708
11643
|
const steps = orderTrackingSteps(order);
|
|
12709
11644
|
return /* @__PURE__ */ jsx(
|
|
12710
11645
|
"ol",
|
|
12711
11646
|
{
|
|
12712
11647
|
"data-testid": TID.orderTracking,
|
|
12713
|
-
className: `grid ${
|
|
11648
|
+
className: `grid ${compact ? "gap-2" : "gap-3"} ${GRID_COLS[steps.length] ?? "sm:grid-cols-4"}`,
|
|
12714
11649
|
"aria-label": "Acompanhamento do pedido",
|
|
12715
11650
|
children: steps.map((step) => {
|
|
12716
11651
|
const Icon2 = step.icon;
|
|
12717
11652
|
const cancelled = step.state === "cancelled";
|
|
12718
11653
|
const done = step.state === "complete";
|
|
12719
11654
|
const current = step.state === "current";
|
|
12720
|
-
const
|
|
11655
|
+
const active = done || current;
|
|
12721
11656
|
return /* @__PURE__ */ jsx(
|
|
12722
11657
|
"li",
|
|
12723
11658
|
{
|
|
@@ -12725,8 +11660,8 @@ function OrderTrackingTimeline({ order, compact: compact2 = false }) {
|
|
|
12725
11660
|
"data-state": step.state,
|
|
12726
11661
|
className: [
|
|
12727
11662
|
"relative min-w-0 rounded-xl border p-3",
|
|
12728
|
-
cancelled ? "border-destructive/40 bg-destructive/10" :
|
|
12729
|
-
|
|
11663
|
+
cancelled ? "border-destructive/40 bg-destructive/10" : active ? "border-primary/35 bg-primary/5" : "bg-muted/20 text-muted-foreground",
|
|
11664
|
+
compact ? "text-xs" : "text-sm"
|
|
12730
11665
|
].join(" "),
|
|
12731
11666
|
children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
|
|
12732
11667
|
/* @__PURE__ */ jsx(
|
|
@@ -12758,7 +11693,7 @@ var menuItems = [
|
|
|
12758
11693
|
{ id: "addresses", label: "Endere\xE7os", icon: MapPin },
|
|
12759
11694
|
{ id: "payments", label: "Pagamentos", icon: CreditCard }
|
|
12760
11695
|
];
|
|
12761
|
-
function CustomerAccountShell({ title, subtitle, active
|
|
11696
|
+
function CustomerAccountShell({ title, subtitle, active, onSelect, children }) {
|
|
12762
11697
|
const config = useStorefrontConfig();
|
|
12763
11698
|
const session = useSessionStore();
|
|
12764
11699
|
const displayName = session.name || session.email?.split("@")[0] || "Cliente";
|
|
@@ -12783,7 +11718,7 @@ function CustomerAccountShell({ title, subtitle, active: active2, onSelect, chil
|
|
|
12783
11718
|
] }),
|
|
12784
11719
|
/* @__PURE__ */ jsx("nav", { "data-testid": TID.customerAccountMenu, className: "mt-4 space-y-1", "aria-label": "\xC1rea do cliente", children: menuItems.map((item) => {
|
|
12785
11720
|
const Icon2 = item.icon;
|
|
12786
|
-
const selected = item.id ===
|
|
11721
|
+
const selected = item.id === active;
|
|
12787
11722
|
return /* @__PURE__ */ jsxs(
|
|
12788
11723
|
Link,
|
|
12789
11724
|
{
|
|
@@ -12854,7 +11789,7 @@ function OrderConfirmationPage({ orderId }) {
|
|
|
12854
11789
|
const [loading, setLoading] = useState(true);
|
|
12855
11790
|
const money = (v) => formatMoney(v, config.currency, config.locale);
|
|
12856
11791
|
useStorefrontHead({ title: order ? `Pedido #${order.orderNumber} \u2014 ${config.name}` : config.name });
|
|
12857
|
-
const reload =
|
|
11792
|
+
const reload = React36__default.useCallback(() => {
|
|
12858
11793
|
let cancelled = false;
|
|
12859
11794
|
getShopProvider().getOrder(orderId).then((o) => {
|
|
12860
11795
|
if (!cancelled) setOrder(o);
|
|
@@ -12883,7 +11818,7 @@ function OrderConfirmationPage({ orderId }) {
|
|
|
12883
11818
|
] }, column)) }),
|
|
12884
11819
|
/* @__PURE__ */ jsxs("div", { className: "mt-6", children: [
|
|
12885
11820
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-32" }),
|
|
12886
|
-
/* @__PURE__ */ jsx("div", { className: "mt-3 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(
|
|
11821
|
+
/* @__PURE__ */ jsx("div", { className: "mt-3 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(React36__default.Fragment, { children: [
|
|
12887
11822
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-7 shrink-0 rounded-full" }),
|
|
12888
11823
|
node < 3 && /* @__PURE__ */ jsx(Skeleton, { className: "h-px flex-1" })
|
|
12889
11824
|
] }, node)) })
|
|
@@ -13170,7 +12105,7 @@ function OrdersPanel() {
|
|
|
13170
12105
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-24 rounded-full" })
|
|
13171
12106
|
] }),
|
|
13172
12107
|
/* @__PURE__ */ jsx(Skeleton, { className: "mt-2 h-3 w-20" }),
|
|
13173
|
-
/* @__PURE__ */ jsx("div", { className: "mt-4 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(
|
|
12108
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(React36__default.Fragment, { children: [
|
|
13174
12109
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-6 shrink-0 rounded-full" }),
|
|
13175
12110
|
node < 3 && /* @__PURE__ */ jsx(Skeleton, { className: "h-px flex-1" })
|
|
13176
12111
|
] }, node)) }),
|
|
@@ -13249,7 +12184,7 @@ function ProfilePanel() {
|
|
|
13249
12184
|
const [saving, setSaving] = useState(false);
|
|
13250
12185
|
const [saved, setSaved] = useState(false);
|
|
13251
12186
|
const [error, setError] = useState(null);
|
|
13252
|
-
|
|
12187
|
+
React36__default.useEffect(() => {
|
|
13253
12188
|
if (!supported) return;
|
|
13254
12189
|
let cancelled = false;
|
|
13255
12190
|
provider.getMyProfile().then((p) => {
|
|
@@ -13542,7 +12477,7 @@ function PolicyPage({ kind }) {
|
|
|
13542
12477
|
] }) })
|
|
13543
12478
|
] });
|
|
13544
12479
|
}
|
|
13545
|
-
var StorefrontErrorBoundary = class extends
|
|
12480
|
+
var StorefrontErrorBoundary = class extends React36__default.Component {
|
|
13546
12481
|
constructor() {
|
|
13547
12482
|
super(...arguments);
|
|
13548
12483
|
this.state = { error: null };
|
|
@@ -13831,1334 +12766,6 @@ function createStorefront(options) {
|
|
|
13831
12766
|
return createStorefrontApp(config);
|
|
13832
12767
|
}
|
|
13833
12768
|
|
|
13834
|
-
|
|
13835
|
-
|
|
13836
|
-
|
|
13837
|
-
var STORE_PAYMENT_MODES = ["mock", "pix-mercadopago", "gateway"];
|
|
13838
|
-
var STORE_PAYMENT_METHOD_KINDS = [
|
|
13839
|
-
"pix",
|
|
13840
|
-
"credit_card",
|
|
13841
|
-
"debit_card",
|
|
13842
|
-
"boleto",
|
|
13843
|
-
"cash",
|
|
13844
|
-
"other"
|
|
13845
|
-
];
|
|
13846
|
-
var STORE_BACKEND_PROVIDERS = ["mock", "fayz-api", "fayz-shop", "custom"];
|
|
13847
|
-
var STORE_ROUTE_KINDS = [
|
|
13848
|
-
"home",
|
|
13849
|
-
"catalog",
|
|
13850
|
-
"product",
|
|
13851
|
-
"checkout",
|
|
13852
|
-
"account",
|
|
13853
|
-
"order",
|
|
13854
|
-
"custom"
|
|
13855
|
-
];
|
|
13856
|
-
var STORE_ROUTE_CHROMES = ["default", "minimal", "focused"];
|
|
13857
|
-
var STORE_THEME_RADII = ["none", "soft", "round", "pill"];
|
|
13858
|
-
var f = (type, description, extra = {}) => ({ type, description, ...extra });
|
|
13859
|
-
var STORE_SECTIONS = {
|
|
13860
|
-
store: {
|
|
13861
|
-
description: "Store identity: name, currency, locale.",
|
|
13862
|
-
versions: [1],
|
|
13863
|
-
fields: {
|
|
13864
|
-
name: f("string", "Store display name (header, page title).", { required: true }),
|
|
13865
|
-
currency: f("string", "ISO 4217 currency code \u2014 default 'BRL'."),
|
|
13866
|
-
locale: f("string", "Intl locale for money/date formatting \u2014 default 'pt-BR'.")
|
|
13867
|
-
}
|
|
13868
|
-
},
|
|
13869
|
-
theme: {
|
|
13870
|
-
description: "Visual identity: colors, fonts, radius, header/card personality.",
|
|
13871
|
-
versions: [1],
|
|
13872
|
-
fields: {
|
|
13873
|
-
name: f("string", "Theme name.", { required: true }),
|
|
13874
|
-
colors: f("object", "HSL token triplets (background, primary, \u2026)."),
|
|
13875
|
-
font: f("object", "Google Fonts pairing (heading, body, display, serif)."),
|
|
13876
|
-
radius: f("string", "Corner radius scale.", { enum: STORE_THEME_RADII }),
|
|
13877
|
-
header: f("object", "Header treatment (variant, uppercaseNav, search)."),
|
|
13878
|
-
productCard: f("object", "Card style and image aspect."),
|
|
13879
|
-
uppercaseButtons: f("boolean", "Uppercase CTA buttons with letter-spacing."),
|
|
13880
|
-
spacing: f("object", "Spacing scale (key \u2192 CSS length), emitted as --sf-space-<key>. e.g. {sm:'8px', md:'16px'}."),
|
|
13881
|
-
typeScale: f("object", "Type scale (key \u2192 CSS font-size), emitted as --sf-text-<key>. e.g. {body:'1rem', h1:'clamp(40px,6vw,66px)'}."),
|
|
13882
|
-
breakpoints: f("object", "Layout breakpoints (key \u2192 CSS length), emitted as --sf-breakpoint-<key> for JS/generated-style consumers."),
|
|
13883
|
-
motion: f("object", "Motion tokens (key \u2192 duration or easing), emitted as --sf-motion-<key>. e.g. {fast:'150ms', reveal:'cubic-bezier(0.22,1,0.36,1)'}."),
|
|
13884
|
-
tokens: f("object", "Free-form brand-token passthrough, emitted verbatim as CSS custom properties.")
|
|
13885
|
-
}
|
|
13886
|
-
},
|
|
13887
|
-
commerce: {
|
|
13888
|
-
description: "Commercial behavior: mode, shipping, payments, discounts, enquiry, feature toggles.",
|
|
13889
|
-
// v2 = the legacy `discounts` coupon list has been migrated onto the rule
|
|
13890
|
-
// engine (codemod commerce.discounts-to-promotions). Both versions are
|
|
13891
|
-
// understood, which is the whole point: the fleet migrates store by store.
|
|
13892
|
-
versions: [1, 2],
|
|
13893
|
-
fields: {
|
|
13894
|
-
commerceMode: f("string", "Checkout-first, catalog-only browsing, or product enquiry.", {
|
|
13895
|
-
enum: STORE_COMMERCE_MODES
|
|
13896
|
-
}),
|
|
13897
|
-
shipping: f("object", "Flat rate and free-above threshold."),
|
|
13898
|
-
payments: f("object", "Payment mode and offered methods."),
|
|
13899
|
-
discounts: f("array", "DEPRECATED \u2014 store-level discount codes ({code, percent, title?}). Use promotions.promotions.", {
|
|
13900
|
-
deprecated: {
|
|
13901
|
-
id: "storefront.commerce.discounts",
|
|
13902
|
-
removedAtVersion: 2,
|
|
13903
|
-
replacement: "promotions.promotions"
|
|
13904
|
-
}
|
|
13905
|
-
}),
|
|
13906
|
-
enquiry: f("object", "Product enquiry behavior for catalog/enquiry stores."),
|
|
13907
|
-
features: f("object", "Feature toggles (discounts, accounts, cart, checkout).")
|
|
13908
|
-
}
|
|
13909
|
-
},
|
|
13910
|
-
presentation: {
|
|
13911
|
-
description: "What the shopper sees: composed pages, slots, nav, footer, chrome.",
|
|
13912
|
-
versions: [1],
|
|
13913
|
-
fields: {
|
|
13914
|
-
announcement: f("string", "Promo message above the header."),
|
|
13915
|
-
logo: f("string", "Text logo. A JSX logo is code and lives at code.logo."),
|
|
13916
|
-
home: f("object", "Home page blueprint (legacy short form of pages.home)."),
|
|
13917
|
-
pages: f("object", "Pages composed from blocks, keyed by page kind."),
|
|
13918
|
-
slots: f("object", "Blocks grafted into named positions inside SDK pages."),
|
|
13919
|
-
nav: f("array", "Header nav links ({label, to})."),
|
|
13920
|
-
footer: f("object", "Footer content (about, contact, social, labels)."),
|
|
13921
|
-
imageLoading: f("object", "Global image reveal behavior."),
|
|
13922
|
-
catalogFacets: f(
|
|
13923
|
-
"array",
|
|
13924
|
-
"Catalog refinements over product.metadata ({key, label, values[]}), rendered in the filters panel and mirrored into ?<key>=<value>."
|
|
13925
|
-
),
|
|
13926
|
-
productSpecs: f(
|
|
13927
|
-
"object",
|
|
13928
|
-
"PDP specification table rules: `exclude` hides metadata keys, `labels` renames the rest."
|
|
13929
|
-
),
|
|
13930
|
-
search: f(
|
|
13931
|
-
"object",
|
|
13932
|
-
"Header search: mode ('inline' live filter, the default, or 'overlay'), plus placeholder, resultsPath, suggestionsLimit, minChars and labels. A custom suggestion renderer is code and lives at code.searchRenderSuggestion."
|
|
13933
|
-
)
|
|
13934
|
-
}
|
|
13935
|
-
},
|
|
13936
|
-
content: {
|
|
13937
|
-
description: "Long-form content: legal/institutional pages, product reviews.",
|
|
13938
|
-
versions: [1],
|
|
13939
|
-
fields: {
|
|
13940
|
-
legal: f("object", "Privacy / terms / returns page text."),
|
|
13941
|
-
reviews: f(
|
|
13942
|
-
"object",
|
|
13943
|
-
"Store-supplied product reviews ({items, enabled, emptyText}). Nothing is invented \u2014 with no items the PDP renders an honest empty state."
|
|
13944
|
-
)
|
|
13945
|
-
}
|
|
13946
|
-
},
|
|
13947
|
-
catalog: {
|
|
13948
|
-
description: "Mock catalog seed for stores without a live backend.",
|
|
13949
|
-
versions: [1],
|
|
13950
|
-
fields: {
|
|
13951
|
-
products: f("array", "Seed products."),
|
|
13952
|
-
categories: f("array", "Seed categories."),
|
|
13953
|
-
discounts: f("array", "Seed discounts."),
|
|
13954
|
-
promotions: f("array", "Seed rule-engine promotions for the mock provider. Prefer the top-level promotions section.")
|
|
13955
|
-
}
|
|
13956
|
-
},
|
|
13957
|
-
entities: {
|
|
13958
|
-
description: "Custom entity declarations (defineEntity inputs), keyed by entity key.",
|
|
13959
|
-
versions: [1],
|
|
13960
|
-
fields: {
|
|
13961
|
-
definitions: f("object", "Entity key \u2192 declaration ({fields, scope, access, indexes, \u2026}).")
|
|
13962
|
-
}
|
|
13963
|
-
},
|
|
13964
|
-
promotions: {
|
|
13965
|
-
description: "Rule-engine promotions: eligibility rules + application method, as pure data (spine M6).",
|
|
13966
|
-
versions: [1],
|
|
13967
|
-
fields: {
|
|
13968
|
-
promotions: f("array", "Promotions ({id, code?, isAutomatic?, rules?, applicationMethod}). Rule attributes come from the rule_attribute vocabulary.")
|
|
13969
|
-
}
|
|
13970
|
-
},
|
|
13971
|
-
backend: {
|
|
13972
|
-
description: "Backend descriptor: which provider serves the store.",
|
|
13973
|
-
// v2 = the legacy supabaseUrl/supabaseAnonKey pair has moved to
|
|
13974
|
-
// auth.supabase (codemod backend.supabase-to-auth).
|
|
13975
|
-
versions: [1, 2],
|
|
13976
|
-
fields: {
|
|
13977
|
-
provider: f("string", "Backend provider family.", { enum: STORE_BACKEND_PROVIDERS }),
|
|
13978
|
-
url: f("string", "Backend URL, when the provider needs one."),
|
|
13979
|
-
supabaseUrl: f("string", "DEPRECATED legacy field, kept for lossless round-trip. Use auth.supabase.url.", {
|
|
13980
|
-
deprecated: {
|
|
13981
|
-
id: "storefront.backend.supabaseUrl",
|
|
13982
|
-
removedAtVersion: 2,
|
|
13983
|
-
replacement: "auth.supabase.url"
|
|
13984
|
-
}
|
|
13985
|
-
}),
|
|
13986
|
-
supabaseAnonKey: f("string", "DEPRECATED legacy field, kept for lossless round-trip. Use auth.supabase.anonKey.", {
|
|
13987
|
-
deprecated: {
|
|
13988
|
-
id: "storefront.backend.supabaseAnonKey",
|
|
13989
|
-
removedAtVersion: 2,
|
|
13990
|
-
replacement: "auth.supabase.anonKey"
|
|
13991
|
-
}
|
|
13992
|
-
})
|
|
13993
|
-
}
|
|
13994
|
-
},
|
|
13995
|
-
auth: {
|
|
13996
|
-
description: "Customer auth, when expressible as data. Code-bearing auth lives at code.auth.",
|
|
13997
|
-
versions: [1],
|
|
13998
|
-
fields: {
|
|
13999
|
-
adapter: f("string", "Adapter id ('mock' | 'supabase')."),
|
|
14000
|
-
provider: f("string", "Provider id ('mock' | 'supabase')."),
|
|
14001
|
-
routes: f("object", "Auth route overrides."),
|
|
14002
|
-
supabase: f("object", "Supabase connection (url, anonKey, callback urls).")
|
|
14003
|
-
}
|
|
14004
|
-
},
|
|
14005
|
-
code: {
|
|
14006
|
-
description: "The code sidecar: config fields that hold code, referenced by registered handle name.",
|
|
14007
|
-
versions: [1],
|
|
14008
|
-
fields: {
|
|
14009
|
-
logo: f("string", "Handle of the JSX logo node."),
|
|
14010
|
-
provider: f("string", "Handle of the explicit ShopProvider."),
|
|
14011
|
-
auth: f("string", "Handle of a code-bearing auth config."),
|
|
14012
|
-
footerCredit: f("string", "Handle of the footer credit node."),
|
|
14013
|
-
searchRenderSuggestion: f("string", "Handle of the custom search-suggestion renderer."),
|
|
14014
|
-
components: f("object", "Component-slot name \u2192 handle of its override."),
|
|
14015
|
-
routes: f("array", "Custom routes; each component is a handle name.")
|
|
14016
|
-
}
|
|
14017
|
-
}
|
|
14018
|
-
};
|
|
14019
|
-
var STORE_SECTION_NAMES = Object.keys(STORE_SECTIONS);
|
|
14020
|
-
function sectionToJsonSchema(name) {
|
|
14021
|
-
const spec = STORE_SECTIONS[name];
|
|
14022
|
-
const properties = {
|
|
14023
|
-
version: {
|
|
14024
|
-
type: "integer",
|
|
14025
|
-
description: `Schema version of the ${name} section. Supported: ${spec.versions.join(", ")}.`,
|
|
14026
|
-
enum: [...spec.versions]
|
|
14027
|
-
}
|
|
14028
|
-
};
|
|
14029
|
-
const required = ["version"];
|
|
14030
|
-
for (const [field2, fieldSpec] of Object.entries(spec.fields)) {
|
|
14031
|
-
const node = { type: fieldSpec.type, description: fieldSpec.description };
|
|
14032
|
-
if (fieldSpec.enum) node.enum = [...fieldSpec.enum];
|
|
14033
|
-
if (fieldSpec.deprecated) {
|
|
14034
|
-
node.deprecated = true;
|
|
14035
|
-
node["x-fayz-deprecation"] = fieldSpec.deprecated.id;
|
|
14036
|
-
node["x-fayz-replacement"] = fieldSpec.deprecated.replacement;
|
|
14037
|
-
node["x-fayz-removed-at-section-version"] = fieldSpec.deprecated.removedAtVersion;
|
|
14038
|
-
}
|
|
14039
|
-
properties[field2] = node;
|
|
14040
|
-
if (fieldSpec.required) required.push(field2);
|
|
14041
|
-
}
|
|
14042
|
-
return {
|
|
14043
|
-
type: "object",
|
|
14044
|
-
description: spec.description,
|
|
14045
|
-
properties,
|
|
14046
|
-
required
|
|
14047
|
-
};
|
|
14048
|
-
}
|
|
14049
|
-
function isJsonValue(value) {
|
|
14050
|
-
if (value === null) return true;
|
|
14051
|
-
const t = typeof value;
|
|
14052
|
-
if (t === "string" || t === "number" || t === "boolean") return true;
|
|
14053
|
-
if (Array.isArray(value)) return value.every(isJsonValue);
|
|
14054
|
-
if (t === "object") {
|
|
14055
|
-
const record = value;
|
|
14056
|
-
if ("$$typeof" in record) return false;
|
|
14057
|
-
const proto = Object.getPrototypeOf(record);
|
|
14058
|
-
if (proto !== Object.prototype && proto !== null) return false;
|
|
14059
|
-
return Object.values(record).every((v) => v === void 0 || isJsonValue(v));
|
|
14060
|
-
}
|
|
14061
|
-
return false;
|
|
14062
|
-
}
|
|
14063
|
-
function isRecord(value) {
|
|
14064
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14065
|
-
}
|
|
14066
|
-
function compact(obj) {
|
|
14067
|
-
const out = {};
|
|
14068
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
14069
|
-
if (value !== void 0) out[key] = value;
|
|
14070
|
-
}
|
|
14071
|
-
return out;
|
|
14072
|
-
}
|
|
14073
|
-
|
|
14074
|
-
// src/extend/component-contracts.ts
|
|
14075
|
-
var STOREFRONT_COMPONENT_KEYS = [
|
|
14076
|
-
"ProductCard",
|
|
14077
|
-
"ProductDetail",
|
|
14078
|
-
"ProductGallery",
|
|
14079
|
-
"ProductPrice",
|
|
14080
|
-
"ProductActions",
|
|
14081
|
-
"ProductEnquiryForm",
|
|
14082
|
-
"CategoryCard",
|
|
14083
|
-
"CollectionSection",
|
|
14084
|
-
"HeroSection",
|
|
14085
|
-
"MediaCarousel",
|
|
14086
|
-
"ProductSlider",
|
|
14087
|
-
"Header",
|
|
14088
|
-
"Footer",
|
|
14089
|
-
"Shell",
|
|
14090
|
-
"EmptyState",
|
|
14091
|
-
"LoadingState",
|
|
14092
|
-
"ErrorState",
|
|
14093
|
-
"CartDrawerFooterExtra"
|
|
14094
|
-
];
|
|
14095
|
-
var STOREFRONT_PAGE_KINDS = ["home", "catalog", "product", "collection", "content"];
|
|
14096
|
-
var STRUCTURAL_BLOCK_KEYS = /* @__PURE__ */ new Set(["type", "id", "props", "children", "data"]);
|
|
14097
|
-
var DATA_NEED_KEYS = ["loader", "params"];
|
|
14098
|
-
var CODE_ROUTE_KEYS = ["id", "path", "kind", "chrome", "component"];
|
|
14099
|
-
var SLOT_AREAS = [...new Set(STOREFRONT_SLOTS.map((slot) => slot.area))];
|
|
14100
|
-
function slotNamesFor(area) {
|
|
14101
|
-
return STOREFRONT_SLOTS.filter((slot) => slot.area === area).map((slot) => slot.name);
|
|
14102
|
-
}
|
|
14103
|
-
var PAGE_KIND_PARAMS = {
|
|
14104
|
-
home: [],
|
|
14105
|
-
catalog: [],
|
|
14106
|
-
product: ["slug"],
|
|
14107
|
-
collection: ["slug"]
|
|
14108
|
-
};
|
|
14109
|
-
var SLOT_AREA_PARAMS = {
|
|
14110
|
-
productDetail: ["slug"]
|
|
14111
|
-
};
|
|
14112
|
-
var knownEntities = /* @__PURE__ */ new Set();
|
|
14113
|
-
function checkEntityRef(errors, path, value) {
|
|
14114
|
-
if (typeof value !== "string" || !value) return;
|
|
14115
|
-
if (!knownEntities.has(value)) {
|
|
14116
|
-
push(
|
|
14117
|
-
errors,
|
|
14118
|
-
path,
|
|
14119
|
-
"unknown-entity",
|
|
14120
|
-
`entity "${value}" is not declared (defineEntity or the entities section)`,
|
|
14121
|
-
[...knownEntities].sort()
|
|
14122
|
-
);
|
|
14123
|
-
}
|
|
14124
|
-
}
|
|
14125
|
-
function push(errors, path, code, message, valid) {
|
|
14126
|
-
errors.push(valid ? { path, code, message, valid: [...valid] } : { path, code, message });
|
|
14127
|
-
}
|
|
14128
|
-
function blockPropKeys(entry) {
|
|
14129
|
-
if ("props" in entry) {
|
|
14130
|
-
const props = entry.props;
|
|
14131
|
-
return isRecord(props) ? Object.keys(props) : [];
|
|
14132
|
-
}
|
|
14133
|
-
return Object.keys(entry).filter((key) => !STRUCTURAL_BLOCK_KEYS.has(key));
|
|
14134
|
-
}
|
|
14135
|
-
function validateSettingValues(errors, valuesPath, settings, values, owner, labelPrefix = "") {
|
|
14136
|
-
for (const setting of settings) {
|
|
14137
|
-
const value = values[setting.id];
|
|
14138
|
-
if (value === void 0) continue;
|
|
14139
|
-
const valuePath = `${valuesPath}.${setting.id}`;
|
|
14140
|
-
const label = `${labelPrefix}${setting.id}`;
|
|
14141
|
-
if (setting.type === "entity") {
|
|
14142
|
-
checkEntityRef(errors, valuePath, value);
|
|
14143
|
-
continue;
|
|
14144
|
-
}
|
|
14145
|
-
if (setting.type !== "list" || !setting.of?.length || !Array.isArray(value)) continue;
|
|
14146
|
-
const of = setting.of;
|
|
14147
|
-
const declared = collectSettingIds(of);
|
|
14148
|
-
value.forEach((item, index) => {
|
|
14149
|
-
if (!isRecord(item)) return;
|
|
14150
|
-
const itemPath = `${valuePath}[${index}]`;
|
|
14151
|
-
for (const key of Object.keys(item)) {
|
|
14152
|
-
if (!declared.has(key)) {
|
|
14153
|
-
push(
|
|
14154
|
-
errors,
|
|
14155
|
-
`${itemPath}.${key}`,
|
|
14156
|
-
owner.code,
|
|
14157
|
-
`${owner.subject} declares no ${owner.noun} "${label}[].${key}"`,
|
|
14158
|
-
[...declared].sort()
|
|
14159
|
-
);
|
|
14160
|
-
}
|
|
14161
|
-
}
|
|
14162
|
-
validateSettingValues(errors, itemPath, of, item, owner, `${label}[].`);
|
|
14163
|
-
});
|
|
14164
|
-
}
|
|
14165
|
-
}
|
|
14166
|
-
function checkLiteralParam(errors, path, containerPath, loaderId, setting, value) {
|
|
14167
|
-
const expected = setting.type === "number" ? "number" : setting.type === "boolean" ? "boolean" : setting.type === "list" ? "array" : "string";
|
|
14168
|
-
const actual = Array.isArray(value) ? "array" : typeof value;
|
|
14169
|
-
if (actual !== expected) {
|
|
14170
|
-
push(
|
|
14171
|
-
errors,
|
|
14172
|
-
path,
|
|
14173
|
-
"invalid-value",
|
|
14174
|
-
`loader "${loaderId}" param "${setting.id}" expects ${expected}, got ${actual}`
|
|
14175
|
-
);
|
|
14176
|
-
return;
|
|
14177
|
-
}
|
|
14178
|
-
if (setting.type === "select" && setting.options?.length && typeof value === "string") {
|
|
14179
|
-
const allowed = setting.options.map((option) => option.value);
|
|
14180
|
-
if (!allowed.includes(value)) {
|
|
14181
|
-
push(errors, path, "invalid-value", `"${value}" is not a valid ${setting.id}`, allowed);
|
|
14182
|
-
}
|
|
14183
|
-
}
|
|
14184
|
-
if (setting.type === "entity") checkEntityRef(errors, path, value);
|
|
14185
|
-
if (setting.type === "list") {
|
|
14186
|
-
validateSettingValues(
|
|
14187
|
-
errors,
|
|
14188
|
-
containerPath,
|
|
14189
|
-
[setting],
|
|
14190
|
-
{ [setting.id]: value },
|
|
14191
|
-
{ subject: `loader "${loaderId}"`, noun: "param", code: "unknown-loader-param" }
|
|
14192
|
-
);
|
|
14193
|
-
}
|
|
14194
|
-
}
|
|
14195
|
-
function validateDataNeeds(errors, entryPath, blockType, value, declaredParams) {
|
|
14196
|
-
if (!isRecord(value)) {
|
|
14197
|
-
push(errors, `${entryPath}.data`, "invalid-value", "`data` maps need names to {loader, params?}");
|
|
14198
|
-
return;
|
|
14199
|
-
}
|
|
14200
|
-
const blockSettings = getBlockMeta(blockType)?.settings;
|
|
14201
|
-
for (const [name, need] of Object.entries(value)) {
|
|
14202
|
-
const needPath = `${entryPath}.data.${name}`;
|
|
14203
|
-
if (!isRecord(need) || typeof need.loader !== "string" || !need.loader) {
|
|
14204
|
-
push(errors, needPath, "invalid-value", "a data need is {loader: string, params?: object}");
|
|
14205
|
-
continue;
|
|
14206
|
-
}
|
|
14207
|
-
if (!loaderRegistry.has(need.loader)) {
|
|
14208
|
-
push(errors, `${needPath}.loader`, "unknown-loader", `loader "${need.loader}" is not registered`, listLoaders());
|
|
14209
|
-
continue;
|
|
14210
|
-
}
|
|
14211
|
-
for (const key of Object.keys(need)) {
|
|
14212
|
-
if (!DATA_NEED_KEYS.includes(key)) {
|
|
14213
|
-
push(errors, `${needPath}.${key}`, "unknown-field", `a data need has no field "${key}"`, DATA_NEED_KEYS);
|
|
14214
|
-
}
|
|
14215
|
-
}
|
|
14216
|
-
if (need.params === void 0) continue;
|
|
14217
|
-
if (!isRecord(need.params)) {
|
|
14218
|
-
push(errors, `${needPath}.params`, "invalid-value", "loader params are an object");
|
|
14219
|
-
continue;
|
|
14220
|
-
}
|
|
14221
|
-
const loaderSettings = loaderRegistry.getEntry(need.loader)?.meta.settings;
|
|
14222
|
-
const declaredLoaderParams = loaderSettings ? collectSettingIds(loaderSettings) : null;
|
|
14223
|
-
for (const [param, paramValue] of Object.entries(need.params)) {
|
|
14224
|
-
const paramPath = `${needPath}.params.${param}`;
|
|
14225
|
-
const setting = loaderSettings?.find((s2) => s2.id === param);
|
|
14226
|
-
if (declaredLoaderParams && !declaredLoaderParams.has(param)) {
|
|
14227
|
-
push(
|
|
14228
|
-
errors,
|
|
14229
|
-
paramPath,
|
|
14230
|
-
"unknown-loader-param",
|
|
14231
|
-
`loader "${need.loader}" declares no param "${param}"`,
|
|
14232
|
-
[...declaredLoaderParams].sort()
|
|
14233
|
-
);
|
|
14234
|
-
continue;
|
|
14235
|
-
}
|
|
14236
|
-
if (isLoaderParamRef(paramValue)) {
|
|
14237
|
-
if (!declaredParams.includes(paramValue.$param)) {
|
|
14238
|
-
push(
|
|
14239
|
-
errors,
|
|
14240
|
-
paramPath,
|
|
14241
|
-
"unbound-route-param",
|
|
14242
|
-
declaredParams.length ? `$param "${paramValue.$param}" is not a route param of this page` : `$param "${paramValue.$param}" cannot bind \u2014 this page declares no route params`,
|
|
14243
|
-
declaredParams
|
|
14244
|
-
);
|
|
14245
|
-
}
|
|
14246
|
-
continue;
|
|
14247
|
-
}
|
|
14248
|
-
if (isLoaderPropRef(paramValue)) {
|
|
14249
|
-
const settingIds = blockSettings ? collectSettingIds(blockSettings) : null;
|
|
14250
|
-
if (settingIds && !settingIds.has(paramValue.$prop)) {
|
|
14251
|
-
push(
|
|
14252
|
-
errors,
|
|
14253
|
-
paramPath,
|
|
14254
|
-
"unknown-prop-binding",
|
|
14255
|
-
`$prop "${paramValue.$prop}" is not a setting of block "${blockType}"`,
|
|
14256
|
-
[...settingIds].sort()
|
|
14257
|
-
);
|
|
14258
|
-
}
|
|
14259
|
-
continue;
|
|
14260
|
-
}
|
|
14261
|
-
if (setting) {
|
|
14262
|
-
checkLiteralParam(errors, paramPath, `${needPath}.params`, need.loader, setting, paramValue);
|
|
14263
|
-
}
|
|
14264
|
-
}
|
|
14265
|
-
}
|
|
14266
|
-
}
|
|
14267
|
-
function validateBlockList(errors, path, value, declaredParams) {
|
|
14268
|
-
if (!Array.isArray(value)) {
|
|
14269
|
-
push(errors, path, "invalid-value", `expected an array of blocks, got ${typeof value}`);
|
|
14270
|
-
return;
|
|
14271
|
-
}
|
|
14272
|
-
value.forEach((entry, index) => {
|
|
14273
|
-
const entryPath = `${path}[${index}]`;
|
|
14274
|
-
if (!isRecord(entry)) {
|
|
14275
|
-
push(errors, entryPath, "invalid-value", "a block entry must be an object with a `type`");
|
|
14276
|
-
return;
|
|
14277
|
-
}
|
|
14278
|
-
const type = entry.type;
|
|
14279
|
-
if (typeof type !== "string" || !type) {
|
|
14280
|
-
push(errors, `${entryPath}.type`, "invalid-value", "a block entry must declare a string `type`");
|
|
14281
|
-
return;
|
|
14282
|
-
}
|
|
14283
|
-
if (!blockRegistry.has(type)) {
|
|
14284
|
-
push(
|
|
14285
|
-
errors,
|
|
14286
|
-
`${entryPath}.type`,
|
|
14287
|
-
"unknown-block",
|
|
14288
|
-
`block "${type}" is not registered`,
|
|
14289
|
-
blockRegistry.ids().sort()
|
|
14290
|
-
);
|
|
14291
|
-
return;
|
|
14292
|
-
}
|
|
14293
|
-
const settings = getBlockMeta(type)?.settings;
|
|
14294
|
-
if (settings) {
|
|
14295
|
-
const declared = collectSettingIds(settings);
|
|
14296
|
-
for (const key of blockPropKeys(entry)) {
|
|
14297
|
-
if (!declared.has(key)) {
|
|
14298
|
-
push(
|
|
14299
|
-
errors,
|
|
14300
|
-
`${entryPath}.props.${key}`,
|
|
14301
|
-
"unknown-setting",
|
|
14302
|
-
`block "${type}" declares no setting "${key}"`,
|
|
14303
|
-
[...declared].sort()
|
|
14304
|
-
);
|
|
14305
|
-
}
|
|
14306
|
-
}
|
|
14307
|
-
const props = isRecord(entry.props) ? entry.props : entry;
|
|
14308
|
-
validateSettingValues(errors, `${entryPath}.props`, settings, props, {
|
|
14309
|
-
subject: `block "${type}"`,
|
|
14310
|
-
noun: "setting",
|
|
14311
|
-
code: "unknown-setting"
|
|
14312
|
-
});
|
|
14313
|
-
}
|
|
14314
|
-
if ("data" in entry && entry.data !== void 0) {
|
|
14315
|
-
validateDataNeeds(errors, entryPath, type, entry.data, declaredParams);
|
|
14316
|
-
}
|
|
14317
|
-
if ("children" in entry && entry.children !== void 0) {
|
|
14318
|
-
validateBlockList(errors, `${entryPath}.children`, entry.children, declaredParams);
|
|
14319
|
-
}
|
|
14320
|
-
});
|
|
14321
|
-
}
|
|
14322
|
-
function validateBlockTree(errors, path, value, declaredParams = []) {
|
|
14323
|
-
validateBlockList(errors, path, value, declaredParams);
|
|
14324
|
-
if (!Array.isArray(value)) return;
|
|
14325
|
-
const nodes = toBlockNodes(value);
|
|
14326
|
-
for (const violation of checkBlockConstraints(nodes)) {
|
|
14327
|
-
push(errors, `${path}${violation.path}`, violation.rule, violation.detail, violation.valid);
|
|
14328
|
-
}
|
|
14329
|
-
}
|
|
14330
|
-
function collectSettingIds(settings) {
|
|
14331
|
-
return new Set(settings.map((setting) => setting.id));
|
|
14332
|
-
}
|
|
14333
|
-
var TOKEN_KEY = /^[a-zA-Z][a-zA-Z0-9-]*$/;
|
|
14334
|
-
function validateTheme(errors, section) {
|
|
14335
|
-
for (const field2 of THEME_SCALE_FIELDS) {
|
|
14336
|
-
const scale = section[field2];
|
|
14337
|
-
if (scale === void 0) continue;
|
|
14338
|
-
if (!isRecord(scale)) continue;
|
|
14339
|
-
for (const [key, value] of Object.entries(scale)) {
|
|
14340
|
-
const path = `theme.${field2}.${key}`;
|
|
14341
|
-
if (!TOKEN_KEY.test(key)) {
|
|
14342
|
-
push(
|
|
14343
|
-
errors,
|
|
14344
|
-
path,
|
|
14345
|
-
"invalid-token-key",
|
|
14346
|
-
`"${key}" cannot become the CSS custom property ${THEME_SCALE_VAR_PREFIX[field2]}-${key} \u2014 token keys match ${TOKEN_KEY}`
|
|
14347
|
-
);
|
|
14348
|
-
}
|
|
14349
|
-
if (typeof value !== "string") {
|
|
14350
|
-
push(errors, path, "invalid-value", `a ${field2} token is a CSS value string, got ${typeof value}`);
|
|
14351
|
-
}
|
|
14352
|
-
}
|
|
14353
|
-
}
|
|
14354
|
-
}
|
|
14355
|
-
function validateSectionEnvelope(errors, name, section) {
|
|
14356
|
-
const spec = STORE_SECTIONS[name];
|
|
14357
|
-
const version = section.version;
|
|
14358
|
-
if (typeof version !== "number" || !spec.versions.includes(version)) {
|
|
14359
|
-
push(
|
|
14360
|
-
errors,
|
|
14361
|
-
`${name}.version`,
|
|
14362
|
-
"unsupported-section-version",
|
|
14363
|
-
`section "${name}" declares version ${JSON.stringify(version)}, which this SDK does not understand`,
|
|
14364
|
-
spec.versions.map(String)
|
|
14365
|
-
);
|
|
14366
|
-
return false;
|
|
14367
|
-
}
|
|
14368
|
-
const fieldNames = Object.keys(spec.fields);
|
|
14369
|
-
for (const key of Object.keys(section)) {
|
|
14370
|
-
if (key === "version") continue;
|
|
14371
|
-
const fieldSpec = spec.fields[key];
|
|
14372
|
-
if (!fieldSpec) {
|
|
14373
|
-
push(errors, `${name}.${key}`, "unknown-field", `section "${name}" has no field "${key}"`, fieldNames);
|
|
14374
|
-
continue;
|
|
14375
|
-
}
|
|
14376
|
-
const deprecated = fieldSpec.deprecated;
|
|
14377
|
-
if (deprecated && version >= deprecated.removedAtVersion) {
|
|
14378
|
-
push(
|
|
14379
|
-
errors,
|
|
14380
|
-
`${name}.${key}`,
|
|
14381
|
-
"removed-field",
|
|
14382
|
-
`field "${name}.${key}" was removed at ${name} version ${deprecated.removedAtVersion} (deprecation ${deprecated.id}); this section declares version ${version}`,
|
|
14383
|
-
[deprecated.replacement]
|
|
14384
|
-
);
|
|
14385
|
-
continue;
|
|
14386
|
-
}
|
|
14387
|
-
const value = section[key];
|
|
14388
|
-
const actual = Array.isArray(value) ? "array" : typeof value;
|
|
14389
|
-
if (actual !== fieldSpec.type) {
|
|
14390
|
-
push(
|
|
14391
|
-
errors,
|
|
14392
|
-
`${name}.${key}`,
|
|
14393
|
-
"invalid-value",
|
|
14394
|
-
`field "${name}.${key}" expects ${fieldSpec.type}, got ${actual}`
|
|
14395
|
-
);
|
|
14396
|
-
continue;
|
|
14397
|
-
}
|
|
14398
|
-
if (fieldSpec.enum && typeof value === "string" && !fieldSpec.enum.includes(value)) {
|
|
14399
|
-
push(
|
|
14400
|
-
errors,
|
|
14401
|
-
`${name}.${key}`,
|
|
14402
|
-
"invalid-value",
|
|
14403
|
-
`"${value}" is not a valid ${name}.${key}`,
|
|
14404
|
-
fieldSpec.enum
|
|
14405
|
-
);
|
|
14406
|
-
}
|
|
14407
|
-
}
|
|
14408
|
-
for (const [field2, fieldSpec] of Object.entries(spec.fields)) {
|
|
14409
|
-
if (fieldSpec.required && section[field2] === void 0) {
|
|
14410
|
-
push(errors, `${name}.${field2}`, "missing-field", `section "${name}" requires "${field2}"`);
|
|
14411
|
-
}
|
|
14412
|
-
}
|
|
14413
|
-
return true;
|
|
14414
|
-
}
|
|
14415
|
-
function validateCommerce(errors, section) {
|
|
14416
|
-
const payments = section.payments;
|
|
14417
|
-
if (isRecord(payments)) {
|
|
14418
|
-
if (payments.mode !== void 0) {
|
|
14419
|
-
if (typeof payments.mode !== "string" || !STORE_PAYMENT_MODES.includes(payments.mode)) {
|
|
14420
|
-
push(
|
|
14421
|
-
errors,
|
|
14422
|
-
"commerce.payments.mode",
|
|
14423
|
-
"invalid-value",
|
|
14424
|
-
`"${String(payments.mode)}" is not a payment mode`,
|
|
14425
|
-
STORE_PAYMENT_MODES
|
|
14426
|
-
);
|
|
14427
|
-
}
|
|
14428
|
-
}
|
|
14429
|
-
if (payments.methods !== void 0) {
|
|
14430
|
-
if (!Array.isArray(payments.methods)) {
|
|
14431
|
-
push(errors, "commerce.payments.methods", "invalid-value", "payments.methods must be an array");
|
|
14432
|
-
} else {
|
|
14433
|
-
payments.methods.forEach((method, index) => {
|
|
14434
|
-
if (typeof method !== "string" || !STORE_PAYMENT_METHOD_KINDS.includes(method)) {
|
|
14435
|
-
push(
|
|
14436
|
-
errors,
|
|
14437
|
-
`commerce.payments.methods[${index}]`,
|
|
14438
|
-
"invalid-value",
|
|
14439
|
-
`"${String(method)}" is not a payment method`,
|
|
14440
|
-
STORE_PAYMENT_METHOD_KINDS
|
|
14441
|
-
);
|
|
14442
|
-
}
|
|
14443
|
-
});
|
|
14444
|
-
}
|
|
14445
|
-
}
|
|
14446
|
-
}
|
|
14447
|
-
const discounts = section.discounts;
|
|
14448
|
-
if (Array.isArray(discounts)) {
|
|
14449
|
-
discounts.forEach((discount, index) => {
|
|
14450
|
-
if (!isRecord(discount) || typeof discount.code !== "string" || typeof discount.percent !== "number") {
|
|
14451
|
-
push(
|
|
14452
|
-
errors,
|
|
14453
|
-
`commerce.discounts[${index}]`,
|
|
14454
|
-
"invalid-value",
|
|
14455
|
-
"a discount is {code: string, percent: number, title?: string}"
|
|
14456
|
-
);
|
|
14457
|
-
}
|
|
14458
|
-
});
|
|
14459
|
-
}
|
|
14460
|
-
}
|
|
14461
|
-
var CONTENT_SLUG = /^[a-z0-9][a-z0-9-]*$/;
|
|
14462
|
-
function validateContentPages(errors, basePath, value) {
|
|
14463
|
-
if (!isRecord(value)) {
|
|
14464
|
-
push(errors, basePath, "invalid-value", "pages.content maps slugs to {title?, path?, blocks: [...]}");
|
|
14465
|
-
return;
|
|
14466
|
-
}
|
|
14467
|
-
const pathOwners = /* @__PURE__ */ new Map();
|
|
14468
|
-
for (const [slug, page] of Object.entries(value)) {
|
|
14469
|
-
const pagePath = `${basePath}.${slug}`;
|
|
14470
|
-
if (!CONTENT_SLUG.test(slug)) {
|
|
14471
|
-
push(
|
|
14472
|
-
errors,
|
|
14473
|
-
pagePath,
|
|
14474
|
-
"invalid-value",
|
|
14475
|
-
`"${slug}" cannot become the route "/${slug}" \u2014 content slugs match ${CONTENT_SLUG}`
|
|
14476
|
-
);
|
|
14477
|
-
}
|
|
14478
|
-
if (!isRecord(page) || page.blocks === void 0) {
|
|
14479
|
-
push(errors, pagePath, "invalid-value", "a content page is {title?, path?, blocks: [...]}");
|
|
14480
|
-
continue;
|
|
14481
|
-
}
|
|
14482
|
-
if (page.title !== void 0 && typeof page.title !== "string") {
|
|
14483
|
-
push(errors, `${pagePath}.title`, "invalid-value", `title expects string, got ${typeof page.title}`);
|
|
14484
|
-
}
|
|
14485
|
-
let routePath = `/${slug}`;
|
|
14486
|
-
if (page.path !== void 0) {
|
|
14487
|
-
if (typeof page.path !== "string" || !page.path.startsWith("/")) {
|
|
14488
|
-
push(errors, `${pagePath}.path`, "invalid-value", `path is an absolute route ('/${slug}'), got ${JSON.stringify(page.path)}`);
|
|
14489
|
-
} else {
|
|
14490
|
-
routePath = page.path;
|
|
14491
|
-
}
|
|
14492
|
-
}
|
|
14493
|
-
const owner = pathOwners.get(routePath);
|
|
14494
|
-
if (owner) {
|
|
14495
|
-
push(
|
|
14496
|
-
errors,
|
|
14497
|
-
`${pagePath}.path`,
|
|
14498
|
-
"duplicate-content-path",
|
|
14499
|
-
`content pages "${owner}" and "${slug}" both resolve to "${routePath}" \u2014 one of them can never render`
|
|
14500
|
-
);
|
|
14501
|
-
} else {
|
|
14502
|
-
pathOwners.set(routePath, slug);
|
|
14503
|
-
}
|
|
14504
|
-
validateBlockTree(errors, `${pagePath}.blocks`, page.blocks, routePathParams(routePath));
|
|
14505
|
-
}
|
|
14506
|
-
}
|
|
14507
|
-
function validatePresentation(errors, section) {
|
|
14508
|
-
const home = section.home;
|
|
14509
|
-
if (isRecord(home) && home.sections !== void 0) {
|
|
14510
|
-
validateBlockTree(errors, "presentation.home.sections", home.sections);
|
|
14511
|
-
}
|
|
14512
|
-
const pages = section.pages;
|
|
14513
|
-
if (isRecord(pages)) {
|
|
14514
|
-
const validKinds = [...STOREFRONT_PAGE_KINDS];
|
|
14515
|
-
for (const [kind, page] of Object.entries(pages)) {
|
|
14516
|
-
const pagePath = `presentation.pages.${kind}`;
|
|
14517
|
-
if (!validKinds.includes(kind)) {
|
|
14518
|
-
push(errors, pagePath, "unknown-page-kind", `"${kind}" is not a composable page kind`, validKinds);
|
|
14519
|
-
continue;
|
|
14520
|
-
}
|
|
14521
|
-
if (kind === "content") {
|
|
14522
|
-
validateContentPages(errors, pagePath, page);
|
|
14523
|
-
continue;
|
|
14524
|
-
}
|
|
14525
|
-
if (!isRecord(page) || page.blocks === void 0) {
|
|
14526
|
-
push(errors, pagePath, "invalid-value", "a composed page is {blocks: [...]}");
|
|
14527
|
-
continue;
|
|
14528
|
-
}
|
|
14529
|
-
validateBlockTree(errors, `${pagePath}.blocks`, page.blocks, PAGE_KIND_PARAMS[kind] ?? []);
|
|
14530
|
-
}
|
|
14531
|
-
}
|
|
14532
|
-
const slots = section.slots;
|
|
14533
|
-
if (isRecord(slots)) {
|
|
14534
|
-
for (const [area, areaSlots] of Object.entries(slots)) {
|
|
14535
|
-
const areaPath = `presentation.slots.${area}`;
|
|
14536
|
-
if (!SLOT_AREAS.includes(area)) {
|
|
14537
|
-
push(errors, areaPath, "unknown-slot-area", `"${area}" is not a slot area`, SLOT_AREAS);
|
|
14538
|
-
continue;
|
|
14539
|
-
}
|
|
14540
|
-
if (!isRecord(areaSlots)) {
|
|
14541
|
-
push(errors, areaPath, "invalid-value", "a slot area maps slot names to block lists");
|
|
14542
|
-
continue;
|
|
14543
|
-
}
|
|
14544
|
-
const validNames = slotNamesFor(area);
|
|
14545
|
-
for (const [slotName, blocks] of Object.entries(areaSlots)) {
|
|
14546
|
-
const slotPath = `${areaPath}.${slotName}`;
|
|
14547
|
-
if (!validNames.includes(slotName)) {
|
|
14548
|
-
push(errors, slotPath, "unknown-slot", `"${area}.${slotName}" is not a slot`, validNames);
|
|
14549
|
-
continue;
|
|
14550
|
-
}
|
|
14551
|
-
validateBlockTree(errors, slotPath, blocks, SLOT_AREA_PARAMS[area] ?? []);
|
|
14552
|
-
}
|
|
14553
|
-
}
|
|
14554
|
-
}
|
|
14555
|
-
}
|
|
14556
|
-
var ENTITY_KEY_RE = /^[a-z][a-z0-9_]*$/;
|
|
14557
|
-
var ENTITY_FIELD_RE = /^[a-z][a-z0-9_]*$/;
|
|
14558
|
-
function validateEntitiesSection(errors, section) {
|
|
14559
|
-
const definitions = section.definitions;
|
|
14560
|
-
if (definitions === void 0 || !isRecord(definitions)) return;
|
|
14561
|
-
for (const [key, declaration] of Object.entries(definitions)) {
|
|
14562
|
-
const path = `entities.definitions.${key}`;
|
|
14563
|
-
if (!ENTITY_KEY_RE.test(key)) {
|
|
14564
|
-
push(errors, path, "invalid-value", `"${key}" is not a valid entity key \u2014 keys are snake_case`);
|
|
14565
|
-
}
|
|
14566
|
-
if (!isRecord(declaration) || !isRecord(declaration.fields) || Object.keys(declaration.fields).length === 0) {
|
|
14567
|
-
push(errors, path, "invalid-value", "an entity declaration is {fields: {<name>: {type, \u2026}}, scope?, access?, indexes?}");
|
|
14568
|
-
continue;
|
|
14569
|
-
}
|
|
14570
|
-
const fields = declaration.fields;
|
|
14571
|
-
const fieldNames = Object.keys(fields);
|
|
14572
|
-
for (const [name, field2] of Object.entries(fields)) {
|
|
14573
|
-
const fieldPath = `${path}.fields.${name}`;
|
|
14574
|
-
if (!ENTITY_FIELD_RE.test(name)) {
|
|
14575
|
-
push(errors, fieldPath, "invalid-value", `"${name}" is not a valid field name \u2014 fields are snake_case`);
|
|
14576
|
-
}
|
|
14577
|
-
if (RESERVED_ENTITY_FIELDS.includes(name)) {
|
|
14578
|
-
push(errors, fieldPath, "invalid-value", `"${name}" is a structural record column`, RESERVED_ENTITY_FIELDS);
|
|
14579
|
-
continue;
|
|
14580
|
-
}
|
|
14581
|
-
if (!isRecord(field2) || typeof field2.type !== "string") {
|
|
14582
|
-
push(errors, fieldPath, "invalid-value", "a field is {type: <entity field type>, label?, required?, \u2026}");
|
|
14583
|
-
continue;
|
|
14584
|
-
}
|
|
14585
|
-
if (!ENTITY_FIELD_TYPES.includes(field2.type)) {
|
|
14586
|
-
push(errors, `${fieldPath}.type`, "unknown-entity-field-type", `"${field2.type}" is not an entity field type`, ENTITY_FIELD_TYPES);
|
|
14587
|
-
continue;
|
|
14588
|
-
}
|
|
14589
|
-
if (field2.type === "ref") {
|
|
14590
|
-
if (typeof field2.entity !== "string" || !field2.entity) {
|
|
14591
|
-
push(errors, fieldPath, "invalid-value", `a ref field names its target: {type: 'ref', entity: '<key>'}`);
|
|
14592
|
-
} else {
|
|
14593
|
-
checkEntityRef(errors, `${fieldPath}.entity`, field2.entity);
|
|
14594
|
-
}
|
|
14595
|
-
}
|
|
14596
|
-
}
|
|
14597
|
-
const scope = declaration.scope;
|
|
14598
|
-
if (scope !== void 0 && scope !== "tenant") {
|
|
14599
|
-
push(errors, `${path}.scope`, "invalid-value", `"${String(scope)}" is not an entity scope`, ["tenant"]);
|
|
14600
|
-
}
|
|
14601
|
-
const access = declaration.access;
|
|
14602
|
-
if (access !== void 0) {
|
|
14603
|
-
if (!isRecord(access)) {
|
|
14604
|
-
push(errors, `${path}.access`, "invalid-value", "access is {read: 'public'|'staff', write: 'staff'}");
|
|
14605
|
-
} else {
|
|
14606
|
-
if (access.read !== void 0 && access.read !== "public" && access.read !== "staff") {
|
|
14607
|
-
push(errors, `${path}.access.read`, "invalid-value", `"${String(access.read)}" is not a read access level`, ["public", "staff"]);
|
|
14608
|
-
}
|
|
14609
|
-
if (access.write !== void 0 && access.write !== "staff") {
|
|
14610
|
-
push(errors, `${path}.access.write`, "invalid-value", `"${String(access.write)}" is not a write access level \u2014 shopper writes go through actions (M7), not RLS`, ["staff"]);
|
|
14611
|
-
}
|
|
14612
|
-
}
|
|
14613
|
-
}
|
|
14614
|
-
const references = (where, name) => {
|
|
14615
|
-
if (typeof name !== "string" || !fieldNames.includes(name)) {
|
|
14616
|
-
push(errors, `${path}.${where}`, "invalid-value", `${where} references undeclared field "${String(name)}"`, fieldNames);
|
|
14617
|
-
}
|
|
14618
|
-
};
|
|
14619
|
-
if (Array.isArray(declaration.indexes)) {
|
|
14620
|
-
declaration.indexes.forEach((tuple, i) => {
|
|
14621
|
-
if (!Array.isArray(tuple)) {
|
|
14622
|
-
push(errors, `${path}.indexes[${i}]`, "invalid-value", "an index is an array of declared field names");
|
|
14623
|
-
return;
|
|
14624
|
-
}
|
|
14625
|
-
for (const name of tuple) references(`indexes[${i}]`, name);
|
|
14626
|
-
});
|
|
14627
|
-
}
|
|
14628
|
-
if (declaration.titleField !== void 0) references("titleField", declaration.titleField);
|
|
14629
|
-
if (Array.isArray(declaration.displayFields)) {
|
|
14630
|
-
for (const name of declaration.displayFields) references("displayFields", name);
|
|
14631
|
-
}
|
|
14632
|
-
}
|
|
14633
|
-
}
|
|
14634
|
-
function validatePromotionRule(errors, path, rule) {
|
|
14635
|
-
if (!isRecord(rule) || typeof rule.attribute !== "string" || typeof rule.operator !== "string") {
|
|
14636
|
-
push(errors, path, "invalid-value", "a rule is {attribute, operator, values: [...]}");
|
|
14637
|
-
return;
|
|
14638
|
-
}
|
|
14639
|
-
if (!hasRuleAttribute(rule.attribute)) {
|
|
14640
|
-
push(
|
|
14641
|
-
errors,
|
|
14642
|
-
`${path}.attribute`,
|
|
14643
|
-
"unknown-rule-attribute",
|
|
14644
|
-
`"${rule.attribute}" is not in the rule attribute vocabulary`,
|
|
14645
|
-
listRuleAttributeKeys()
|
|
14646
|
-
);
|
|
14647
|
-
return;
|
|
14648
|
-
}
|
|
14649
|
-
if (!RULE_OPERATORS.includes(rule.operator)) {
|
|
14650
|
-
push(errors, `${path}.operator`, "unknown-rule-operator", `"${rule.operator}" is not a rule operator`, RULE_OPERATORS);
|
|
14651
|
-
return;
|
|
14652
|
-
}
|
|
14653
|
-
const attribute = resolveRuleAttribute(rule.attribute);
|
|
14654
|
-
if (!attribute.operators.includes(rule.operator)) {
|
|
14655
|
-
push(
|
|
14656
|
-
errors,
|
|
14657
|
-
`${path}.operator`,
|
|
14658
|
-
"unsupported-rule-operator",
|
|
14659
|
-
`attribute "${rule.attribute}" does not support operator "${rule.operator}"`,
|
|
14660
|
-
attribute.operators
|
|
14661
|
-
);
|
|
14662
|
-
}
|
|
14663
|
-
if (!Array.isArray(rule.values) || rule.values.length === 0) {
|
|
14664
|
-
push(errors, `${path}.values`, "invalid-value", "rule values are a non-empty array of scalars");
|
|
14665
|
-
return;
|
|
14666
|
-
}
|
|
14667
|
-
rule.values.forEach((value, index) => {
|
|
14668
|
-
const t = typeof value;
|
|
14669
|
-
if (t !== "string" && t !== "number" && t !== "boolean") {
|
|
14670
|
-
push(errors, `${path}.values[${index}]`, "invalid-value", `a rule value is a JSON scalar, got ${t}`);
|
|
14671
|
-
}
|
|
14672
|
-
});
|
|
14673
|
-
}
|
|
14674
|
-
function validateRuleList(errors, path, value) {
|
|
14675
|
-
if (value === void 0) return;
|
|
14676
|
-
if (!Array.isArray(value)) {
|
|
14677
|
-
push(errors, path, "invalid-value", `expected an array of rules, got ${typeof value}`);
|
|
14678
|
-
return;
|
|
14679
|
-
}
|
|
14680
|
-
value.forEach((rule, index) => validatePromotionRule(errors, `${path}[${index}]`, rule));
|
|
14681
|
-
}
|
|
14682
|
-
function validatePromotionsSection(errors, section) {
|
|
14683
|
-
const promotions = section.promotions;
|
|
14684
|
-
if (promotions === void 0 || !Array.isArray(promotions)) return;
|
|
14685
|
-
promotions.forEach((promotion, index) => {
|
|
14686
|
-
const path = `promotions.promotions[${index}]`;
|
|
14687
|
-
if (!isRecord(promotion) || typeof promotion.id !== "string" || !promotion.id) {
|
|
14688
|
-
push(errors, path, "invalid-value", "a promotion is {id, code?, isAutomatic?, rules?, applicationMethod}");
|
|
14689
|
-
return;
|
|
14690
|
-
}
|
|
14691
|
-
if (promotion.type !== void 0 && !PROMOTION_TYPES.includes(promotion.type)) {
|
|
14692
|
-
push(errors, `${path}.type`, "invalid-value", `"${String(promotion.type)}" is not a promotion type`, PROMOTION_TYPES);
|
|
14693
|
-
}
|
|
14694
|
-
if (promotion.status !== void 0 && !PROMOTION_STATUSES.includes(promotion.status)) {
|
|
14695
|
-
push(errors, `${path}.status`, "invalid-value", `"${String(promotion.status)}" is not a promotion status`, PROMOTION_STATUSES);
|
|
14696
|
-
}
|
|
14697
|
-
if (promotion.code === void 0 && promotion.isAutomatic !== true) {
|
|
14698
|
-
push(
|
|
14699
|
-
errors,
|
|
14700
|
-
`${path}.code`,
|
|
14701
|
-
"invalid-value",
|
|
14702
|
-
"a promotion needs a code or isAutomatic: true \u2014 otherwise nothing can ever trigger it"
|
|
14703
|
-
);
|
|
14704
|
-
}
|
|
14705
|
-
validateRuleList(errors, `${path}.rules`, promotion.rules);
|
|
14706
|
-
const method = promotion.applicationMethod;
|
|
14707
|
-
if (!isRecord(method)) {
|
|
14708
|
-
push(errors, `${path}.applicationMethod`, "invalid-value", "a promotion carries an applicationMethod ({type, value, targetType, \u2026})");
|
|
14709
|
-
return;
|
|
14710
|
-
}
|
|
14711
|
-
const methodPath = `${path}.applicationMethod`;
|
|
14712
|
-
if (typeof method.type !== "string" || !APPLICATION_METHOD_TYPES.includes(method.type)) {
|
|
14713
|
-
push(errors, `${methodPath}.type`, "invalid-value", `"${String(method.type)}" is not an application method type`, APPLICATION_METHOD_TYPES);
|
|
14714
|
-
}
|
|
14715
|
-
if (typeof method.value !== "number" || method.value < 0) {
|
|
14716
|
-
push(errors, `${methodPath}.value`, "invalid-value", "applicationMethod.value is a non-negative number");
|
|
14717
|
-
}
|
|
14718
|
-
if (typeof method.targetType !== "string" || !APPLICATION_METHOD_TARGET_TYPES.includes(method.targetType)) {
|
|
14719
|
-
push(errors, `${methodPath}.targetType`, "invalid-value", `"${String(method.targetType)}" is not a target type`, APPLICATION_METHOD_TARGET_TYPES);
|
|
14720
|
-
}
|
|
14721
|
-
if (method.allocation !== void 0 && !APPLICATION_METHOD_ALLOCATIONS.includes(method.allocation)) {
|
|
14722
|
-
push(errors, `${methodPath}.allocation`, "invalid-value", `"${String(method.allocation)}" is not an allocation`, APPLICATION_METHOD_ALLOCATIONS);
|
|
14723
|
-
}
|
|
14724
|
-
for (const field2 of ["maxQuantity", "applyToQuantity", "buyRulesMinQuantity"]) {
|
|
14725
|
-
const value = method[field2];
|
|
14726
|
-
if (value !== void 0 && value !== null && (typeof value !== "number" || value < 1)) {
|
|
14727
|
-
push(errors, `${methodPath}.${field2}`, "invalid-value", `${field2} is a positive integer when set`);
|
|
14728
|
-
}
|
|
14729
|
-
}
|
|
14730
|
-
validateRuleList(errors, `${methodPath}.targetRules`, method.targetRules);
|
|
14731
|
-
validateRuleList(errors, `${methodPath}.buyRules`, method.buyRules);
|
|
14732
|
-
});
|
|
14733
|
-
}
|
|
14734
|
-
function validateHandleRef(errors, path, name) {
|
|
14735
|
-
if (typeof name !== "string" || !name) {
|
|
14736
|
-
push(errors, path, "invalid-value", "a code reference is a registered handle name (string)");
|
|
14737
|
-
return;
|
|
14738
|
-
}
|
|
14739
|
-
if (!hasHandle(name)) {
|
|
14740
|
-
push(errors, path, "unknown-handle", `handle "${name}" is not registered`, listHandles());
|
|
14741
|
-
}
|
|
14742
|
-
}
|
|
14743
|
-
function validateCode(errors, section) {
|
|
14744
|
-
for (const field2 of ["logo", "provider", "auth", "footerCredit"]) {
|
|
14745
|
-
if (section[field2] !== void 0) validateHandleRef(errors, `code.${field2}`, section[field2]);
|
|
14746
|
-
}
|
|
14747
|
-
const components = section.components;
|
|
14748
|
-
if (isRecord(components)) {
|
|
14749
|
-
for (const [slot, handle] of Object.entries(components)) {
|
|
14750
|
-
const slotPath = `code.components.${slot}`;
|
|
14751
|
-
if (!STOREFRONT_COMPONENT_KEYS.includes(slot)) {
|
|
14752
|
-
push(
|
|
14753
|
-
errors,
|
|
14754
|
-
slotPath,
|
|
14755
|
-
"unknown-component-slot",
|
|
14756
|
-
`"${slot}" is not an overridable storefront component`,
|
|
14757
|
-
STOREFRONT_COMPONENT_KEYS
|
|
14758
|
-
);
|
|
14759
|
-
continue;
|
|
14760
|
-
}
|
|
14761
|
-
validateHandleRef(errors, slotPath, handle);
|
|
14762
|
-
}
|
|
14763
|
-
}
|
|
14764
|
-
const routes = section.routes;
|
|
14765
|
-
if (Array.isArray(routes)) {
|
|
14766
|
-
routes.forEach((route, index) => {
|
|
14767
|
-
const routePath = `code.routes[${index}]`;
|
|
14768
|
-
if (!isRecord(route)) {
|
|
14769
|
-
push(errors, routePath, "invalid-value", "a route is {id, path, kind?, chrome?, component}");
|
|
14770
|
-
return;
|
|
14771
|
-
}
|
|
14772
|
-
for (const required of ["id", "path"]) {
|
|
14773
|
-
if (typeof route[required] !== "string" || !route[required]) {
|
|
14774
|
-
push(errors, `${routePath}.${required}`, "missing-field", `route requires a string "${required}"`);
|
|
14775
|
-
}
|
|
14776
|
-
}
|
|
14777
|
-
for (const key of Object.keys(route)) {
|
|
14778
|
-
if (!CODE_ROUTE_KEYS.includes(key)) {
|
|
14779
|
-
push(errors, `${routePath}.${key}`, "unknown-field", `a route has no field "${key}"`, CODE_ROUTE_KEYS);
|
|
14780
|
-
}
|
|
14781
|
-
}
|
|
14782
|
-
if (route.kind !== void 0 && !STORE_ROUTE_KINDS.includes(route.kind)) {
|
|
14783
|
-
push(
|
|
14784
|
-
errors,
|
|
14785
|
-
`${routePath}.kind`,
|
|
14786
|
-
"invalid-value",
|
|
14787
|
-
`"${String(route.kind)}" is not a route kind`,
|
|
14788
|
-
STORE_ROUTE_KINDS
|
|
14789
|
-
);
|
|
14790
|
-
}
|
|
14791
|
-
if (route.chrome !== void 0 && !STORE_ROUTE_CHROMES.includes(route.chrome)) {
|
|
14792
|
-
push(
|
|
14793
|
-
errors,
|
|
14794
|
-
`${routePath}.chrome`,
|
|
14795
|
-
"invalid-value",
|
|
14796
|
-
`"${String(route.chrome)}" is not a route chrome`,
|
|
14797
|
-
STORE_ROUTE_CHROMES
|
|
14798
|
-
);
|
|
14799
|
-
}
|
|
14800
|
-
validateHandleRef(errors, `${routePath}.component`, route.component);
|
|
14801
|
-
});
|
|
14802
|
-
}
|
|
14803
|
-
}
|
|
14804
|
-
function validateStore(doc) {
|
|
14805
|
-
registerStorefrontBlocks();
|
|
14806
|
-
const errors = [];
|
|
14807
|
-
knownEntities = new Set(listEntityDeclarations());
|
|
14808
|
-
if (isRecord(doc)) {
|
|
14809
|
-
const entitiesSection = doc.entities;
|
|
14810
|
-
if (isRecord(entitiesSection) && isRecord(entitiesSection.definitions)) {
|
|
14811
|
-
for (const key of Object.keys(entitiesSection.definitions)) knownEntities.add(key);
|
|
14812
|
-
}
|
|
14813
|
-
}
|
|
14814
|
-
if (!isRecord(doc)) {
|
|
14815
|
-
push(errors, "", "invalid-document", `a store document is an object, got ${doc === null ? "null" : typeof doc}`);
|
|
14816
|
-
return { ok: false, errors };
|
|
14817
|
-
}
|
|
14818
|
-
if (doc.$kind !== STORE_DOCUMENT_KIND) {
|
|
14819
|
-
push(
|
|
14820
|
-
errors,
|
|
14821
|
-
"$kind",
|
|
14822
|
-
"invalid-document",
|
|
14823
|
-
`expected $kind "${STORE_DOCUMENT_KIND}", got ${JSON.stringify(doc.$kind)}`,
|
|
14824
|
-
[STORE_DOCUMENT_KIND]
|
|
14825
|
-
);
|
|
14826
|
-
}
|
|
14827
|
-
if (doc.store === void 0) {
|
|
14828
|
-
push(errors, "store", "missing-section", 'the "store" section (name/currency/locale) is required', [
|
|
14829
|
-
...STORE_SECTION_NAMES
|
|
14830
|
-
]);
|
|
14831
|
-
}
|
|
14832
|
-
for (const [name, section] of Object.entries(doc)) {
|
|
14833
|
-
if (name === "$kind") continue;
|
|
14834
|
-
if (!STORE_SECTION_NAMES.includes(name)) {
|
|
14835
|
-
push(errors, name, "unknown-section", `"${name}" is not a document section`, STORE_SECTION_NAMES);
|
|
14836
|
-
continue;
|
|
14837
|
-
}
|
|
14838
|
-
if (!isRecord(section)) {
|
|
14839
|
-
push(errors, name, "invalid-value", `section "${name}" must be an object with a version`);
|
|
14840
|
-
continue;
|
|
14841
|
-
}
|
|
14842
|
-
const sectionName = name;
|
|
14843
|
-
if (!validateSectionEnvelope(errors, sectionName, section)) continue;
|
|
14844
|
-
if (sectionName === "theme") validateTheme(errors, section);
|
|
14845
|
-
if (sectionName === "entities") validateEntitiesSection(errors, section);
|
|
14846
|
-
if (sectionName === "promotions") validatePromotionsSection(errors, section);
|
|
14847
|
-
if (sectionName === "commerce") validateCommerce(errors, section);
|
|
14848
|
-
if (sectionName === "presentation") validatePresentation(errors, section);
|
|
14849
|
-
if (sectionName === "code") validateCode(errors, section);
|
|
14850
|
-
}
|
|
14851
|
-
return { ok: errors.length === 0, errors };
|
|
14852
|
-
}
|
|
14853
|
-
function slugifyStoreName(name) {
|
|
14854
|
-
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "app";
|
|
14855
|
-
}
|
|
14856
|
-
function codeRef(value, configPath, handleSuffix, ctx) {
|
|
14857
|
-
const existing = handleNameFor(value);
|
|
14858
|
-
if (existing) return existing;
|
|
14859
|
-
const name = `${ctx.appId}.${handleSuffix}`;
|
|
14860
|
-
if (!ctx.autoRegister) {
|
|
14861
|
-
throw new Error(
|
|
14862
|
-
`exportStore: config.${configPath} holds code that is not a registered handle. Call registerHandle('${name}', value) before exporting, or export with { registerMissingHandles: true } (defineStorefront does).`
|
|
14863
|
-
);
|
|
14864
|
-
}
|
|
14865
|
-
registerHandle(
|
|
14866
|
-
name,
|
|
14867
|
-
value,
|
|
14868
|
-
{ description: `Auto-registered from config.${configPath}`, source: "app" },
|
|
14869
|
-
// The app re-declaring its config (module re-evaluation, HMR) re-derives
|
|
14870
|
-
// the same name for a fresh value; replacing is the correct semantics.
|
|
14871
|
-
{ replace: true }
|
|
14872
|
-
);
|
|
14873
|
-
return name;
|
|
14874
|
-
}
|
|
14875
|
-
function findNonJsonPath(value, path) {
|
|
14876
|
-
if (value === null || value === void 0) return null;
|
|
14877
|
-
const t = typeof value;
|
|
14878
|
-
if (t === "string" || t === "number" || t === "boolean") return null;
|
|
14879
|
-
if (Array.isArray(value)) {
|
|
14880
|
-
for (let i = 0; i < value.length; i++) {
|
|
14881
|
-
const found = findNonJsonPath(value[i], `${path}[${i}]`);
|
|
14882
|
-
if (found) return found;
|
|
14883
|
-
}
|
|
14884
|
-
return null;
|
|
14885
|
-
}
|
|
14886
|
-
if (t === "object") {
|
|
14887
|
-
const record = value;
|
|
14888
|
-
if ("$$typeof" in record) return path;
|
|
14889
|
-
const proto = Object.getPrototypeOf(record);
|
|
14890
|
-
if (proto !== Object.prototype && proto !== null) return path;
|
|
14891
|
-
for (const [key, child] of Object.entries(record)) {
|
|
14892
|
-
const found = findNonJsonPath(child, `${path}.${key}`);
|
|
14893
|
-
if (found) return found;
|
|
14894
|
-
}
|
|
14895
|
-
return null;
|
|
14896
|
-
}
|
|
14897
|
-
return path;
|
|
14898
|
-
}
|
|
14899
|
-
function hasContent(section) {
|
|
14900
|
-
return Object.keys(section).some((key) => key !== "version");
|
|
14901
|
-
}
|
|
14902
|
-
function exportStore(config, options = {}) {
|
|
14903
|
-
const ctx = {
|
|
14904
|
-
appId: options.appId ?? slugifyStoreName(config.name),
|
|
14905
|
-
autoRegister: options.registerMissingHandles ?? false
|
|
14906
|
-
};
|
|
14907
|
-
const code = { version: 1 };
|
|
14908
|
-
let presentationLogo;
|
|
14909
|
-
if (config.logo !== void 0) {
|
|
14910
|
-
if (typeof config.logo === "string") presentationLogo = config.logo;
|
|
14911
|
-
else code.logo = codeRef(config.logo, "logo", "logo", ctx);
|
|
14912
|
-
}
|
|
14913
|
-
let footerData;
|
|
14914
|
-
if (config.footer !== void 0) {
|
|
14915
|
-
const { credit, ...rest } = config.footer;
|
|
14916
|
-
if (credit === void 0 || typeof credit === "string") {
|
|
14917
|
-
footerData = config.footer;
|
|
14918
|
-
} else {
|
|
14919
|
-
footerData = rest;
|
|
14920
|
-
code.footerCredit = codeRef(credit, "footer.credit", "footer-credit", ctx);
|
|
14921
|
-
}
|
|
14922
|
-
}
|
|
14923
|
-
let searchData;
|
|
14924
|
-
if (config.search !== void 0) {
|
|
14925
|
-
const { renderSuggestion, ...rest } = config.search;
|
|
14926
|
-
searchData = rest;
|
|
14927
|
-
if (renderSuggestion !== void 0) {
|
|
14928
|
-
code.searchRenderSuggestion = codeRef(
|
|
14929
|
-
renderSuggestion,
|
|
14930
|
-
"search.renderSuggestion",
|
|
14931
|
-
"search-render-suggestion",
|
|
14932
|
-
ctx
|
|
14933
|
-
);
|
|
14934
|
-
}
|
|
14935
|
-
}
|
|
14936
|
-
let authData;
|
|
14937
|
-
if (config.auth !== void 0) {
|
|
14938
|
-
if (isJsonValue(config.auth)) authData = config.auth;
|
|
14939
|
-
else code.auth = codeRef(config.auth, "auth", "auth", ctx);
|
|
14940
|
-
}
|
|
14941
|
-
if (config.provider !== void 0) {
|
|
14942
|
-
code.provider = codeRef(config.provider, "provider", "provider", ctx);
|
|
14943
|
-
}
|
|
14944
|
-
if (config.components !== void 0) {
|
|
14945
|
-
const componentRefs = {};
|
|
14946
|
-
for (const [key, override] of Object.entries(config.components)) {
|
|
14947
|
-
if (override === void 0) continue;
|
|
14948
|
-
componentRefs[key] = codeRef(override, `components.${key}`, `components.${key}`, ctx);
|
|
14949
|
-
}
|
|
14950
|
-
if (Object.keys(componentRefs).length > 0) code.components = componentRefs;
|
|
14951
|
-
}
|
|
14952
|
-
if (config.routes !== void 0 && config.routes.length > 0) {
|
|
14953
|
-
code.routes = config.routes.map(
|
|
14954
|
-
(route) => compact({
|
|
14955
|
-
id: route.id,
|
|
14956
|
-
path: route.path,
|
|
14957
|
-
kind: route.kind,
|
|
14958
|
-
chrome: route.chrome,
|
|
14959
|
-
component: codeRef(route.component, `routes[${route.id}].component`, `routes.${route.id}`, ctx)
|
|
14960
|
-
})
|
|
14961
|
-
);
|
|
14962
|
-
}
|
|
14963
|
-
const sections = {
|
|
14964
|
-
store: compact({
|
|
14965
|
-
version: 1,
|
|
14966
|
-
name: config.name,
|
|
14967
|
-
currency: config.currency,
|
|
14968
|
-
locale: config.locale
|
|
14969
|
-
}),
|
|
14970
|
-
theme: config.theme ? { version: 1, ...compact(config.theme) } : { version: 1 },
|
|
14971
|
-
commerce: compact({
|
|
14972
|
-
version: 1,
|
|
14973
|
-
commerceMode: config.commerceMode,
|
|
14974
|
-
shipping: config.shipping,
|
|
14975
|
-
payments: config.payments,
|
|
14976
|
-
discounts: config.discounts,
|
|
14977
|
-
enquiry: config.enquiry,
|
|
14978
|
-
features: config.features
|
|
14979
|
-
}),
|
|
14980
|
-
presentation: compact({
|
|
14981
|
-
version: 1,
|
|
14982
|
-
announcement: config.announcement,
|
|
14983
|
-
logo: presentationLogo,
|
|
14984
|
-
home: config.home,
|
|
14985
|
-
pages: config.pages,
|
|
14986
|
-
slots: config.slots,
|
|
14987
|
-
nav: config.nav,
|
|
14988
|
-
footer: footerData,
|
|
14989
|
-
imageLoading: config.imageLoading,
|
|
14990
|
-
catalogFacets: config.catalogFacets,
|
|
14991
|
-
productSpecs: config.productSpecs,
|
|
14992
|
-
search: searchData
|
|
14993
|
-
}),
|
|
14994
|
-
content: compact({ version: 1, legal: config.legal, reviews: config.reviews }),
|
|
14995
|
-
catalog: config.catalog ? { version: 1, ...compact(config.catalog) } : { version: 1 },
|
|
14996
|
-
entities: config.entities ? { version: 1, definitions: config.entities } : { version: 1 },
|
|
14997
|
-
promotions: config.promotions ? { version: 1, promotions: config.promotions } : { version: 1 },
|
|
14998
|
-
backend: compact({
|
|
14999
|
-
version: 1,
|
|
15000
|
-
provider: config.backend?.provider,
|
|
15001
|
-
url: config.backend?.url,
|
|
15002
|
-
supabaseUrl: config.supabaseUrl,
|
|
15003
|
-
supabaseAnonKey: config.supabaseAnonKey
|
|
15004
|
-
}),
|
|
15005
|
-
auth: authData ? { version: 1, ...compact(authData) } : { version: 1 },
|
|
15006
|
-
code: compact(code)
|
|
15007
|
-
};
|
|
15008
|
-
const include = {
|
|
15009
|
-
theme: config.theme !== void 0,
|
|
15010
|
-
catalog: config.catalog !== void 0,
|
|
15011
|
-
entities: config.entities !== void 0,
|
|
15012
|
-
promotions: config.promotions !== void 0,
|
|
15013
|
-
auth: authData !== void 0,
|
|
15014
|
-
commerce: hasContent(sections.commerce),
|
|
15015
|
-
presentation: hasContent(sections.presentation),
|
|
15016
|
-
content: hasContent(sections.content),
|
|
15017
|
-
backend: hasContent(sections.backend),
|
|
15018
|
-
code: hasContent(sections.code)
|
|
15019
|
-
};
|
|
15020
|
-
const doc = { $kind: STORE_DOCUMENT_KIND, store: sections.store };
|
|
15021
|
-
for (const name of ["theme", "commerce", "presentation", "content", "catalog", "entities", "promotions", "backend", "auth", "code"]) {
|
|
15022
|
-
if (include[name]) doc[name] = sections[name];
|
|
15023
|
-
}
|
|
15024
|
-
for (const [name, section] of Object.entries(doc)) {
|
|
15025
|
-
if (name === "$kind") continue;
|
|
15026
|
-
const offending = findNonJsonPath(section, name);
|
|
15027
|
-
if (offending) {
|
|
15028
|
-
throw new Error(
|
|
15029
|
-
`exportStore: ${offending} holds a non-serializable value. Code belongs in a registered handle (registerHandle) referenced from the document's code section \u2014 data sections must be pure JSON.`
|
|
15030
|
-
);
|
|
15031
|
-
}
|
|
15032
|
-
}
|
|
15033
|
-
return doc;
|
|
15034
|
-
}
|
|
15035
|
-
function formatErrors(errors) {
|
|
15036
|
-
return errors.map((e) => ` - ${e.path || "(document)"}: ${e.message}${e.valid ? ` (valid: ${e.valid.join(", ")})` : ""}`).join("\n");
|
|
15037
|
-
}
|
|
15038
|
-
function hydrateStoreDocument(input, options = {}) {
|
|
15039
|
-
const onError = options.onError ?? "throw";
|
|
15040
|
-
const report = validateStore(input);
|
|
15041
|
-
if (!report.ok) {
|
|
15042
|
-
const message = `Store document failed validation:
|
|
15043
|
-
${formatErrors(report.errors)}`;
|
|
15044
|
-
if (onError === "throw") throw new Error(message);
|
|
15045
|
-
console.error(`[storefront] ${message}`);
|
|
15046
|
-
}
|
|
15047
|
-
const doc = input;
|
|
15048
|
-
const resolve = (name, path) => {
|
|
15049
|
-
try {
|
|
15050
|
-
return resolveHandle(name);
|
|
15051
|
-
} catch (err) {
|
|
15052
|
-
if (onError === "throw") throw err;
|
|
15053
|
-
console.error(`[storefront] dropping ${path}: ${errorMessage(err)}`);
|
|
15054
|
-
return void 0;
|
|
15055
|
-
}
|
|
15056
|
-
};
|
|
15057
|
-
const config = { name: doc.store?.name ?? "" };
|
|
15058
|
-
const set = (key, value) => {
|
|
15059
|
-
if (value !== void 0) config[key] = value;
|
|
15060
|
-
};
|
|
15061
|
-
set("currency", doc.store?.currency);
|
|
15062
|
-
set("locale", doc.store?.locale);
|
|
15063
|
-
if (doc.theme) {
|
|
15064
|
-
const { version: _v, ...theme } = doc.theme;
|
|
15065
|
-
set("theme", theme);
|
|
15066
|
-
}
|
|
15067
|
-
if (doc.commerce) {
|
|
15068
|
-
set("commerceMode", doc.commerce.commerceMode);
|
|
15069
|
-
set("shipping", doc.commerce.shipping);
|
|
15070
|
-
set("payments", doc.commerce.payments);
|
|
15071
|
-
set("discounts", doc.commerce.discounts);
|
|
15072
|
-
set("enquiry", doc.commerce.enquiry);
|
|
15073
|
-
set("features", doc.commerce.features);
|
|
15074
|
-
}
|
|
15075
|
-
if (doc.presentation) {
|
|
15076
|
-
set("announcement", doc.presentation.announcement);
|
|
15077
|
-
set("home", doc.presentation.home);
|
|
15078
|
-
set("pages", doc.presentation.pages);
|
|
15079
|
-
set("slots", doc.presentation.slots);
|
|
15080
|
-
set("nav", doc.presentation.nav);
|
|
15081
|
-
set("imageLoading", doc.presentation.imageLoading);
|
|
15082
|
-
set("catalogFacets", doc.presentation.catalogFacets);
|
|
15083
|
-
set("productSpecs", doc.presentation.productSpecs);
|
|
15084
|
-
set("search", doc.presentation.search);
|
|
15085
|
-
if (doc.presentation.logo !== void 0) set("logo", doc.presentation.logo);
|
|
15086
|
-
}
|
|
15087
|
-
if (doc.content) {
|
|
15088
|
-
set("legal", doc.content.legal);
|
|
15089
|
-
set("reviews", doc.content.reviews);
|
|
15090
|
-
}
|
|
15091
|
-
if (doc.catalog) {
|
|
15092
|
-
const { version: _v, ...seed } = doc.catalog;
|
|
15093
|
-
set("catalog", seed);
|
|
15094
|
-
}
|
|
15095
|
-
if (doc.entities?.definitions) set("entities", doc.entities.definitions);
|
|
15096
|
-
if (doc.promotions?.promotions) set("promotions", doc.promotions.promotions);
|
|
15097
|
-
if (doc.backend) {
|
|
15098
|
-
const { provider, url, supabaseUrl, supabaseAnonKey } = doc.backend;
|
|
15099
|
-
if (provider !== void 0 || url !== void 0) set("backend", compact({ provider, url }));
|
|
15100
|
-
set("supabaseUrl", supabaseUrl);
|
|
15101
|
-
set("supabaseAnonKey", supabaseAnonKey);
|
|
15102
|
-
}
|
|
15103
|
-
if (doc.auth) {
|
|
15104
|
-
const { version: _v, ...auth } = doc.auth;
|
|
15105
|
-
set("auth", auth);
|
|
15106
|
-
}
|
|
15107
|
-
const code = doc.code;
|
|
15108
|
-
if (code) {
|
|
15109
|
-
if (code.logo) set("logo", resolve(code.logo, "code.logo"));
|
|
15110
|
-
if (code.provider) set("provider", resolve(code.provider, "code.provider"));
|
|
15111
|
-
if (code.auth) set("auth", resolve(code.auth, "code.auth"));
|
|
15112
|
-
if (code.components) {
|
|
15113
|
-
const components = {};
|
|
15114
|
-
for (const [key, handle] of Object.entries(code.components)) {
|
|
15115
|
-
const value = resolve(handle, `code.components.${key}`);
|
|
15116
|
-
if (value !== void 0) components[key] = value;
|
|
15117
|
-
}
|
|
15118
|
-
if (Object.keys(components).length > 0) set("components", components);
|
|
15119
|
-
}
|
|
15120
|
-
if (code.routes) {
|
|
15121
|
-
const routes = [];
|
|
15122
|
-
for (const route of code.routes) {
|
|
15123
|
-
const component = resolve(
|
|
15124
|
-
route.component,
|
|
15125
|
-
`code.routes[${route.id}].component`
|
|
15126
|
-
);
|
|
15127
|
-
if (component === void 0) continue;
|
|
15128
|
-
routes.push(
|
|
15129
|
-
compact({
|
|
15130
|
-
id: route.id,
|
|
15131
|
-
path: route.path,
|
|
15132
|
-
kind: route.kind,
|
|
15133
|
-
chrome: route.chrome,
|
|
15134
|
-
component
|
|
15135
|
-
})
|
|
15136
|
-
);
|
|
15137
|
-
}
|
|
15138
|
-
if (routes.length > 0) set("routes", routes);
|
|
15139
|
-
}
|
|
15140
|
-
if (code.searchRenderSuggestion) {
|
|
15141
|
-
const renderSuggestion = resolve(
|
|
15142
|
-
code.searchRenderSuggestion,
|
|
15143
|
-
"code.searchRenderSuggestion"
|
|
15144
|
-
);
|
|
15145
|
-
if (renderSuggestion !== void 0) {
|
|
15146
|
-
set("search", { ...doc.presentation?.search ?? {}, renderSuggestion });
|
|
15147
|
-
}
|
|
15148
|
-
}
|
|
15149
|
-
if (code.footerCredit) {
|
|
15150
|
-
const credit = resolve(code.footerCredit, "code.footerCredit");
|
|
15151
|
-
if (credit !== void 0) {
|
|
15152
|
-
set("footer", { ...doc.presentation?.footer ?? {}, credit });
|
|
15153
|
-
}
|
|
15154
|
-
}
|
|
15155
|
-
}
|
|
15156
|
-
if (config.footer === void 0 && doc.presentation?.footer !== void 0) {
|
|
15157
|
-
set("footer", doc.presentation.footer);
|
|
15158
|
-
}
|
|
15159
|
-
return config;
|
|
15160
|
-
}
|
|
15161
|
-
|
|
15162
|
-
export { AddressForm, AddressSheet, AddressStrip, BEFORE_PLACE_ORDER_VALVE, BLOCK_STRUCTURAL_KEYS, BUYER_COUNTRY_COOKIE, BenefitsRow, BlockDataError, CART_LINE_ANNOTATION_POINT, CATALOG_BODY_BLOCK, CHECKOUT_FIELD_POINT, CartDrawer, CatalogPage, CategoryShowcase, CheckoutPage, ClosedStoreDialog, CollectionCta, CollectionHero, ContentPage, CountdownBand, CountrySelect, DeliverToPicker, EmailConfirmationRequiredError, EntityListBlock, FaqSection, FiltersPanel, FormBlock, HeroSection, ImageTiles, ItemSheet, Link, MESSAGES, ManifestoBlock, MediaCarousel, MenuItemRow, MenuPage, MenuToolbar, 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, ScheduleSheet, SealsBand, SearchOverlay, ServiceHoursModal, Slot, SmoothImage, StepsSection, StoreCover, StorefrontAnalytics, StorefrontConfigHost, StorefrontConfigProvider, StorefrontFooter, StorefrontHeader, StorefrontPage, StorefrontRouterProvider, StorefrontShell, StorefrontThemeStyle, StoryQuote, THEME_SCALE_FIELDS, THEME_SCALE_VAR_PREFIX, TID, Testimonials, TierCards, applyDeliveryPolicy, applyStoreSettings, bannerPlaceholder, blockInstanceId, buildEnquiryFromForm, checkPageBlocks, collectDataNeeds, collectOrderMetadata, contentPagePath, createStorefront, createStorefrontApp, currentStaticRenderPass, defaultPageBlocks, entityListBlockMeta, establishCustomerSession, exportStore, formatMoney, formatProductOptionSelection, getCartLineAnnotations, getCheckoutFieldContributions, getCustomerAuthAdapter, getProductCardBadges, getProductOptionGroups, hydrateStoreDocument, hydratedEntriesFor, identifyStorefrontBuyer, initStorefrontRuntime, isJsonValue, isKnownPath, isNestedBlockRef, isPublicPath, isRecord, listSlots, marketForCountry, marketUnitPrice, matchContentPage, matchPath, matchesFacets, mergeCollectionFacet, mergePageTheme, navigateTo, nextMilestone, normalizeLanguage, normalizeProductOptionSelection, onStorefrontEvent, 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, selectIsOpen, selectRequiresShipping, selectShipping, selectShowsHours, selectSubtotal, selectTotal, selectionPrice, serializePageData, shellRouterAdapter, signInByEmail, signOutCustomer, signUpCustomer, slugifyStoreName, startStorefrontPostHog, storeBuyerId, storefrontComponentContracts, storefrontPaths, themeToCss, toBlockNodes, toFacetMap, trackStorefront, translate, useBlockData, useBuyerCountry, useBuyerStore, useCartStore, useCatalogStore, useCategories, useDeliveryStore, useDiscountValidator, useEnquiry, useHashPath, useInView, useLoader, useMarketProduct, useMarketStore, useMyOrders, useNavigate, usePopOnChange, useProduct, useProducts, useRoutePath, useRouterAdapter, useScrollToTopOnNavigate, useScrolled, useServiceStore, useSessionStore, useSlotContext, useStorefrontActions, useStorefrontConfig, useStorefrontConfigOptional, useStorefrontHead, useStorefrontPage, useStorefrontPageOptional, useT, usedSlots, validateStore, withFacet, withMarketPrice, withStaticRenderPass };
|
|
15163
|
-
//# sourceMappingURL=chunk-6H5VD6OB.js.map
|
|
15164
|
-
//# sourceMappingURL=chunk-6H5VD6OB.js.map
|
|
12769
|
+
export { AddressForm, AddressSheet, AddressStrip, BEFORE_PLACE_ORDER_VALVE, BUYER_COUNTRY_COOKIE, BenefitsRow, CART_LINE_ANNOTATION_POINT, CHECKOUT_FIELD_POINT, CartDrawer, CatalogPage, CategoryShowcase, CheckoutPage, ClosedStoreDialog, CollectionCta, CollectionHero, ContentPage, CountdownBand, CountrySelect, DeliverToPicker, EmailConfirmationRequiredError, EntityListBlock, FaqSection, FiltersPanel, FormBlock, HeroSection, ImageTiles, ItemSheet, ManifestoBlock, MediaCarousel, MenuItemRow, MenuPage, MenuToolbar, MotifStrip, MyPurchasesPage, NewsletterBand, ORDER_METADATA_POINT, OrderConfirmationPage, OrderTrackingTimeline, PAGE_DATA_SCRIPT_ID, PLACEHOLDER_ASPECTS, PRODUCT_CARD_BADGE_POINT, PaymentTerms, Price, ProductCard, ProductDetailPage, ProductEnquiryForm, ProductGallery, ProductGrid, ProductOptionSelector, ProductRail, ProductReviews, ProductSlider, ProductSpecs, ProductSpotlight, PromoBanner, QuantityInput, Reveal, STOREFRONT_SLOTS, ScheduleSheet, SealsBand, SearchOverlay, ServiceHoursModal, Slot, SmoothImage, StepsSection, StoreCover, StorefrontAnalytics, StorefrontConfigHost, StorefrontFooter, StorefrontHeader, StorefrontPage, StorefrontShell, StorefrontThemeStyle, StoryQuote, THEME_SCALE_FIELDS, THEME_SCALE_VAR_PREFIX, TID, Testimonials, TierCards, applyDeliveryPolicy, applyStoreSettings, bannerPlaceholder, buildEnquiryFromForm, collectOrderMetadata, createStorefront, createStorefrontApp, entityListBlockMeta, establishCustomerSession, formatMoney, formatProductOptionSelection, getCartLineAnnotations, getCheckoutFieldContributions, getCustomerAuthAdapter, getProductCardBadges, getProductOptionGroups, hydratedEntriesFor, identifyStorefrontBuyer, initStorefrontRuntime, listSlots, marketForCountry, marketUnitPrice, matchesFacets, mergeCollectionFacet, nextMilestone, normalizeProductOptionSelection, onStorefrontEvent, orderGalleryImages, overrideComponent, overrideProps, pickProductCardImage, placeStorefrontOrder, prefersReducedMotion, productCardComponentContract, productOptionSelectionKey, productPlaceholder, readHydratedPageData, registerStorefrontBlocks, registerStorefrontEntities, registerStorefrontExtensionPoints, registerStorefrontLoaders, resetPageDiagnostics, resetProductOptionsDeprecationWarnings, resetStorefrontExtensionPoints, resolveAuthAdapter, resolveOverride, resolvePaymentTerms, resolveStorefrontProvider, resolveVariantForSelection, roundCents, runBeforePlaceOrderValve, sectionsToBlocks, selectCount, selectDiscountTotal, selectIsOpen, selectRequiresShipping, selectShipping, selectShowsHours, selectSubtotal, selectTotal, selectionPrice, serializePageData, signInByEmail, signOutCustomer, signUpCustomer, startStorefrontPostHog, storeBuyerId, storefrontComponentContracts, themeToCss, toFacetMap, trackStorefront, useBuyerCountry, useBuyerStore, useCartStore, useCatalogStore, useCategories, useDeliveryStore, useDiscountValidator, useEnquiry, useInView, useMarketProduct, useMarketStore, useMyOrders, usePopOnChange, useProduct, useProducts, useScrolled, useServiceStore, useSessionStore, useSlotContext, useStorefrontActions, useStorefrontHead, useStorefrontPage, useStorefrontPageOptional, useT, usedSlots, withFacet, withMarketPrice };
|
|
12770
|
+
//# sourceMappingURL=chunk-CWHGBPRP.js.map
|
|
12771
|
+
//# sourceMappingURL=chunk-CWHGBPRP.js.map
|