@fayz-ai/storefront 0.46.0 → 0.47.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.
Files changed (50) hide show
  1. package/dist/{chunk-NH55KVUY.js → chunk-DK3KK373.js} +1219 -412
  2. package/dist/chunk-DK3KK373.js.map +1 -0
  3. package/dist/components/cart/CartDrawer.d.ts.map +1 -1
  4. package/dist/components/checkout/AddressForm.d.ts +39 -0
  5. package/dist/components/checkout/AddressForm.d.ts.map +1 -0
  6. package/dist/components/checkout/CheckoutField.d.ts +16 -0
  7. package/dist/components/checkout/CheckoutField.d.ts.map +1 -0
  8. package/dist/components/checkout/CheckoutSteps.d.ts.map +1 -1
  9. package/dist/components/checkout/DeliveryEstimator.d.ts.map +1 -1
  10. package/dist/components/delivery/DeliverToPicker.d.ts +19 -0
  11. package/dist/components/delivery/DeliverToPicker.d.ts.map +1 -0
  12. package/dist/components/layout/SearchOverlay.d.ts.map +1 -1
  13. package/dist/components/marketing/CollectionSections.d.ts.map +1 -1
  14. package/dist/components/product/ProductCard.d.ts +1 -1
  15. package/dist/components/product/ProductCard.d.ts.map +1 -1
  16. package/dist/document/config.d.ts +27 -1
  17. package/dist/document/config.d.ts.map +1 -1
  18. package/dist/document/store-policy.d.ts +12 -1
  19. package/dist/document/store-policy.d.ts.map +1 -1
  20. package/dist/hooks/index.d.ts +2 -0
  21. package/dist/hooks/index.d.ts.map +1 -1
  22. package/dist/hooks/use-buyer-country.d.ts +21 -0
  23. package/dist/hooks/use-buyer-country.d.ts.map +1 -0
  24. package/dist/hooks/use-market-product.d.ts +9 -0
  25. package/dist/hooks/use-market-product.d.ts.map +1 -0
  26. package/dist/hooks/use-payment-methods.d.ts.map +1 -1
  27. package/dist/index.d.ts +10 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +5 -3
  30. package/dist/index.js.map +1 -1
  31. package/dist/lib/checkout-address.d.ts +21 -0
  32. package/dist/lib/checkout-address.d.ts.map +1 -0
  33. package/dist/locales/index.d.ts +10 -0
  34. package/dist/locales/index.d.ts.map +1 -0
  35. package/dist/locales/messages.d.ts +140 -0
  36. package/dist/locales/messages.d.ts.map +1 -0
  37. package/dist/render.js +1 -1
  38. package/dist/stores/buyer.store.d.ts +18 -0
  39. package/dist/stores/buyer.store.d.ts.map +1 -0
  40. package/dist/stores/cart.store.d.ts +6 -0
  41. package/dist/stores/cart.store.d.ts.map +1 -1
  42. package/dist/stores/delivery.store.d.ts +13 -2
  43. package/dist/stores/delivery.store.d.ts.map +1 -1
  44. package/dist/stores/market.store.d.ts +27 -0
  45. package/dist/stores/market.store.d.ts.map +1 -0
  46. package/dist/views/CheckoutPage.d.ts.map +1 -1
  47. package/dist/views/ProductDetailPage.d.ts.map +1 -1
  48. package/dist/workflows/checkout.d.ts.map +1 -1
  49. package/package.json +7 -7
  50. package/dist/chunk-NH55KVUY.js.map +0 -1
@@ -3,11 +3,11 @@ import { persist } from 'zustand/middleware';
3
3
  import { createAuthRuntime, createMockAuthAdapter } from '@fayz-ai/plugin-auth';
4
4
  import { getShopProvider, setShopProvider } from '@fayz-ai/shop/runtime';
5
5
  import { setShopCarrierQuotesResolver, setShopAccessTokenResolver, setShopShippingItemsResolver } from '@fayz-ai/sdk/shop';
6
- import { normalizePostalCode, lookupPostalCode, defaultRouterAdapter, defineLoader, staticRouterAdapter, isLoaderParamRef, isLoaderPropRef, resolveLoader, errorMessage, dataNeedKey, getBlockMeta, defaultPropsFromSettings, getBlockErrorVisibility, isBlockEnabledOn, checkBlockConstraints, checkBlockContext, repairBlockTree, renderBlocks, clearExtensionPoints, defineExtensionPoint, runExtensionPoint, runEscapeValve, breadcrumbJsonLd, hasEntityDeclaration, resolveEntityDeclaration, defineBlock, formatPostalCode, defineEntity, listEntityDeclarations, resolveHandle, seoOrigin, describeError, RESERVED_ENTITY_FIELDS, ENTITY_FIELD_TYPES, handleNameFor, registerHandle, hasHandle, listHandles, blockRegistry, loaderRegistry, listLoaders } from '@fayz-ai/core';
7
- import React37, { createContext, useContext, useEffect, useRef, useState, useSyncExternalStore, useMemo, useCallback } from 'react';
6
+ import { normalizePostalCode, getCountrySchema, lookupPostalCode, defaultRouterAdapter, defineLoader, staticRouterAdapter, isLoaderParamRef, isLoaderPropRef, resolveLoader, errorMessage, dataNeedKey, getBlockMeta, defaultPropsFromSettings, getBlockErrorVisibility, isBlockEnabledOn, checkBlockConstraints, checkBlockContext, repairBlockTree, renderBlocks, clearExtensionPoints, defineExtensionPoint, runExtensionPoint, runEscapeValve, breadcrumbJsonLd, hasEntityDeclaration, resolveEntityDeclaration, defineBlock, formatPostalCode, countryName, defineEntity, listEntityDeclarations, resolveHandle, seoOrigin, describeError, RESERVED_ENTITY_FIELDS, ENTITY_FIELD_TYPES, handleNameFor, registerHandle, validateAddress, hasHandle, listHandles, blockRegistry, loaderRegistry, listLoaders } from '@fayz-ai/core';
7
+ import React38, { createContext, useContext, useEffect, useRef, useState, useSyncExternalStore, useMemo, useCallback } from 'react';
8
8
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
9
- import { isStorageImageUrl, imageVariantUrl, imageSrcSet, IMAGE_SRCSET_WIDTHS, validateDiscount, documentDigits, isChargeableProvider, supportsCard, formatDocument, isValidDocument, gatewayLabel } from '@fayz-ai/shop';
10
- import { ChevronLeft, ChevronRight, ShoppingBag, X, Minus, Plus, Send, MessageCircle, Mail, Truck, RefreshCcw, ShieldCheck, ChevronDown, Check, Search, Menu, Trash2, Lock, CreditCard, Store, Bike, Clock, MapPin, Star, Phone, User, UserCircle, Package, LogOut, QrCode, Copy, XCircle, RotateCcw, PackageCheck, Info, AlertCircle } from 'lucide-react';
9
+ import { isStorageImageUrl, imageVariantUrl, imageSrcSet, IMAGE_SRCSET_WIDTHS, validateDiscount, documentDigits, isChargeableProvider, supportsCard, formatDocument, gatewayLabel, isValidDocument } from '@fayz-ai/shop';
10
+ import { ChevronLeft, ChevronRight, ShoppingBag, X, Minus, Plus, Send, MessageCircle, Mail, Truck, RefreshCcw, ShieldCheck, ChevronDown, Check, Search, Menu, Trash2, MapPin, Lock, CreditCard, Store, Bike, Clock, Star, Phone, User, UserCircle, Package, LogOut, QrCode, Copy, XCircle, RotateCcw, PackageCheck, Info, AlertCircle } from 'lucide-react';
11
11
  import { getLucideIcon } from '@fayz-ai/ui/icons';
12
12
  import { storefrontDiscountToPromotion, previewCouponPercent, discountToPromotion, PROMOTION_TYPES, PROMOTION_STATUSES, APPLICATION_METHOD_TYPES, APPLICATION_METHOD_TARGET_TYPES, APPLICATION_METHOD_ALLOCATIONS, hasRuleAttribute, listRuleAttributeKeys, RULE_OPERATORS, resolveRuleAttribute } from '@fayz-ai/shop/rules';
13
13
  import { createMockShopProvider } from '@fayz-ai/shop/mock';
@@ -155,6 +155,46 @@ async function signOutCustomer() {
155
155
  useSessionStore.getState().signOut();
156
156
  }
157
157
  }
158
+ var useMarketStore = create()((set) => ({
159
+ markets: [],
160
+ active: null,
161
+ prices: {},
162
+ setMarkets: (markets) => set({ markets }),
163
+ setActive: (active2) => set({ active: active2 }),
164
+ setPrices: (code, list) => set((state) => ({
165
+ prices: {
166
+ ...state.prices,
167
+ [code]: Object.fromEntries(list.map((p) => [`${p.productId}:${p.variantId ?? ""}`, p.price]))
168
+ }
169
+ }))
170
+ }));
171
+ function marketForCountry(markets, country) {
172
+ const iso2 = country.toUpperCase();
173
+ return markets.find((m) => m.countries.includes(iso2)) ?? markets.find((m) => m.isDefault) ?? null;
174
+ }
175
+ function marketUnitPrice(state, productId, variantId, fallback) {
176
+ const market = state.active;
177
+ if (!market) return fallback;
178
+ const list = state.prices[market.code];
179
+ const hit = list?.[`${productId}:${variantId ?? ""}`] ?? list?.[`${productId}:`];
180
+ if (hit != null) return hit;
181
+ return market.isDefault ? fallback : null;
182
+ }
183
+ function withMarketPrice(product, state = useMarketStore.getState()) {
184
+ const market = state.active;
185
+ if (!market || market.isDefault) return product;
186
+ const price = marketUnitPrice(state, product.id, null, product.price);
187
+ if (price == null) {
188
+ return { ...product, compareAtPrice: null, currency: market.currency, inventoryCount: 0, metadata: { ...product.metadata, unavailableInMarket: market.code } };
189
+ }
190
+ return {
191
+ ...product,
192
+ price,
193
+ compareAtPrice: null,
194
+ currency: market.currency,
195
+ variants: product.variants?.map((v) => ({ ...v, price: marketUnitPrice(state, product.id, v.id, v.price ?? product.price), compareAtPrice: null }))
196
+ };
197
+ }
158
198
 
159
199
  // src/lib/format.ts
160
200
  function formatMoney(value, currency = "BRL", locale = "pt-BR") {
@@ -240,11 +280,14 @@ function newAddressId() {
240
280
  }
241
281
  var EMPTY = {
242
282
  postalCode: "",
283
+ country: "BR",
243
284
  address: null,
244
285
  options: [],
245
286
  selectedZoneId: null,
246
287
  status: "idle",
247
288
  error: null,
289
+ errorKey: null,
290
+ errorVars: null,
248
291
  refusedZone: null,
249
292
  reviewZone: null
250
293
  };
@@ -263,13 +306,33 @@ var useDeliveryStore = create()(
263
306
  setScheduledFor(startsAt) {
264
307
  set({ scheduledFor: startsAt });
265
308
  },
266
- async resolve(postalCode, subtotal) {
309
+ async resolve(postalCode, subtotal, country = "BR") {
310
+ const iso2 = country.toUpperCase();
311
+ if (iso2 !== "BR") {
312
+ const schema = getCountrySchema(iso2);
313
+ const code2 = schema.postal.normalize(postalCode);
314
+ if (!schema.postal.pattern.test(code2)) {
315
+ set({
316
+ ...EMPTY,
317
+ postalCode,
318
+ country: iso2,
319
+ status: "error",
320
+ error: `Confira o c\xF3digo postal (ex.: ${schema.postal.example}).`,
321
+ errorKey: "delivery.error.postal",
322
+ errorVars: { example: schema.postal.example }
323
+ });
324
+ return;
325
+ }
326
+ const address2 = await lookupPostalCode(code2, iso2).catch(() => null);
327
+ set({ ...EMPTY, postalCode: code2, country: iso2, address: address2, status: "idle" });
328
+ return;
329
+ }
267
330
  const code = normalizePostalCode(postalCode);
268
331
  if (code.length !== 8) {
269
- set({ ...EMPTY, postalCode, status: "error", error: "Digite os 8 d\xEDgitos do CEP." });
332
+ set({ ...EMPTY, postalCode, status: "error", error: "Digite os 8 d\xEDgitos do CEP.", errorKey: "delivery.error.digits" });
270
333
  return;
271
334
  }
272
- set({ postalCode: code, status: "loading", error: null });
335
+ set({ postalCode: code, country: "BR", status: "loading", error: null, errorKey: null, errorVars: null });
273
336
  const shop = getShopProvider();
274
337
  const addressPromise = lookupPostalCode(code).catch(() => null);
275
338
  const hint = await Promise.race([
@@ -287,7 +350,8 @@ var useDeliveryStore = create()(
287
350
  ...EMPTY,
288
351
  postalCode: code,
289
352
  status: "error",
290
- error: "N\xE3o foi poss\xEDvel calcular o frete agora. Tente de novo."
353
+ error: "N\xE3o foi poss\xEDvel calcular o frete agora. Tente de novo.",
354
+ errorKey: "delivery.error.quote"
291
355
  });
292
356
  return;
293
357
  }
@@ -310,7 +374,9 @@ var useDeliveryStore = create()(
310
374
  status: options.length > 0 ? "served" : "unserved",
311
375
  // Reported alongside the price, not instead of it: the CEP may be
312
376
  // mistyped even though its range is covered.
313
- error: notFound ? "CEP n\xE3o encontrado. Confira os n\xFAmeros." : null
377
+ error: notFound ? "CEP n\xE3o encontrado. Confira os n\xFAmeros." : null,
378
+ errorKey: notFound ? "delivery.error.notFound" : null,
379
+ errorVars: null
314
380
  });
315
381
  },
316
382
  selectZone(zoneId) {
@@ -366,6 +432,7 @@ var useDeliveryStore = create()(
366
432
  // comprador ao checkout com uma janela que o servidor vai recusar.
367
433
  partialize: (state) => ({
368
434
  postalCode: state.postalCode,
435
+ country: state.country,
369
436
  address: state.address,
370
437
  fulfillmentType: state.fulfillmentType,
371
438
  // O caderno é o ponto: número e complemento são o que o comprador
@@ -376,6 +443,7 @@ var useDeliveryStore = create()(
376
443
  }),
377
444
  onRehydrateStorage: () => (state) => {
378
445
  if (state?.address) state.status = "idle";
446
+ if (state && !state.country) state.country = "BR";
379
447
  }
380
448
  }
381
449
  )
@@ -407,7 +475,9 @@ var useCartStore = create()(
407
475
  const baseId = optionKey ? `${product.id}:${optionKey}` : product.id;
408
476
  const lineId = cleanNotes ? `${baseId}#${cleanNotes}` : baseId;
409
477
  const variant = resolveVariantForSelection(product, normalizedOptions);
410
- const unitPrice = variant?.price ?? product.price;
478
+ const basePrice = variant?.price ?? product.price;
479
+ const unitPrice = marketUnitPrice(useMarketStore.getState(), product.id, variant?.id, basePrice);
480
+ if (unitPrice == null) return state;
411
481
  const stock = variant ? variant.inventoryCount : product.inventoryCount;
412
482
  const existing = state.lines.find((l) => (l.lineId ?? l.productId) === lineId);
413
483
  if (existing) {
@@ -433,6 +503,7 @@ var useCartStore = create()(
433
503
  options: normalizedOptions,
434
504
  optionsLabel: formatProductOptionSelection(normalizedOptions),
435
505
  unitPrice,
506
+ basePrice,
436
507
  quantity: Math.min(qty, stock || Infinity),
437
508
  imageUrl: image?.url ?? null,
438
509
  maxQuantity: stock,
@@ -467,6 +538,20 @@ var useCartStore = create()(
467
538
  }),
468
539
  clearDiscount: () => set({ discountCode: null, discountPercent: 0, discountFreeShipping: false }),
469
540
  clear: () => set({ lines: [], discountCode: null, discountPercent: 0, discountFreeShipping: false }),
541
+ repriceForMarket: () => set((state) => {
542
+ const market = useMarketStore.getState();
543
+ let changed = false;
544
+ const lines = state.lines.flatMap((line) => {
545
+ const price = marketUnitPrice(market, line.productId, line.variantId, line.basePrice ?? line.unitPrice);
546
+ if (price == null) {
547
+ changed = true;
548
+ return [];
549
+ }
550
+ if (price !== line.unitPrice) changed = true;
551
+ return [{ ...line, unitPrice: price }];
552
+ });
553
+ return changed ? { lines } : state;
554
+ }),
470
555
  openDrawer: () => set({ isOpen: true }),
471
556
  closeDrawer: () => set({ isOpen: false, justAddedLineId: null }),
472
557
  reconcile: async (resolve) => {
@@ -808,6 +893,423 @@ function productPlaceholder(label, w = PLACEHOLDER_ASPECTS.product[0], h = PLACE
808
893
  function escapeXml(text) {
809
894
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
810
895
  }
896
+
897
+ // src/locales/messages.ts
898
+ var ptBR = {
899
+ // Checkout shell
900
+ "checkout.title": "Checkout \u2014 {{store}}",
901
+ "checkout.backToStore": "Voltar \xE0 loja",
902
+ "checkout.secure": "Checkout seguro",
903
+ "checkout.help": "Ajuda",
904
+ "checkout.steps.label": "Etapas do checkout",
905
+ "checkout.steps.1": "Dados",
906
+ "checkout.steps.2": "Entrega",
907
+ "checkout.steps.3": "Pagamento",
908
+ "checkout.steps.4": "Pronto",
909
+ // Step 1 — contact
910
+ "checkout.contact.title": "Informa\xE7\xF5es de contato",
911
+ "checkout.contact.signedInAs": "Conectado como {{email}}",
912
+ "checkout.contact.haveAccount": "J\xE1 tem conta? Entrar",
913
+ "checkout.contact.email": "E-mail",
914
+ "checkout.contact.name": "Nome completo",
915
+ "checkout.contact.phone": "Telefone",
916
+ "checkout.contact.phoneOptional": "Telefone (opcional)",
917
+ "checkout.contact.document": "CPF ou CNPJ",
918
+ "checkout.contact.documentOptional": "CPF ou CNPJ (opcional)",
919
+ "checkout.contact.requiresAccount": "Esta loja pede uma conta para finalizar a compra.",
920
+ "checkout.contact.signInOrCreate": "Entrar ou criar conta",
921
+ // Step 2 — address
922
+ "checkout.address.title": "Endere\xE7o de entrega",
923
+ "checkout.address.loadingSaved": "Buscando seus endere\xE7os salvos",
924
+ "checkout.address.selected": "Selecionado",
925
+ "checkout.address.addNew": "+ Adicionar novo endere\xE7o",
926
+ "checkout.address.enter": "Informe o endere\xE7o de entrega",
927
+ "checkout.address.enterHint": "Preencher outro endere\xE7o para esta compra",
928
+ "checkout.address.lookingUp": "Buscando o endere\xE7o deste CEP",
929
+ "checkout.address.notFound": "CEP n\xE3o encontrado \u2014 preencha o endere\xE7o \xE0 m\xE3o.",
930
+ "checkout.address.filled": "Preenchemos o endere\xE7o para voc\xEA.",
931
+ "checkout.address.regionFromPostal": "Prov\xEDncia preenchida pelo c\xF3digo postal.",
932
+ "checkout.address.optional": "{{label}} (opcional)",
933
+ "checkout.address.choose": "Selecione",
934
+ "checkout.address.shipTo": "Enviar para",
935
+ // Step 3 — payment
936
+ "checkout.confirming.title": "Confirmando seu pedido",
937
+ "checkout.confirming.label": "Criando seu pedido",
938
+ "checkout.confirming.keepOpen": "N\xE3o feche esta p\xE1gina \u2014 estamos registrando seu pedido na loja.",
939
+ "checkout.payment.title": "Pagamento",
940
+ "checkout.payment.label": "Forma de pagamento",
941
+ "checkout.payment.cardOnline": "Voc\xEA paga na p\xE1gina segura do provedor e volta para a loja",
942
+ "checkout.payment.placeOrder": "Fazer pedido - {{total}}",
943
+ "checkout.payment.pendingNote": "O pedido fica aguardando pagamento at\xE9 a loja confirmar.",
944
+ "checkout.payment.unavailableCountry": "Esta forma de pagamento n\xE3o est\xE1 dispon\xEDvel para {{country}}.",
945
+ "payment.pix.label": "Pix",
946
+ "payment.pix.hint": "Voc\xEA recebe a chave para pagar ap\xF3s confirmar o pedido",
947
+ "payment.credit_card.label": "Cart\xE3o de cr\xE9dito",
948
+ "payment.credit_card.hint": "Maquininha na entrega",
949
+ "payment.debit_card.label": "Cart\xE3o de d\xE9bito",
950
+ "payment.debit_card.hint": "Maquininha na entrega",
951
+ "payment.boleto.label": "Boleto",
952
+ "payment.boleto.hint": "Enviado por e-mail ap\xF3s a confirma\xE7\xE3o",
953
+ "payment.cash.label": "Dinheiro",
954
+ "payment.cash.hint": "Pagamento na entrega",
955
+ "payment.other.label": "Combinar com a loja",
956
+ "payment.other.hint": "A loja entra em contato para acertar o pagamento",
957
+ // Step 4
958
+ "checkout.done.title": "Pagamento confirmado!",
959
+ "checkout.done.text": "Seu pedido foi criado e a loja j\xE1 foi avisada.",
960
+ "checkout.done.viewOrder": "Ver meu pedido",
961
+ // Navigation
962
+ "checkout.continueToDelivery": "Continuar para a entrega",
963
+ "checkout.goToPayment": "Ir para o pagamento - {{total}}",
964
+ "checkout.backToContact": "Voltar aos dados",
965
+ "checkout.backToCart": "Voltar ao carrinho",
966
+ // Summary
967
+ "summary.title": "Resumo do pedido",
968
+ "summary.subtotal": "Subtotal",
969
+ "summary.discount": "Desconto",
970
+ "summary.delivery": "Entrega",
971
+ "summary.pickup": "Retirada na loja",
972
+ "summary.noFee": "Sem taxa",
973
+ "summary.free": "Gr\xE1tis",
974
+ "summary.total": "Total",
975
+ "summary.protected": "Compra protegida e dados criptografados.",
976
+ "summary.shipping": "Frete",
977
+ // Discount
978
+ "discount.placeholder": "Cupom de desconto",
979
+ "discount.apply": "Aplicar",
980
+ "discount.freeShipping": "frete gr\xE1tis",
981
+ "discount.percentOff": "{{percent}}% de desconto",
982
+ "discount.applied": "{{code}} aplicado: {{effect}}.",
983
+ "discount.appliedToast": "Cupom aplicado!",
984
+ "discount.invalid": "Cupom inv\xE1lido.",
985
+ "discount.invalidToast": "Cupom inv\xE1lido",
986
+ "discount.checkCode": "Verifique o c\xF3digo e tente novamente.",
987
+ "discount.cannotValidate": "N\xE3o conseguimos validar esse cupom agora.",
988
+ "discount.cannotValidateToast": "N\xE3o conseguimos validar o cupom",
989
+ "discount.tryLater": "Tente de novo em alguns instantes.",
990
+ // Legal
991
+ "legal.privacy": "Privacidade",
992
+ "legal.terms": "Termos",
993
+ "legal.refunds": "Trocas e devolu\xE7\xF5es",
994
+ // Validation
995
+ "error.requiresAccount": "Esta loja pede uma conta para finalizar a compra. Entre ou crie a sua.",
996
+ "error.email": "Informe um e-mail v\xE1lido.",
997
+ "error.name": "Informe seu nome completo.",
998
+ "error.phone": "Informe um telefone de contato.",
999
+ "error.documentInvalid": "CPF ou CNPJ inv\xE1lido \u2014 confira os n\xFAmeros.",
1000
+ "error.documentMissing": "Informe o CPF ou CNPJ do comprador.",
1001
+ "error.taxIdInvalid": "NIF/NIE inv\xE1lido \u2014 confira o n\xFAmero.",
1002
+ "error.address": "Preencha ou selecione o endere\xE7o de entrega.",
1003
+ "error.number": "Falta o n\xFAmero do endere\xE7o.",
1004
+ "error.complement": "Informe o complemento (apto, bloco).",
1005
+ "error.state": "Informe a UF com duas letras (ex.: RJ).",
1006
+ "error.postalInvalid": "Confira o c\xF3digo postal (ex.: {{example}}).",
1007
+ "error.region": "Selecione a {{label}}.",
1008
+ "error.refusedZone": "Esta loja n\xE3o entrega nesse endere\xE7o. Tente outro.",
1009
+ "error.unserved": "Ainda n\xE3o entregamos nesse CEP. Tente outro endere\xE7o.",
1010
+ "error.sessionMismatch": "Sua sess\xE3o ficou presa a outro cadastro. Recarregue a p\xE1gina e tente de novo.",
1011
+ "error.outOfStock": "Um item do carrinho ficou sem estoque. Revise o carrinho e tente de novo.",
1012
+ "error.placeOrder": "N\xE3o foi poss\xEDvel concluir o pedido.",
1013
+ // Delivery estimator
1014
+ "delivery.title": "Calcular entrega",
1015
+ "delivery.calculate": "Calcular",
1016
+ "delivery.postalLabel": "CEP",
1017
+ "delivery.change": "Trocar CEP",
1018
+ "delivery.unserved": "Ainda n\xE3o entregamos nesse CEP.",
1019
+ "delivery.refused": "Esta loja n\xE3o entrega nesse endere\xE7o.",
1020
+ "delivery.review": "Entregamos nessa regi\xE3o, mas confirmamos com voc\xEA antes de sair.",
1021
+ "delivery.etaSoon": "hoje ou amanh\xE3",
1022
+ "delivery.etaRange": "{{min}} a {{max}} dias \xFAteis",
1023
+ "delivery.etaDays": "{{days}} dia(s) \xFAtil(eis)",
1024
+ "delivery.flatRate": "O frete \xE9 calculado no checkout.",
1025
+ "delivery.error.digits": "Digite os 8 d\xEDgitos do CEP.",
1026
+ "delivery.error.postal": "Confira o c\xF3digo postal (ex.: {{example}}).",
1027
+ "delivery.error.quote": "N\xE3o foi poss\xEDvel calcular o frete agora. Tente de novo.",
1028
+ "delivery.error.notFound": "CEP n\xE3o encontrado. Confira os n\xFAmeros.",
1029
+ // Cart
1030
+ "cart.title": "Carrinho",
1031
+ "cart.close": "Fechar carrinho",
1032
+ "cart.empty": "Seu carrinho est\xE1 vazio.",
1033
+ "cart.remove": "Remover {{name}}",
1034
+ "cart.checkout": "Finalizar compra",
1035
+ "cart.missingForFree": "Faltam {{amount}} para frete gr\xE1tis",
1036
+ "cart.wonFree": "Voc\xEA ganhou frete gr\xE1tis!",
1037
+ // Deliver to
1038
+ "country.deliverTo": "Enviar para",
1039
+ "country.change": "Trocar pa\xEDs",
1040
+ "country.label": "Pa\xEDs de entrega"
1041
+ };
1042
+ var en = {
1043
+ "checkout.backToStore": "Back to store",
1044
+ "checkout.secure": "Secure checkout",
1045
+ "checkout.help": "Help",
1046
+ "checkout.steps.label": "Checkout steps",
1047
+ "checkout.steps.1": "Details",
1048
+ "checkout.steps.2": "Delivery",
1049
+ "checkout.steps.3": "Payment",
1050
+ "checkout.steps.4": "Done",
1051
+ "checkout.contact.title": "Contact information",
1052
+ "checkout.contact.signedInAs": "Signed in as {{email}}",
1053
+ "checkout.contact.haveAccount": "Have an account? Sign in",
1054
+ "checkout.contact.email": "Email",
1055
+ "checkout.contact.name": "Full name",
1056
+ "checkout.contact.phone": "Phone",
1057
+ "checkout.contact.phoneOptional": "Phone (optional)",
1058
+ "checkout.contact.document": "Tax ID",
1059
+ "checkout.contact.documentOptional": "Tax ID (optional)",
1060
+ "checkout.contact.requiresAccount": "This store needs an account to complete the purchase.",
1061
+ "checkout.contact.signInOrCreate": "Sign in or create an account",
1062
+ "checkout.address.title": "Delivery address",
1063
+ "checkout.address.loadingSaved": "Loading your saved addresses",
1064
+ "checkout.address.selected": "Selected",
1065
+ "checkout.address.addNew": "+ Add a new address",
1066
+ "checkout.address.enter": "Enter the delivery address",
1067
+ "checkout.address.enterHint": "Use a different address for this order",
1068
+ "checkout.address.lookingUp": "Looking up this postal code",
1069
+ "checkout.address.notFound": "Postal code not found \u2014 fill in the address by hand.",
1070
+ "checkout.address.filled": "We filled in the address for you.",
1071
+ "checkout.address.regionFromPostal": "Province filled in from the postcode.",
1072
+ "checkout.address.optional": "{{label}} (optional)",
1073
+ "checkout.address.choose": "Select",
1074
+ "checkout.address.shipTo": "Ship to",
1075
+ "checkout.confirming.title": "Confirming your order",
1076
+ "checkout.confirming.label": "Creating your order",
1077
+ "checkout.confirming.keepOpen": "Don\u2019t close this page \u2014 we\u2019re registering your order with the store.",
1078
+ "checkout.payment.title": "Payment",
1079
+ "checkout.payment.label": "Payment method",
1080
+ "checkout.payment.cardOnline": "You pay on the provider\u2019s secure page and come back to the store",
1081
+ "checkout.payment.placeOrder": "Place order - {{total}}",
1082
+ "checkout.payment.pendingNote": "The order awaits payment until the store confirms it.",
1083
+ "checkout.payment.unavailableCountry": "This payment method isn\u2019t available for {{country}}.",
1084
+ "payment.pix.hint": "You get the key to pay after confirming the order",
1085
+ "payment.credit_card.label": "Credit card",
1086
+ "payment.credit_card.hint": "Card machine on delivery",
1087
+ "payment.debit_card.label": "Debit card",
1088
+ "payment.debit_card.hint": "Card machine on delivery",
1089
+ "payment.boleto.hint": "Sent by email after confirmation",
1090
+ "payment.cash.label": "Cash",
1091
+ "payment.cash.hint": "Pay on delivery",
1092
+ "payment.other.label": "Arrange with the store",
1093
+ "payment.other.hint": "The store will contact you to arrange payment",
1094
+ "checkout.done.title": "Payment confirmed!",
1095
+ "checkout.done.text": "Your order was created and the store has been notified.",
1096
+ "checkout.done.viewOrder": "View my order",
1097
+ "checkout.continueToDelivery": "Continue to delivery",
1098
+ "checkout.goToPayment": "Go to payment - {{total}}",
1099
+ "checkout.backToContact": "Back to details",
1100
+ "checkout.backToCart": "Back to cart",
1101
+ "summary.title": "Order summary",
1102
+ "summary.discount": "Discount",
1103
+ "summary.delivery": "Delivery",
1104
+ "summary.pickup": "Store pickup",
1105
+ "summary.noFee": "No fee",
1106
+ "summary.free": "Free",
1107
+ "summary.protected": "Protected purchase, encrypted data.",
1108
+ "summary.shipping": "Shipping",
1109
+ "discount.placeholder": "Discount code",
1110
+ "discount.apply": "Apply",
1111
+ "discount.freeShipping": "free shipping",
1112
+ "discount.percentOff": "{{percent}}% off",
1113
+ "discount.applied": "{{code}} applied: {{effect}}.",
1114
+ "discount.appliedToast": "Code applied!",
1115
+ "discount.invalid": "Invalid code.",
1116
+ "discount.invalidToast": "Invalid code",
1117
+ "discount.checkCode": "Check the code and try again.",
1118
+ "discount.cannotValidate": "We couldn\u2019t check this code right now.",
1119
+ "discount.cannotValidateToast": "We couldn\u2019t check the code",
1120
+ "discount.tryLater": "Try again in a moment.",
1121
+ "legal.privacy": "Privacy",
1122
+ "legal.terms": "Terms",
1123
+ "legal.refunds": "Returns",
1124
+ "error.requiresAccount": "This store needs an account to complete the purchase. Sign in or create one.",
1125
+ "error.email": "Enter a valid email.",
1126
+ "error.name": "Enter your full name.",
1127
+ "error.phone": "Enter a contact phone number.",
1128
+ "error.documentInvalid": "Invalid tax ID \u2014 check the numbers.",
1129
+ "error.documentMissing": "Enter the buyer\u2019s tax ID.",
1130
+ "error.taxIdInvalid": "Invalid NIF/NIE \u2014 check the number.",
1131
+ "error.address": "Fill in or select the delivery address.",
1132
+ "error.number": "The street number is missing.",
1133
+ "error.complement": "Enter the apartment or unit.",
1134
+ "error.state": "Enter the two-letter state code (e.g. RJ).",
1135
+ "error.postalInvalid": "Check the postal code (e.g. {{example}}).",
1136
+ "error.region": "Select the {{label}}.",
1137
+ "error.refusedZone": "This store doesn\u2019t deliver to this address. Try another.",
1138
+ "error.unserved": "We don\u2019t deliver to this postal code yet. Try another address.",
1139
+ "error.sessionMismatch": "Your session got attached to another account. Reload the page and try again.",
1140
+ "error.outOfStock": "An item in your cart is out of stock. Review the cart and try again.",
1141
+ "error.placeOrder": "We couldn\u2019t complete the order.",
1142
+ "delivery.title": "Estimate delivery",
1143
+ "delivery.calculate": "Estimate",
1144
+ "delivery.postalLabel": "Postal code",
1145
+ "delivery.change": "Change postal code",
1146
+ "delivery.unserved": "We don\u2019t deliver to this postal code yet.",
1147
+ "delivery.refused": "This store doesn\u2019t deliver to this address.",
1148
+ "delivery.review": "We deliver to this area, but we\u2019ll confirm with you before shipping.",
1149
+ "delivery.etaSoon": "today or tomorrow",
1150
+ "delivery.etaRange": "{{min}} to {{max}} business days",
1151
+ "delivery.etaDays": "{{days}} business day(s)",
1152
+ "delivery.flatRate": "Shipping is calculated at checkout.",
1153
+ "delivery.error.digits": "Enter all 8 digits of the CEP.",
1154
+ "delivery.error.postal": "Check the postal code (e.g. {{example}}).",
1155
+ "delivery.error.quote": "We couldn\u2019t calculate shipping right now. Try again.",
1156
+ "delivery.error.notFound": "Postal code not found. Check the numbers.",
1157
+ "cart.title": "Cart",
1158
+ "cart.close": "Close cart",
1159
+ "cart.empty": "Your cart is empty.",
1160
+ "cart.remove": "Remove {{name}}",
1161
+ "cart.checkout": "Checkout",
1162
+ "cart.missingForFree": "{{amount}} away from free shipping",
1163
+ "cart.wonFree": "You got free shipping!",
1164
+ "country.deliverTo": "Deliver to",
1165
+ "country.change": "Change country",
1166
+ "country.label": "Delivery country"
1167
+ };
1168
+ var es = {
1169
+ "checkout.backToStore": "Volver a la tienda",
1170
+ "checkout.secure": "Pago seguro",
1171
+ "checkout.help": "Ayuda",
1172
+ "checkout.steps.label": "Pasos del pago",
1173
+ "checkout.steps.1": "Datos",
1174
+ "checkout.steps.2": "Env\xEDo",
1175
+ "checkout.steps.3": "Pago",
1176
+ "checkout.steps.4": "Listo",
1177
+ "checkout.contact.title": "Datos de contacto",
1178
+ "checkout.contact.signedInAs": "Has iniciado sesi\xF3n como {{email}}",
1179
+ "checkout.contact.haveAccount": "\xBFYa tienes cuenta? Entrar",
1180
+ "checkout.contact.email": "Email",
1181
+ "checkout.contact.name": "Nombre completo",
1182
+ "checkout.contact.phone": "Tel\xE9fono",
1183
+ "checkout.contact.phoneOptional": "Tel\xE9fono (opcional)",
1184
+ "checkout.contact.document": "NIF/NIE",
1185
+ "checkout.contact.documentOptional": "NIF/NIE (opcional)",
1186
+ "checkout.contact.requiresAccount": "Esta tienda pide una cuenta para finalizar la compra.",
1187
+ "checkout.contact.signInOrCreate": "Entrar o crear cuenta",
1188
+ "checkout.address.title": "Direcci\xF3n de env\xEDo",
1189
+ "checkout.address.loadingSaved": "Buscando tus direcciones guardadas",
1190
+ "checkout.address.selected": "Seleccionada",
1191
+ "checkout.address.addNew": "+ A\xF1adir una direcci\xF3n nueva",
1192
+ "checkout.address.enter": "Indica la direcci\xF3n de env\xEDo",
1193
+ "checkout.address.enterHint": "Usar otra direcci\xF3n para este pedido",
1194
+ "checkout.address.lookingUp": "Buscando este c\xF3digo postal",
1195
+ "checkout.address.notFound": "C\xF3digo postal no encontrado: rellena la direcci\xF3n a mano.",
1196
+ "checkout.address.filled": "Hemos rellenado la direcci\xF3n por ti.",
1197
+ "checkout.address.regionFromPostal": "Provincia rellenada a partir del c\xF3digo postal.",
1198
+ "checkout.address.optional": "{{label}} (opcional)",
1199
+ "checkout.address.choose": "Selecciona",
1200
+ "checkout.address.shipTo": "Enviar a",
1201
+ "checkout.confirming.title": "Confirmando tu pedido",
1202
+ "checkout.confirming.label": "Creando tu pedido",
1203
+ "checkout.confirming.keepOpen": "No cierres esta p\xE1gina: estamos registrando tu pedido en la tienda.",
1204
+ "checkout.payment.title": "Pago",
1205
+ "checkout.payment.label": "Forma de pago",
1206
+ "checkout.payment.cardOnline": "Pagas en la p\xE1gina segura del proveedor y vuelves a la tienda",
1207
+ "checkout.payment.placeOrder": "Hacer pedido - {{total}}",
1208
+ "checkout.payment.pendingNote": "El pedido queda pendiente de pago hasta que la tienda lo confirme.",
1209
+ "checkout.payment.unavailableCountry": "Esta forma de pago no est\xE1 disponible para {{country}}.",
1210
+ "payment.pix.hint": "Recibes la clave para pagar al confirmar el pedido",
1211
+ "payment.credit_card.label": "Tarjeta de cr\xE9dito",
1212
+ "payment.credit_card.hint": "Dat\xE1fono en la entrega",
1213
+ "payment.debit_card.label": "Tarjeta de d\xE9bito",
1214
+ "payment.debit_card.hint": "Dat\xE1fono en la entrega",
1215
+ "payment.boleto.hint": "Enviado por email tras la confirmaci\xF3n",
1216
+ "payment.cash.label": "Efectivo",
1217
+ "payment.cash.hint": "Pago en la entrega",
1218
+ "payment.other.label": "Acordar con la tienda",
1219
+ "payment.other.hint": "La tienda te contactar\xE1 para acordar el pago",
1220
+ "checkout.done.title": "\xA1Pago confirmado!",
1221
+ "checkout.done.text": "Tu pedido se ha creado y la tienda ya ha sido avisada.",
1222
+ "checkout.done.viewOrder": "Ver mi pedido",
1223
+ "checkout.continueToDelivery": "Continuar al env\xEDo",
1224
+ "checkout.goToPayment": "Ir al pago - {{total}}",
1225
+ "checkout.backToContact": "Volver a los datos",
1226
+ "checkout.backToCart": "Volver al carrito",
1227
+ "summary.title": "Resumen del pedido",
1228
+ "summary.discount": "Descuento",
1229
+ "summary.delivery": "Env\xEDo",
1230
+ "summary.pickup": "Recogida en tienda",
1231
+ "summary.noFee": "Sin coste",
1232
+ "summary.free": "Gratis",
1233
+ "summary.protected": "Compra protegida y datos cifrados.",
1234
+ "summary.shipping": "Env\xEDo",
1235
+ "discount.placeholder": "C\xF3digo de descuento",
1236
+ "discount.apply": "Aplicar",
1237
+ "discount.freeShipping": "env\xEDo gratis",
1238
+ "discount.percentOff": "{{percent}}% de descuento",
1239
+ "discount.applied": "{{code}} aplicado: {{effect}}.",
1240
+ "discount.appliedToast": "\xA1C\xF3digo aplicado!",
1241
+ "discount.invalid": "C\xF3digo no v\xE1lido.",
1242
+ "discount.invalidToast": "C\xF3digo no v\xE1lido",
1243
+ "discount.checkCode": "Revisa el c\xF3digo e int\xE9ntalo de nuevo.",
1244
+ "discount.cannotValidate": "No hemos podido validar este c\xF3digo ahora.",
1245
+ "discount.cannotValidateToast": "No hemos podido validar el c\xF3digo",
1246
+ "discount.tryLater": "Int\xE9ntalo de nuevo en unos instantes.",
1247
+ "legal.privacy": "Privacidad",
1248
+ "legal.terms": "T\xE9rminos",
1249
+ "legal.refunds": "Devoluciones",
1250
+ "error.requiresAccount": "Esta tienda pide una cuenta para finalizar la compra. Entra o crea la tuya.",
1251
+ "error.email": "Indica un email v\xE1lido.",
1252
+ "error.name": "Indica tu nombre completo.",
1253
+ "error.phone": "Indica un tel\xE9fono de contacto.",
1254
+ "error.documentInvalid": "Documento no v\xE1lido: revisa los n\xFAmeros.",
1255
+ "error.documentMissing": "Indica el documento del comprador.",
1256
+ "error.taxIdInvalid": "NIF/NIE no v\xE1lido: revisa el n\xFAmero.",
1257
+ "error.address": "Rellena o selecciona la direcci\xF3n de env\xEDo.",
1258
+ "error.number": "Falta el n\xFAmero de la direcci\xF3n.",
1259
+ "error.complement": "Indica el piso o la puerta.",
1260
+ "error.state": "Indica el estado con dos letras (ej.: RJ).",
1261
+ "error.postalInvalid": "Revisa el c\xF3digo postal (ej.: {{example}}).",
1262
+ "error.region": "Selecciona la {{label}}.",
1263
+ "error.refusedZone": "Esta tienda no env\xEDa a esta direcci\xF3n. Prueba con otra.",
1264
+ "error.unserved": "Todav\xEDa no enviamos a este c\xF3digo postal. Prueba con otra direcci\xF3n.",
1265
+ "error.sessionMismatch": "Tu sesi\xF3n qued\xF3 vinculada a otra cuenta. Recarga la p\xE1gina e int\xE9ntalo de nuevo.",
1266
+ "error.outOfStock": "Un producto del carrito se ha agotado. Revisa el carrito e int\xE9ntalo de nuevo.",
1267
+ "error.placeOrder": "No se ha podido completar el pedido.",
1268
+ "delivery.title": "Calcular env\xEDo",
1269
+ "delivery.calculate": "Calcular",
1270
+ "delivery.postalLabel": "C\xF3digo postal",
1271
+ "delivery.change": "Cambiar c\xF3digo postal",
1272
+ "delivery.unserved": "Todav\xEDa no enviamos a este c\xF3digo postal.",
1273
+ "delivery.refused": "Esta tienda no env\xEDa a esta direcci\xF3n.",
1274
+ "delivery.review": "Enviamos a esta zona, pero lo confirmamos contigo antes de salir.",
1275
+ "delivery.etaSoon": "hoy o ma\xF1ana",
1276
+ "delivery.etaRange": "de {{min}} a {{max}} d\xEDas laborables",
1277
+ "delivery.etaDays": "{{days}} d\xEDa(s) laborable(s)",
1278
+ "delivery.flatRate": "El env\xEDo se calcula en el pago.",
1279
+ "delivery.error.digits": "Escribe los 8 d\xEDgitos del CEP.",
1280
+ "delivery.error.postal": "Revisa el c\xF3digo postal (ej.: {{example}}).",
1281
+ "delivery.error.quote": "No hemos podido calcular el env\xEDo ahora. Int\xE9ntalo de nuevo.",
1282
+ "delivery.error.notFound": "C\xF3digo postal no encontrado. Revisa los n\xFAmeros.",
1283
+ "cart.title": "Carrito",
1284
+ "cart.close": "Cerrar carrito",
1285
+ "cart.empty": "Tu carrito est\xE1 vac\xEDo.",
1286
+ "cart.remove": "Quitar {{name}}",
1287
+ "cart.checkout": "Finalizar compra",
1288
+ "cart.missingForFree": "Te faltan {{amount}} para el env\xEDo gratis",
1289
+ "cart.wonFree": "\xA1Tienes env\xEDo gratis!",
1290
+ "country.deliverTo": "Enviar a",
1291
+ "country.change": "Cambiar pa\xEDs",
1292
+ "country.label": "Pa\xEDs de env\xEDo"
1293
+ };
1294
+ var MESSAGES = { "pt-BR": ptBR, en, es };
1295
+ function normalizeLanguage(value) {
1296
+ const base = (value || "").toLowerCase().split(/[-_]/)[0];
1297
+ if (base === "pt") return "pt-BR";
1298
+ if (base === "en") return "en";
1299
+ if (base === "es") return "es";
1300
+ return null;
1301
+ }
1302
+ function translate(language, key, vars, overrides) {
1303
+ let text = overrides?.[language]?.[key] ?? MESSAGES[language]?.[key] ?? overrides?.["pt-BR"]?.[key] ?? ptBR[key];
1304
+ if (vars) for (const [name, value] of Object.entries(vars)) text = text.split(`{{${name}}}`).join(String(value));
1305
+ return text;
1306
+ }
1307
+ function resolveCountries(config) {
1308
+ const countries = [...new Set((config.countries ?? []).map((c) => c.trim().toUpperCase()).filter(Boolean))];
1309
+ if (countries.length === 0) countries.push("BR");
1310
+ const wanted = config.defaultCountry?.trim().toUpperCase();
1311
+ return { countries, defaultCountry: wanted && countries.includes(wanted) ? wanted : countries[0] };
1312
+ }
811
1313
  function resolveConfig(config) {
812
1314
  const homePage = config.pages?.home ?? (config.home ? { blocks: config.home.sections } : void 0);
813
1315
  const catalogPath = homePage ? "/catalog" : "/";
@@ -818,6 +1320,8 @@ function resolveConfig(config) {
818
1320
  pages: { ...config.pages, ...homePage ? { home: homePage } : {} },
819
1321
  currency: config.currency ?? "BRL",
820
1322
  locale: config.locale ?? "pt-BR",
1323
+ language: normalizeLanguage(config.language) ?? "pt-BR",
1324
+ ...resolveCountries(config),
821
1325
  shipping: { flatRate: config.shipping?.flatRate ?? 0, freeAbove: config.shipping?.freeAbove },
822
1326
  payments: {
823
1327
  mode: config.payments?.mode ?? "mock",
@@ -1065,7 +1569,7 @@ function Link({ to, children, onClick, target, ...rest }) {
1065
1569
  event.preventDefault();
1066
1570
  adapter.navigate(to);
1067
1571
  };
1068
- return React37.createElement(
1572
+ return React38.createElement(
1069
1573
  "a",
1070
1574
  { href: adapter.href(to), onClick: handleClick, target, ...rest },
1071
1575
  children
@@ -1305,9 +1809,9 @@ function SmoothImage({
1305
1809
  const easing = resolved.easing ?? "cubic-bezier(0.22, 1, 0.36, 1)";
1306
1810
  const blur = resolved.blur ?? true;
1307
1811
  const transform = resolved.transform ?? "none";
1308
- const ref = React37.useRef(null);
1309
- const [loaded, setLoaded] = React37.useState(() => mode === "none" || !clientMounted);
1310
- const delivered = React37.useMemo(() => {
1812
+ const ref = React38.useRef(null);
1813
+ const [loaded, setLoaded] = React38.useState(() => mode === "none" || !clientMounted);
1814
+ const delivered = React38.useMemo(() => {
1311
1815
  if (transform !== "supabase" || !src || srcSet || !isStorageImageUrl(src)) return { src, srcSet, sizes };
1312
1816
  if (variant?.width) {
1313
1817
  const w = variant.width;
@@ -1325,10 +1829,10 @@ function SmoothImage({
1325
1829
  sizes: variant?.sizes ?? sizes ?? "100vw"
1326
1830
  };
1327
1831
  }, [transform, src, srcSet, sizes, variant?.width, variant?.sizes, variant?.widths, variant?.quality]);
1328
- React37.useEffect(() => {
1832
+ React38.useEffect(() => {
1329
1833
  clientMounted = true;
1330
1834
  }, []);
1331
- React37.useEffect(() => {
1835
+ React38.useEffect(() => {
1332
1836
  if (mode === "none") {
1333
1837
  setLoaded(true);
1334
1838
  return;
@@ -1935,6 +2439,14 @@ function useStorefrontActions() {
1935
2439
  createProductEnquiry
1936
2440
  };
1937
2441
  }
2442
+ function useMarketProduct(product) {
2443
+ const active2 = useMarketStore((s2) => s2.active);
2444
+ const prices = useMarketStore((s2) => s2.prices);
2445
+ return useMemo(
2446
+ () => product ? withMarketPrice(product, { active: active2, prices }) : product,
2447
+ [product, active2, prices]
2448
+ );
2449
+ }
1938
2450
  function Price({ value, compareAt, testId, compareTestId, className }) {
1939
2451
  const { currency, locale } = useStorefrontConfig();
1940
2452
  return /* @__PURE__ */ jsxs("span", { className: `inline-flex items-baseline gap-2 ${className ?? ""}`, children: [
@@ -2596,8 +3108,8 @@ var BADGE_TONE_CLASSES = {
2596
3108
  warning: "bg-amber-500 text-white"
2597
3109
  };
2598
3110
  function useExtensionBadges(product) {
2599
- const [badges, setBadges] = React37.useState([]);
2600
- React37.useEffect(() => {
3111
+ const [badges, setBadges] = React38.useState([]);
3112
+ React38.useEffect(() => {
2601
3113
  let cancelled = false;
2602
3114
  getProductCardBadges(product).then((next) => {
2603
3115
  if (!cancelled && next.length > 0) setBadges(next);
@@ -2617,7 +3129,8 @@ function pickProductCardImage(images, order = "primary") {
2617
3129
  }
2618
3130
  return images.find((i) => i.isPrimary) ?? images[0];
2619
3131
  }
2620
- function ProductCard({ product, config: providedConfig, actions: providedActions, imageOrder = "primary" }) {
3132
+ function ProductCard({ product: catalogProduct, config: providedConfig, actions: providedActions, imageOrder = "primary" }) {
3133
+ const product = useMarketProduct(catalogProduct);
2621
3134
  const runtimeConfig = useStorefrontConfig();
2622
3135
  const runtimeActions = useStorefrontActions();
2623
3136
  const config = providedConfig ?? runtimeConfig;
@@ -3793,7 +4306,7 @@ function scalarToString(value) {
3793
4306
  }
3794
4307
  function ProductSpecs({ product }) {
3795
4308
  const config = useStorefrontConfig();
3796
- const extraExcluded = React37.useMemo(
4309
+ const extraExcluded = React38.useMemo(
3797
4310
  () => new Set(config.productSpecs?.exclude ?? []),
3798
4311
  [config.productSpecs?.exclude]
3799
4312
  );
@@ -4213,6 +4726,65 @@ function GalleryArrow({ side, onClick, canHover }) {
4213
4726
  }
4214
4727
  );
4215
4728
  }
4729
+ var BUYER_COUNTRY_COOKIE = "fayz_country";
4730
+ var useBuyerStore = create()(
4731
+ persist(
4732
+ (set) => ({
4733
+ picked: null,
4734
+ pick(country) {
4735
+ const iso2 = country.trim().toUpperCase();
4736
+ set({ picked: iso2 });
4737
+ try {
4738
+ document.cookie = `${BUYER_COUNTRY_COOKIE}=${iso2}; path=/; max-age=31536000; samesite=lax`;
4739
+ } catch {
4740
+ }
4741
+ }
4742
+ }),
4743
+ { name: "fayz.storefront.buyer.v1" }
4744
+ )
4745
+ );
4746
+ function navigatorRegion() {
4747
+ try {
4748
+ for (const tag of navigator.languages ?? [navigator.language]) {
4749
+ const region = tag?.split(/[-_]/)[1];
4750
+ if (region && /^[A-Za-z]{2}$/.test(region)) return region.toUpperCase();
4751
+ }
4752
+ } catch {
4753
+ }
4754
+ return void 0;
4755
+ }
4756
+ function useBuyerCountry() {
4757
+ const config = useStorefrontConfig();
4758
+ const allowed = config.countries;
4759
+ const picked = useBuyerStore((s2) => s2.picked);
4760
+ const pick = useBuyerStore((s2) => s2.pick);
4761
+ const [mounted, setMounted] = useState(false);
4762
+ useEffect(() => setMounted(true), []);
4763
+ const ok = (c) => !!c && allowed.includes(c);
4764
+ let country = ok(config.countryHint) ? config.countryHint : config.defaultCountry;
4765
+ if (allowed.length > 1 && mounted) {
4766
+ const region = navigatorRegion();
4767
+ if (ok(picked)) country = picked;
4768
+ else if (!ok(config.countryHint) && ok(region)) country = region;
4769
+ }
4770
+ return {
4771
+ country,
4772
+ allowed,
4773
+ schema: getCountrySchema(country),
4774
+ setCountry(next) {
4775
+ const iso2 = next.toUpperCase();
4776
+ if (!allowed.includes(iso2) || iso2 === country) return;
4777
+ pick(iso2);
4778
+ useDeliveryStore.getState().clear();
4779
+ }
4780
+ };
4781
+ }
4782
+ function useT() {
4783
+ const config = useStorefrontConfig();
4784
+ const language = config.language;
4785
+ const overrides = config.messages;
4786
+ return useCallback((key, vars) => translate(language, key, vars, overrides), [language, overrides]);
4787
+ }
4216
4788
  function RelatedProducts({ product }) {
4217
4789
  const config = useStorefrontConfig();
4218
4790
  const actions = useStorefrontActions();
@@ -4241,21 +4813,24 @@ function DeliveryEstimator({ compact: compact2 = false }) {
4241
4813
  const config = useStorefrontConfig();
4242
4814
  const cart = useCartStore();
4243
4815
  const delivery = useDeliveryStore();
4244
- const [draft, setDraft] = useState(() => formatPostalCode(delivery.postalCode));
4816
+ const t = useT();
4817
+ const { country, schema } = useBuyerCountry();
4818
+ const isBrazil = country === "BR";
4819
+ const [draft, setDraft] = useState(() => delivery.country === country ? formatPostalCode(delivery.postalCode, country) : "");
4245
4820
  const subtotal = selectSubtotal(cart);
4246
4821
  const money = (value) => formatMoney(value, config.currency, config.locale);
4247
4822
  const loading = delivery.status === "loading";
4248
4823
  const resolved = delivery.status === "served";
4249
4824
  async function submit(event) {
4250
4825
  event.preventDefault();
4251
- await delivery.resolve(draft, subtotal);
4826
+ await delivery.resolve(draft, subtotal, country);
4252
4827
  }
4253
4828
  function eta(option) {
4254
4829
  const { etaMinDays: min, etaMaxDays: max } = option;
4255
4830
  if (min == null && max == null) return null;
4256
- if (min === 0 && (max === 0 || max === 1)) return "hoje ou amanh\xE3";
4257
- if (min != null && max != null && min !== max) return `${min} a ${max} dias \xFAteis`;
4258
- return `${max ?? min} dia(s) \xFAtil(eis)`;
4831
+ if (min === 0 && (max === 0 || max === 1)) return t("delivery.etaSoon");
4832
+ if (min != null && max != null && min !== max) return t("delivery.etaRange", { min, max });
4833
+ return t("delivery.etaDays", { days: String(max ?? min) });
4259
4834
  }
4260
4835
  return /* @__PURE__ */ jsxs(
4261
4836
  "section",
@@ -4266,19 +4841,19 @@ function DeliveryEstimator({ compact: compact2 = false }) {
4266
4841
  !resolved && /* @__PURE__ */ jsxs(Fragment, { children: [
4267
4842
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm font-semibold", children: [
4268
4843
  /* @__PURE__ */ jsx(Truck, { className: "h-4 w-4 text-primary" }),
4269
- "Calcular entrega"
4844
+ t("delivery.title")
4270
4845
  ] }),
4271
4846
  /* @__PURE__ */ jsxs("form", { onSubmit: submit, className: "mt-3 flex gap-2", children: [
4272
4847
  /* @__PURE__ */ jsx(
4273
4848
  "input",
4274
4849
  {
4275
4850
  "data-testid": TID.deliveryCepInput,
4276
- "aria-label": "CEP",
4277
- inputMode: "numeric",
4851
+ "aria-label": isBrazil ? "CEP" : t("delivery.postalLabel"),
4852
+ inputMode: schema.postal.inputMode,
4278
4853
  autoComplete: "postal-code",
4279
- placeholder: "00000-000",
4854
+ placeholder: isBrazil ? "00000-000" : schema.postal.example,
4280
4855
  value: draft,
4281
- onChange: (event) => setDraft(formatPostalCode(event.target.value)),
4856
+ onChange: (event) => setDraft(formatPostalCode(event.target.value, country)),
4282
4857
  className: "min-w-0 flex-1 rounded-lg border bg-background px-3 py-2 text-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/10"
4283
4858
  }
4284
4859
  ),
@@ -4289,22 +4864,21 @@ function DeliveryEstimator({ compact: compact2 = false }) {
4289
4864
  "data-testid": TID.deliveryCepSubmit,
4290
4865
  disabled: loading,
4291
4866
  className: "shrink-0 rounded-lg bg-primary px-4 py-2 text-sm font-semibold text-primary-foreground transition hover:opacity-90 disabled:opacity-50",
4292
- children: loading ? "..." : "Calcular"
4867
+ children: loading ? "..." : t("delivery.calculate")
4293
4868
  }
4294
4869
  )
4295
4870
  ] })
4296
4871
  ] }),
4297
- delivery.error && /* @__PURE__ */ jsx("p", { "data-testid": TID.deliveryError, className: "mt-3 text-sm text-destructive", children: delivery.error }),
4872
+ delivery.error && /* @__PURE__ */ jsx("p", { "data-testid": TID.deliveryError, className: "mt-3 text-sm text-destructive", children: delivery.errorKey ? t(delivery.errorKey, delivery.errorVars ?? void 0) : delivery.error }),
4298
4873
  delivery.address && /* @__PURE__ */ jsxs("p", { "data-testid": TID.deliveryAddress, className: "mt-3 flex items-start gap-1.5 text-xs text-muted-foreground", children: [
4299
4874
  /* @__PURE__ */ jsx(MapPin, { className: "mt-0.5 h-3.5 w-3.5 shrink-0" }),
4300
4875
  /* @__PURE__ */ jsxs("span", { children: [
4301
4876
  [delivery.address.street, delivery.address.district].filter(Boolean).join(", "),
4302
4877
  delivery.address.street || delivery.address.district ? " \u2014 " : "",
4303
- delivery.address.city,
4304
- "/",
4305
- delivery.address.state
4878
+ [delivery.address.city, delivery.address.state].filter(Boolean).join("/")
4306
4879
  ] })
4307
4880
  ] }),
4881
+ !isBrazil && delivery.country === country && delivery.postalCode && delivery.status === "idle" && /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: t("delivery.flatRate") }),
4308
4882
  delivery.status === "served" && /* @__PURE__ */ jsx("ul", { className: "mt-3 space-y-2", children: delivery.options.map((option) => {
4309
4883
  const selected = delivery.selectedZoneId === option.zoneId;
4310
4884
  const label = eta(option);
@@ -4324,13 +4898,13 @@ function DeliveryEstimator({ compact: compact2 = false }) {
4324
4898
  /* @__PURE__ */ jsx("span", { className: "block truncate font-medium", children: option.carrier ? `${option.carrier} \xB7 ${option.name}` : option.name }),
4325
4899
  label && /* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: label })
4326
4900
  ] }),
4327
- /* @__PURE__ */ jsx("span", { className: "shrink-0 font-semibold", children: rate === 0 ? "Gr\xE1tis" : money(rate) })
4901
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 font-semibold", children: rate === 0 ? t("summary.free") : money(rate) })
4328
4902
  ]
4329
4903
  }
4330
4904
  ) }, option.zoneId);
4331
4905
  }) }),
4332
- delivery.status === "unserved" && /* @__PURE__ */ jsx("p", { "data-testid": TID.deliveryUnserved, className: "mt-3 text-sm text-destructive", children: delivery.refusedZone ? "Esta loja n\xE3o entrega nesse endere\xE7o." : "Ainda n\xE3o entregamos nesse CEP." }),
4333
- delivery.reviewZone && delivery.status === "served" && /* @__PURE__ */ jsx("p", { className: "mt-3 text-sm text-amber-600 dark:text-amber-500", children: "Entregamos nessa regi\xE3o, mas confirmamos com voc\xEA antes de sair." }),
4906
+ delivery.status === "unserved" && /* @__PURE__ */ jsx("p", { "data-testid": TID.deliveryUnserved, className: "mt-3 text-sm text-destructive", children: delivery.refusedZone ? t("delivery.refused") : t("delivery.unserved") }),
4907
+ delivery.reviewZone && delivery.status === "served" && /* @__PURE__ */ jsx("p", { className: "mt-3 text-sm text-amber-600 dark:text-amber-500", children: t("delivery.review") }),
4334
4908
  delivery.postalCode && /* @__PURE__ */ jsx(
4335
4909
  "button",
4336
4910
  {
@@ -4341,7 +4915,7 @@ function DeliveryEstimator({ compact: compact2 = false }) {
4341
4915
  setDraft("");
4342
4916
  },
4343
4917
  className: "mt-3 py-1 text-xs text-muted-foreground underline-offset-2 hover:underline",
4344
- children: "Trocar CEP"
4918
+ children: t("delivery.change")
4345
4919
  }
4346
4920
  )
4347
4921
  ]
@@ -4351,7 +4925,8 @@ function DeliveryEstimator({ compact: compact2 = false }) {
4351
4925
  function ProductDetailPage({ slug }) {
4352
4926
  const config = useStorefrontConfig();
4353
4927
  const actions = useStorefrontActions();
4354
- const { product, loading } = useProduct(slug);
4928
+ const { product: catalogProduct, loading } = useProduct(slug);
4929
+ const product = useMarketProduct(catalogProduct);
4355
4930
  const addItem = useCartStore((s2) => s2.addItem);
4356
4931
  const [qty, setQty] = useState(1);
4357
4932
  const [selectedOptions, setSelectedOptions] = useState({});
@@ -4590,7 +5165,7 @@ function buildEnquiryFromForm(fields, values, subject, sourceUrl) {
4590
5165
  const phoneField = fields.find((f2) => f2.type === "phone");
4591
5166
  const nameField = fields.find((f2) => f2.id === "name") ?? fields.find((f2) => (f2.type ?? "text") === "text" && f2 !== emailField && f2 !== phoneField);
4592
5167
  const identity = /* @__PURE__ */ new Set([emailField?.id, phoneField?.id, nameField?.id]);
4593
- const lines = fields.filter((f2) => !identity.has(f2.id)).map((f2) => ({ field: f2, value: (values[f2.id] ?? "").trim() })).filter((entry) => entry.value).map(({ field: field2, value }) => field2.type === "textarea" ? value : `${field2.label}: ${value}`);
5168
+ const lines = fields.filter((f2) => !identity.has(f2.id)).map((f2) => ({ field: f2, value: (values[f2.id] ?? "").trim() })).filter((entry) => entry.value).map(({ field, value }) => field.type === "textarea" ? value : `${field.label}: ${value}`);
4594
5169
  return {
4595
5170
  productName: subject,
4596
5171
  customerName: nameField && values[nameField.id]?.trim() || "Visitante",
@@ -4604,31 +5179,31 @@ function buildEnquiryFromForm(fields, values, subject, sourceUrl) {
4604
5179
  }
4605
5180
  var INPUT_CLASS = "w-full border bg-background px-3 py-2 text-sm outline-none focus:border-primary";
4606
5181
  function Field({
4607
- field: field2,
5182
+ field,
4608
5183
  value,
4609
5184
  onChange
4610
5185
  }) {
4611
5186
  const common = {
4612
- "data-testid": TID.formBlockField(field2.id),
4613
- required: field2.required,
5187
+ "data-testid": TID.formBlockField(field.id),
5188
+ required: field.required,
4614
5189
  value,
4615
- placeholder: field2.placeholder,
5190
+ placeholder: field.placeholder,
4616
5191
  className: INPUT_CLASS,
4617
5192
  style: { borderRadius: "var(--sf-radius-input)" }
4618
5193
  };
4619
- return /* @__PURE__ */ jsxs("label", { className: `space-y-1.5 text-sm font-medium ${field2.type === "textarea" ? "block" : ""}`, children: [
5194
+ return /* @__PURE__ */ jsxs("label", { className: `space-y-1.5 text-sm font-medium ${field.type === "textarea" ? "block" : ""}`, children: [
4620
5195
  /* @__PURE__ */ jsxs("span", { children: [
4621
- field2.label,
4622
- field2.required ? "" : " (opcional)"
5196
+ field.label,
5197
+ field.required ? "" : " (opcional)"
4623
5198
  ] }),
4624
- field2.type === "textarea" ? /* @__PURE__ */ jsx("textarea", { ...common, rows: 5, onChange: (e) => onChange(e.target.value), className: `${INPUT_CLASS} resize-none` }) : field2.type === "select" ? /* @__PURE__ */ jsxs("select", { ...common, onChange: (e) => onChange(e.target.value), children: [
5199
+ field.type === "textarea" ? /* @__PURE__ */ jsx("textarea", { ...common, rows: 5, onChange: (e) => onChange(e.target.value), className: `${INPUT_CLASS} resize-none` }) : field.type === "select" ? /* @__PURE__ */ jsxs("select", { ...common, onChange: (e) => onChange(e.target.value), children: [
4625
5200
  /* @__PURE__ */ jsx("option", { value: "", children: "\u2014" }),
4626
- (field2.options ?? []).map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
5201
+ (field.options ?? []).map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
4627
5202
  ] }) : /* @__PURE__ */ jsx(
4628
5203
  "input",
4629
5204
  {
4630
5205
  ...common,
4631
- type: field2.type === "email" ? "email" : field2.type === "phone" ? "tel" : "text",
5206
+ type: field.type === "email" ? "email" : field.type === "phone" ? "tel" : "text",
4632
5207
  onChange: (e) => onChange(e.target.value)
4633
5208
  }
4634
5209
  )
@@ -4675,14 +5250,14 @@ function FormBlock({
4675
5250
  subtitle && /* @__PURE__ */ jsx("p", { className: "mt-2 text-muted-foreground", children: subtitle })
4676
5251
  ] }),
4677
5252
  status === "success" ? /* @__PURE__ */ jsx("p", { "data-testid": TID.formBlockSuccess, className: "text-center font-medium text-emerald-600", children: successMessage }) : /* @__PURE__ */ jsxs("form", { onSubmit: submit, className: "space-y-4", children: [
4678
- fields.map((field2) => /* @__PURE__ */ jsx(
5253
+ fields.map((field) => /* @__PURE__ */ jsx(
4679
5254
  Field,
4680
5255
  {
4681
- field: field2,
4682
- value: values[field2.id] ?? "",
4683
- onChange: (value) => setValues((prev) => ({ ...prev, [field2.id]: value }))
5256
+ field,
5257
+ value: values[field.id] ?? "",
5258
+ onChange: (value) => setValues((prev) => ({ ...prev, [field.id]: value }))
4684
5259
  },
4685
- field2.id
5260
+ field.id
4686
5261
  )),
4687
5262
  /* @__PURE__ */ jsx(
4688
5263
  "button",
@@ -4776,9 +5351,9 @@ var formBlockMeta = {
4776
5351
  // A form is a destination, not merchandising — editorial pages and the home.
4777
5352
  enabledOn: ["home", "catalog", "collection", "content"]
4778
5353
  };
4779
- function fieldValue(field2, value) {
5354
+ function fieldValue(field, value) {
4780
5355
  if (value === null || value === void 0 || value === "") return null;
4781
- switch (field2.type) {
5356
+ switch (field.type) {
4782
5357
  case "image":
4783
5358
  return /* @__PURE__ */ jsx(
4784
5359
  "img",
@@ -4817,12 +5392,12 @@ function EntityCard({ declaration, record, fields }) {
4817
5392
  children: [
4818
5393
  typeof title === "string" && title && /* @__PURE__ */ jsx("h3", { className: "sf-heading mb-2 text-lg font-semibold", children: title }),
4819
5394
  /* @__PURE__ */ jsx("dl", { className: "space-y-1.5", children: detailFields.map((name) => {
4820
- const field2 = declaration.fields[name];
4821
- if (!field2) return null;
4822
- const rendered = fieldValue(field2, record.data[name]);
5395
+ const field = declaration.fields[name];
5396
+ if (!field) return null;
5397
+ const rendered = fieldValue(field, record.data[name]);
4823
5398
  if (rendered === null) return null;
4824
5399
  return /* @__PURE__ */ jsxs("div", { children: [
4825
- /* @__PURE__ */ jsx("dt", { className: "text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: field2.label ?? name }),
5400
+ /* @__PURE__ */ jsx("dt", { className: "text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: field.label ?? name }),
4826
5401
  /* @__PURE__ */ jsx("dd", { className: "text-sm text-foreground/90", children: rendered })
4827
5402
  ] }, name);
4828
5403
  }) })
@@ -5445,7 +6020,7 @@ function CollectionHero({
5445
6020
  {
5446
6021
  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"}`,
5447
6022
  children: /* @__PURE__ */ jsxs(Reveal, { className: centered ? "max-w-3xl" : "max-w-2xl", children: [
5448
- 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(React37.Fragment, { children: [
6023
+ 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(React38.Fragment, { children: [
5449
6024
  i > 0 && /* @__PURE__ */ jsx("span", { className: "text-2xl font-light opacity-60", "aria-hidden": true, children: "\xD7" }),
5450
6025
  /* @__PURE__ */ jsx("img", { src: logo.src, alt: logo.alt, className: "h-10 w-auto object-contain sm:h-14" })
5451
6026
  ] }, logo.src)) }),
@@ -5569,7 +6144,7 @@ function ProductSpotlight({
5569
6144
  loader: "products.bySlug",
5570
6145
  params: { slug: productSlug }
5571
6146
  });
5572
- const product = productSlug ? data ?? null : null;
6147
+ const product = useMarketProduct(productSlug ? data ?? null : null);
5573
6148
  const target = product ? `/product/${product.slug}` : href;
5574
6149
  const art = image ?? product?.images?.[0]?.url ?? bannerPlaceholder(title, hue, hue + 45, 1200, 1200);
5575
6150
  const label = cta ?? (productSlug ? "Comprar" : void 0);
@@ -6198,12 +6773,21 @@ function applyStoreSettings(config, settings) {
6198
6773
  }
6199
6774
  return next;
6200
6775
  }
6776
+ function applyBuyer(config, buyer) {
6777
+ if (!buyer) return config;
6778
+ const language = normalizeLanguage(buyer.language) ?? config.language;
6779
+ const hint = buyer.country?.trim().toUpperCase();
6780
+ const countryHint = hint && config.countries.includes(hint) ? hint : config.countryHint;
6781
+ if (language === config.language && countryHint === config.countryHint) return config;
6782
+ return { ...config, language, countryHint };
6783
+ }
6201
6784
  function StorefrontConfigHost({
6202
6785
  config,
6786
+ buyer,
6203
6787
  children
6204
6788
  }) {
6205
- const [policy, setPolicy] = React37.useState(null);
6206
- React37.useEffect(() => {
6789
+ const [policy, setPolicy] = React38.useState(null);
6790
+ React38.useEffect(() => {
6207
6791
  let cancelled = false;
6208
6792
  let provider;
6209
6793
  try {
@@ -6218,12 +6802,56 @@ function StorefrontConfigHost({
6218
6802
  setShopCarrierQuotesResolver(() => settings?.carrierQuotes);
6219
6803
  }).catch(() => {
6220
6804
  });
6805
+ if (typeof provider.listMarkets === "function") {
6806
+ void provider.listMarkets().then((markets) => {
6807
+ if (!cancelled) useMarketStore.getState().setMarkets(markets);
6808
+ }).catch(() => {
6809
+ });
6810
+ }
6221
6811
  return () => {
6222
6812
  cancelled = true;
6223
6813
  };
6224
6814
  }, [config]);
6225
- const resolved = React37.useMemo(() => applyStoreSettings(config, policy), [config, policy]);
6226
- return /* @__PURE__ */ jsx(StorefrontConfigProvider, { value: resolved, children });
6815
+ const resolved = React38.useMemo(
6816
+ () => applyBuyer(applyStoreSettings(config, policy), buyer),
6817
+ [config, policy, buyer?.language, buyer?.country]
6818
+ );
6819
+ return /* @__PURE__ */ jsx(StorefrontConfigProvider, { value: resolved, children: /* @__PURE__ */ jsx(MarketScope, { children }) });
6820
+ }
6821
+ function MarketScope({ children }) {
6822
+ const base = useStorefrontConfig();
6823
+ const { country } = useBuyerCountry();
6824
+ const markets = useMarketStore((s2) => s2.markets);
6825
+ const market = markets.length ? marketForCountry(markets, country) : null;
6826
+ const prices = useMarketStore((s2) => market ? s2.prices[market.code] : void 0);
6827
+ React38.useEffect(() => {
6828
+ useMarketStore.getState().setActive(market);
6829
+ if (!market || market.isDefault || prices) return;
6830
+ let provider;
6831
+ try {
6832
+ provider = base.provider ?? getShopProvider();
6833
+ } catch {
6834
+ return;
6835
+ }
6836
+ void provider.getMarketPrices?.(market.code).then((list) => useMarketStore.getState().setPrices(market.code, list)).catch(() => {
6837
+ });
6838
+ }, [market?.code, prices]);
6839
+ React38.useEffect(() => {
6840
+ if (!market || !market.isDefault && !prices) return;
6841
+ useCartStore.getState().repriceForMarket();
6842
+ }, [market?.code, prices]);
6843
+ const value = React38.useMemo(() => {
6844
+ if (!market) return base;
6845
+ return {
6846
+ ...base,
6847
+ market,
6848
+ currency: market.currency,
6849
+ locale: market.locale || base.locale,
6850
+ shipping: market.isDefault ? base.shipping : { flatRate: market.shippingFlatRate, freeAbove: market.shippingFreeAbove ?? void 0 },
6851
+ policy: market.paymentProvider ? { ...base.policy, paymentProvider: market.paymentProvider } : base.policy
6852
+ };
6853
+ }, [base, market]);
6854
+ return /* @__PURE__ */ jsx(StorefrontConfigProvider, { value, children });
6227
6855
  }
6228
6856
  var RADIUS_MAP = {
6229
6857
  none: { button: "0px", card: "0px", input: "0px" },
@@ -6276,8 +6904,8 @@ function themeToCss(theme, options = {}) {
6276
6904
  if (theme.font.display) lines.push(`--sf-font-display: '${theme.font.display}', ${fallback};`);
6277
6905
  if (theme.font.serif) lines.push(`--sf-font-serif: '${theme.font.serif}', serif;`);
6278
6906
  }
6279
- for (const [field2, prefix] of Object.entries(THEME_SCALE_VAR_PREFIX)) {
6280
- for (const [key, value] of Object.entries(theme[field2] ?? {})) {
6907
+ for (const [field, prefix] of Object.entries(THEME_SCALE_VAR_PREFIX)) {
6908
+ for (const [key, value] of Object.entries(theme[field] ?? {})) {
6281
6909
  lines.push(`${prefix}-${key}: ${value};`);
6282
6910
  }
6283
6911
  }
@@ -6342,7 +6970,7 @@ function StorefrontThemeStyle({
6342
6970
  document.getElementById(linkId)?.remove();
6343
6971
  };
6344
6972
  }, [fontsHref, linkId, selector]);
6345
- return React37.createElement(
6973
+ return React38.createElement(
6346
6974
  "style",
6347
6975
  { "data-sf-theme": theme.name },
6348
6976
  themeToCss(theme, { selector })
@@ -6441,7 +7069,7 @@ function SearchOverlay({ onClose }) {
6441
7069
  "\u201D."
6442
7070
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
6443
7071
  /* @__PURE__ */ jsx("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4", children: suggestions.map(
6444
- (product) => searchConfig.renderSuggestion ? /* @__PURE__ */ jsx(React37.Fragment, { children: searchConfig.renderSuggestion(product) }, product.id) : /* @__PURE__ */ jsx(SuggestionCard, { product, onNavigate: onClose }, product.id)
7072
+ (product) => searchConfig.renderSuggestion ? /* @__PURE__ */ jsx(React38.Fragment, { children: searchConfig.renderSuggestion(product) }, product.id) : /* @__PURE__ */ jsx(SuggestionCard, { product, onNavigate: onClose }, product.id)
6445
7073
  ) }),
6446
7074
  /* @__PURE__ */ jsx(
6447
7075
  "button",
@@ -6459,7 +7087,8 @@ function SearchOverlay({ onClose }) {
6459
7087
  }
6460
7088
  );
6461
7089
  }
6462
- function SuggestionCard({ product, onNavigate }) {
7090
+ function SuggestionCard({ product: catalogProduct, onNavigate }) {
7091
+ const product = useMarketProduct(catalogProduct);
6463
7092
  const image = product.images.find((i) => i.isPrimary) ?? product.images[0];
6464
7093
  return /* @__PURE__ */ jsxs(
6465
7094
  "button",
@@ -6647,11 +7276,11 @@ function HeaderActions({ onMenuClick }) {
6647
7276
  const openDrawer = useCartStore((s2) => s2.openDrawer);
6648
7277
  const session = useSessionStore();
6649
7278
  const [accountOpen, setAccountOpen] = useState(false);
6650
- const accountRef = React37.useRef(null);
7279
+ const accountRef = React38.useRef(null);
6651
7280
  const pop = usePopOnChange(count);
6652
7281
  const firstName = session.name?.split(/\s+/)[0];
6653
7282
  const initial2 = (firstName ?? session.email ?? "C").slice(0, 1).toUpperCase();
6654
- React37.useEffect(() => {
7283
+ React38.useEffect(() => {
6655
7284
  if (!accountOpen) return;
6656
7285
  const onPointerDown = (event) => {
6657
7286
  if (!accountRef.current?.contains(event.target)) setAccountOpen(false);
@@ -6818,7 +7447,7 @@ function MobileMenuDrawer({ open, onClose }) {
6818
7447
  navigateTo(config.catalogPath);
6819
7448
  onClose();
6820
7449
  };
6821
- React37.useEffect(() => {
7450
+ React38.useEffect(() => {
6822
7451
  if (!open) return;
6823
7452
  const onKey = (e) => {
6824
7453
  if (e.key === "Escape") onClose();
@@ -7178,6 +7807,7 @@ function CartDrawer() {
7178
7807
  const FooterExtra = overrideComponent(components.CartDrawerFooterExtra);
7179
7808
  const footerExtraProps = overrideProps(components.CartDrawerFooterExtra);
7180
7809
  const validate = useDiscountValidator();
7810
+ const t = useT();
7181
7811
  const [code, setCode] = useState("");
7182
7812
  const [discountError, setDiscountError] = useState(null);
7183
7813
  const [applying, setApplying] = useState(false);
@@ -7205,15 +7835,15 @@ function CartDrawer() {
7205
7835
  const applied = code.trim().toUpperCase();
7206
7836
  cart.applyDiscount(applied, result.percent, { freeShipping: result.freeShipping });
7207
7837
  setCode("");
7208
- const effect = result.freeShipping ? "frete gr\xE1tis" : `${result.percent}% de desconto`;
7209
- toast.success("Cupom aplicado!", `${applied} \u2022 ${effect}`);
7838
+ const effect = result.freeShipping ? t("discount.freeShipping") : t("discount.percentOff", { percent: result.percent });
7839
+ toast.success(t("discount.appliedToast"), `${applied} \u2022 ${effect}`);
7210
7840
  } else {
7211
- setDiscountError(result.message ?? "Cupom inv\xE1lido.");
7212
- toast.error("Cupom inv\xE1lido", result.message ?? "Verifique o c\xF3digo e tente novamente.");
7841
+ setDiscountError(result.message ?? t("discount.invalid"));
7842
+ toast.error(t("discount.invalidToast"), result.message ?? t("discount.checkCode"));
7213
7843
  }
7214
7844
  } catch (err) {
7215
- setDiscountError("N\xE3o conseguimos validar esse cupom agora.");
7216
- toast.error("N\xE3o conseguimos validar o cupom", "Tente de novo em alguns instantes.");
7845
+ setDiscountError(t("discount.cannotValidate"));
7846
+ toast.error(t("discount.cannotValidateToast"), t("discount.tryLater"));
7217
7847
  console.warn("[cart] falha ao validar cupom", err);
7218
7848
  } finally {
7219
7849
  setApplying(false);
@@ -7237,25 +7867,25 @@ function CartDrawer() {
7237
7867
  {
7238
7868
  "data-testid": TID.cartDrawer,
7239
7869
  role: "dialog",
7240
- "aria-label": "Carrinho",
7870
+ "aria-label": t("cart.title"),
7241
7871
  className: "absolute right-0 top-0 flex h-full w-full max-w-md animate-slide-in-from-right flex-col bg-background shadow-2xl",
7242
7872
  children: [
7243
7873
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b px-5 py-4", children: [
7244
- /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", children: "Carrinho" }),
7874
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", children: t("cart.title") }),
7245
7875
  /* @__PURE__ */ jsx(
7246
7876
  "button",
7247
7877
  {
7248
7878
  type: "button",
7249
- "aria-label": "Fechar carrinho",
7879
+ "aria-label": t("cart.close"),
7250
7880
  onClick: cart.closeDrawer,
7251
7881
  className: "grid min-h-11 min-w-11 place-items-center rounded-full p-1.5 hover:bg-muted sm:min-h-0 sm:min-w-0",
7252
7882
  children: /* @__PURE__ */ jsx(X, { className: "h-5 w-5" })
7253
7883
  }
7254
7884
  )
7255
7885
  ] }),
7256
- cart.lines.length === 0 ? /* @__PURE__ */ jsx("div", { "data-testid": TID.cartEmpty, className: "flex flex-1 items-center justify-center p-8 text-center text-muted-foreground", children: "Seu carrinho est\xE1 vazio." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
7886
+ cart.lines.length === 0 ? /* @__PURE__ */ jsx("div", { "data-testid": TID.cartEmpty, className: "flex flex-1 items-center justify-center p-8 text-center text-muted-foreground", children: t("cart.empty") }) : /* @__PURE__ */ jsxs(Fragment, { children: [
7257
7887
  freeAbove != null && /* @__PURE__ */ jsxs("div", { "data-testid": TID.shippingProgress, className: "border-b bg-muted/40 px-5 py-3", children: [
7258
- /* @__PURE__ */ jsx("p", { className: "text-xs font-medium", children: missingForFree > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
7888
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium", children: config.language === "pt-BR" ? missingForFree > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
7259
7889
  "Faltam ",
7260
7890
  /* @__PURE__ */ jsx("strong", { children: money(missingForFree) }),
7261
7891
  " para frete gr\xE1tis \u{1F69A}"
@@ -7263,7 +7893,14 @@ function CartDrawer() {
7263
7893
  "\u{1F389} Voc\xEA ganhou ",
7264
7894
  /* @__PURE__ */ jsx("strong", { children: "frete gr\xE1tis" }),
7265
7895
  "!"
7266
- ] }) }),
7896
+ ] }) : missingForFree > 0 ? (() => {
7897
+ const [before, after] = t("cart.missingForFree").split("{{amount}}");
7898
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
7899
+ before,
7900
+ /* @__PURE__ */ jsx("strong", { children: money(missingForFree) }),
7901
+ after
7902
+ ] });
7903
+ })() : /* @__PURE__ */ jsx("strong", { children: t("cart.wonFree") }) }),
7267
7904
  /* @__PURE__ */ jsx("div", { className: "mt-2 h-1.5 overflow-hidden rounded-full bg-border", children: /* @__PURE__ */ jsx(
7268
7905
  "div",
7269
7906
  {
@@ -7297,7 +7934,7 @@ function CartDrawer() {
7297
7934
  {
7298
7935
  type: "button",
7299
7936
  "data-testid": TID.lineRemove,
7300
- "aria-label": `Remover ${line.name}`,
7937
+ "aria-label": t("cart.remove", { name: line.name }),
7301
7938
  onClick: () => cart.removeItem(line.lineId ?? line.productId),
7302
7939
  className: "-m-1.5 grid min-h-11 min-w-11 place-items-center p-1.5 text-muted-foreground hover:text-destructive sm:min-h-0 sm:min-w-0",
7303
7940
  children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
@@ -7354,7 +7991,7 @@ function CartDrawer() {
7354
7991
  {
7355
7992
  "data-testid": TID.discountInput,
7356
7993
  type: "text",
7357
- placeholder: "Cupom de desconto",
7994
+ placeholder: t("discount.placeholder"),
7358
7995
  value: code,
7359
7996
  onChange: (e) => setCode(e.target.value),
7360
7997
  className: "flex-1 rounded-lg border bg-background px-3 py-2 text-sm uppercase"
@@ -7368,7 +8005,7 @@ function CartDrawer() {
7368
8005
  onClick: applyCode,
7369
8006
  disabled: applying || !code.trim(),
7370
8007
  className: "rounded-lg border px-3 py-2 text-sm font-medium hover:bg-muted disabled:opacity-50",
7371
- children: "Aplicar"
8008
+ children: t("discount.apply")
7372
8009
  }
7373
8010
  )
7374
8011
  ] }),
@@ -7378,12 +8015,12 @@ function CartDrawer() {
7378
8015
  selectRequiresShipping(cart) && /* @__PURE__ */ jsx("div", { className: "mb-3", children: /* @__PURE__ */ jsx(DeliveryEstimator, { compact: true }) }),
7379
8016
  /* @__PURE__ */ jsxs("dl", { className: "space-y-1.5 text-sm", children: [
7380
8017
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
7381
- /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: "Subtotal" }),
8018
+ /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: t("summary.subtotal") }),
7382
8019
  /* @__PURE__ */ jsx("dd", { "data-testid": TID.cartSubtotal, "data-price": subtotal.toFixed(2), children: money(subtotal) })
7383
8020
  ] }),
7384
8021
  discountTotal > 0 && /* @__PURE__ */ jsxs("div", { className: "flex justify-between text-emerald-700", "data-testid": TID.discountRow, children: [
7385
8022
  /* @__PURE__ */ jsxs("dt", { children: [
7386
- "Desconto",
8023
+ t("summary.discount"),
7387
8024
  " ",
7388
8025
  /* @__PURE__ */ jsxs(
7389
8026
  "button",
@@ -7406,10 +8043,10 @@ function CartDrawer() {
7406
8043
  ] }),
7407
8044
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
7408
8045
  /* @__PURE__ */ jsxs("dt", { className: cart.discountFreeShipping ? "text-emerald-700" : "text-muted-foreground", children: [
7409
- "Frete",
8046
+ t("summary.shipping"),
7410
8047
  delivery.status === "served" && delivery.postalCode && /* @__PURE__ */ jsxs("span", { className: "ml-1 text-xs", children: [
7411
8048
  "\xB7 ",
7412
- formatPostalCode(delivery.postalCode)
8049
+ formatPostalCode(delivery.postalCode, delivery.country)
7413
8050
  ] }),
7414
8051
  cart.discountFreeShipping && /* @__PURE__ */ jsxs(
7415
8052
  "button",
@@ -7425,10 +8062,10 @@ function CartDrawer() {
7425
8062
  }
7426
8063
  )
7427
8064
  ] }),
7428
- /* @__PURE__ */ jsx("dd", { "data-testid": TID.cartShipping, "data-price": shipping.toFixed(2), children: shipping === 0 ? "Gr\xE1tis" : money(shipping) })
8065
+ /* @__PURE__ */ jsx("dd", { "data-testid": TID.cartShipping, "data-price": shipping.toFixed(2), children: shipping === 0 ? t("summary.free") : money(shipping) })
7429
8066
  ] }),
7430
8067
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between border-t pt-2 text-base font-semibold", children: [
7431
- /* @__PURE__ */ jsx("dt", { children: "Total" }),
8068
+ /* @__PURE__ */ jsx("dt", { children: t("summary.total") }),
7432
8069
  /* @__PURE__ */ jsx("dd", { "data-testid": TID.cartTotal, "data-price": total.toFixed(2), children: money(total) })
7433
8070
  ] })
7434
8071
  ] }),
@@ -7443,7 +8080,7 @@ function CartDrawer() {
7443
8080
  },
7444
8081
  className: "sf-cta w-full bg-primary py-3.5 font-semibold text-primary-foreground shadow-md transition-all hover:-translate-y-0.5 hover:shadow-lg",
7445
8082
  style: { borderRadius: "var(--sf-radius-button)" },
7446
- children: "Finalizar compra"
8083
+ children: t("cart.checkout")
7447
8084
  }
7448
8085
  ),
7449
8086
  /* @__PURE__ */ jsx(Slot, { area: "cart", name: "afterSummary", context: cartSlotContext }),
@@ -7620,7 +8257,7 @@ async function placeStorefrontOrder({
7620
8257
  customerId: customerId ?? void 0
7621
8258
  });
7622
8259
  if (replaced) return { order: replaced, customerId: customerId ?? replaced.customerId ?? "" };
7623
- const metadata = await collectOrderMetadata({
8260
+ const contributed = await collectOrderMetadata({
7624
8261
  items: cart.lines.map((line) => ({
7625
8262
  productId: line.productId,
7626
8263
  quantity: line.quantity,
@@ -7629,6 +8266,7 @@ async function placeStorefrontOrder({
7629
8266
  subtotal: cart.lines.reduce((sum, line) => sum + line.unitPrice * line.quantity, 0),
7630
8267
  customerEmail: email
7631
8268
  });
8269
+ const metadata = config.market ? { ...contributed ?? {}, market: config.market.code } : contributed;
7632
8270
  const place = (withCustomerId) => provider.placeOrder({
7633
8271
  customerId: withCustomerId,
7634
8272
  customer: { name, email },
@@ -7696,6 +8334,181 @@ function useMyOrders() {
7696
8334
  }, [customerId, email, tick]);
7697
8335
  return { orders, loading, refresh };
7698
8336
  }
8337
+ function Skeleton({ className = "", style }) {
8338
+ return /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: `block rounded bg-muted ${className}`, style });
8339
+ }
8340
+ function SkeletonGroup({ label, className = "", children, ...rest }) {
8341
+ return /* @__PURE__ */ jsxs(
8342
+ "div",
8343
+ {
8344
+ role: "status",
8345
+ "aria-busy": "true",
8346
+ className: `animate-pulse motion-reduce:animate-none ${className}`,
8347
+ ...rest,
8348
+ children: [
8349
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: label }),
8350
+ children
8351
+ ]
8352
+ }
8353
+ );
8354
+ }
8355
+ function PulseDot({ className = "" }) {
8356
+ return /* @__PURE__ */ jsxs("span", { "aria-hidden": true, className: `relative flex h-2.5 w-2.5 shrink-0 ${className}`, children: [
8357
+ /* @__PURE__ */ jsx("span", { className: "absolute inset-0 animate-ping rounded-full bg-current opacity-60 motion-reduce:animate-none" }),
8358
+ /* @__PURE__ */ jsx("span", { className: "relative inline-flex h-2.5 w-2.5 rounded-full bg-current" })
8359
+ ] });
8360
+ }
8361
+ function checkoutField(label, testId, value, onChange, props) {
8362
+ return /* @__PURE__ */ jsxs("label", { className: "block", children: [
8363
+ /* @__PURE__ */ jsx("span", { className: "mb-1.5 block text-xs font-medium text-muted-foreground", children: label }),
8364
+ /* @__PURE__ */ jsx(
8365
+ "input",
8366
+ {
8367
+ "data-testid": testId,
8368
+ "aria-label": label,
8369
+ value,
8370
+ onChange: (event) => onChange(event.target.value),
8371
+ className: "w-full rounded-lg border bg-background px-3.5 py-3 text-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/10",
8372
+ ...props
8373
+ }
8374
+ )
8375
+ ] });
8376
+ }
8377
+ function checkoutSelect(label, testId, value, onChange, options, placeholder, props) {
8378
+ return /* @__PURE__ */ jsxs("label", { className: "block", children: [
8379
+ /* @__PURE__ */ jsx("span", { className: "mb-1.5 block text-xs font-medium text-muted-foreground", children: label }),
8380
+ /* @__PURE__ */ jsxs(
8381
+ "select",
8382
+ {
8383
+ "data-testid": testId,
8384
+ "aria-label": label,
8385
+ value,
8386
+ onChange: (event) => onChange(event.target.value),
8387
+ className: "w-full rounded-lg border bg-background px-3.5 py-3 text-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/10",
8388
+ ...props,
8389
+ children: [
8390
+ /* @__PURE__ */ jsx("option", { value: "", children: placeholder }),
8391
+ options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
8392
+ ]
8393
+ }
8394
+ )
8395
+ ] });
8396
+ }
8397
+ var DRAFT_KEY = {
8398
+ postalCode: "zip",
8399
+ street: "street",
8400
+ number: "number",
8401
+ complement: "complement",
8402
+ district: "district",
8403
+ city: "city",
8404
+ region: "state"
8405
+ };
8406
+ var TEST_ID = {
8407
+ postalCode: TID.checkoutZip,
8408
+ street: TID.checkoutStreet,
8409
+ number: "checkout-number",
8410
+ complement: "checkout-complement",
8411
+ district: "checkout-district",
8412
+ city: TID.checkoutCity,
8413
+ region: "checkout-state"
8414
+ };
8415
+ function AddressForm({ country, language, value, onChange, onPostalCode, lookup, complement }) {
8416
+ const t = useT();
8417
+ const schema = getCountrySchema(country);
8418
+ const specs = new Map(schema.fields.map((spec) => [spec.key, spec]));
8419
+ const showComplement = complement?.visible !== false;
8420
+ const requireComplement = complement?.required === true;
8421
+ function input(spec) {
8422
+ const key = DRAFT_KEY[spec.key];
8423
+ const label = spec.label[language];
8424
+ const required = spec.required || spec.key === "complement" && requireComplement;
8425
+ const basePlaceholder = spec.placeholder?.[language] ?? label;
8426
+ const placeholder = required ? basePlaceholder : t("checkout.address.optional", { label: basePlaceholder });
8427
+ if (spec.key === "postalCode") {
8428
+ return checkoutField(label, TEST_ID.postalCode, value.zip, onPostalCode, {
8429
+ placeholder,
8430
+ inputMode: schema.postal.inputMode,
8431
+ autoComplete: "postal-code"
8432
+ });
8433
+ }
8434
+ if (spec.key === "region" && schema.region.input === "select" && schema.regions) {
8435
+ return checkoutSelect(
8436
+ label,
8437
+ TEST_ID.region,
8438
+ value.state,
8439
+ (next) => onChange("state", next),
8440
+ schema.regions.map((region) => ({
8441
+ value: schema.region.stores === "code" ? region.code : region.name,
8442
+ label: region.name
8443
+ })),
8444
+ t("checkout.address.choose"),
8445
+ { autoComplete: spec.autoComplete }
8446
+ );
8447
+ }
8448
+ return checkoutField(label, TEST_ID[spec.key], value[key], (next) => onChange(key, next), {
8449
+ placeholder,
8450
+ ...spec.autoComplete ? { autoComplete: spec.autoComplete } : {}
8451
+ });
8452
+ }
8453
+ function postalHint() {
8454
+ if (lookup === "loading") {
8455
+ return /* @__PURE__ */ jsxs(SkeletonGroup, { label: t("checkout.address.lookingUp"), className: "grid gap-1.5 px-1", children: [
8456
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-2.5 w-40" }),
8457
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-2.5 w-24" })
8458
+ ] });
8459
+ }
8460
+ if (schema.postal.lookup === "viacep") {
8461
+ return /* @__PURE__ */ jsx("p", { className: "px-1 text-xs text-muted-foreground", children: lookup === "not-found" ? t("checkout.address.notFound") : t("checkout.address.filled") });
8462
+ }
8463
+ if (schema.postal.lookup === "prefix" && lookup === "found") {
8464
+ return /* @__PURE__ */ jsx("p", { className: "px-1 text-xs text-muted-foreground", children: t("checkout.address.regionFromPostal") });
8465
+ }
8466
+ return null;
8467
+ }
8468
+ return /* @__PURE__ */ jsx("div", { className: "grid gap-3", children: schema.rows.map((row) => {
8469
+ const cells = row.filter((key) => specs.has(key) && (key !== "complement" || showComplement));
8470
+ if (cells.length === 0) return null;
8471
+ if (cells.length === 1 && cells[0] === "postalCode") {
8472
+ return /* @__PURE__ */ jsxs("div", { className: "grid gap-1 sm:grid-cols-[200px_1fr] sm:items-center", children: [
8473
+ input(specs.get("postalCode")),
8474
+ postalHint()
8475
+ ] }, "postalCode");
8476
+ }
8477
+ if (row.length === 1) return /* @__PURE__ */ jsx(React38.Fragment, { children: input(specs.get(cells[0])) }, cells[0]);
8478
+ return /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3", children: cells.map((key) => /* @__PURE__ */ jsx(React38.Fragment, { children: input(specs.get(key)) }, key)) }, cells.join("-"));
8479
+ }) });
8480
+ }
8481
+ function flag(iso2) {
8482
+ return iso2.toUpperCase().replace(/[^A-Z]/g, "").split("").map((c) => String.fromCodePoint(127462 + c.charCodeAt(0) - 65)).join("");
8483
+ }
8484
+ function CountrySelect({ country, allowed, onChange, className }) {
8485
+ const t = useT();
8486
+ const config = useStorefrontConfig();
8487
+ return /* @__PURE__ */ jsxs("label", { className: `flex items-center gap-2 text-sm ${className ?? ""}`, children: [
8488
+ /* @__PURE__ */ jsx(MapPin, { className: "h-4 w-4 shrink-0 text-muted-foreground", "aria-hidden": true }),
8489
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("country.deliverTo") }),
8490
+ /* @__PURE__ */ jsx(
8491
+ "select",
8492
+ {
8493
+ "data-testid": "deliver-to-country",
8494
+ "aria-label": t("country.label"),
8495
+ value: country,
8496
+ onChange: (event) => onChange(event.target.value),
8497
+ className: "rounded-lg border bg-background px-2.5 py-1.5 text-sm font-medium outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/10",
8498
+ children: allowed.map((iso2) => /* @__PURE__ */ jsxs("option", { value: iso2, children: [
8499
+ flag(iso2),
8500
+ " ",
8501
+ countryName(iso2, config.language)
8502
+ ] }, iso2))
8503
+ }
8504
+ )
8505
+ ] });
8506
+ }
8507
+ function DeliverToPicker({ className }) {
8508
+ const buyer = useBuyerCountry();
8509
+ if (buyer.allowed.length < 2) return null;
8510
+ return /* @__PURE__ */ jsx(CountrySelect, { className, country: buyer.country, allowed: buyer.allowed, onChange: buyer.setCountry });
8511
+ }
7699
8512
 
7700
8513
  // src/app/return-path.ts
7701
8514
  var KEY2 = "fayz:sf:return-path";
@@ -7827,14 +8640,15 @@ function SignInModal({ defaultEmail = "", onClose, onSignedIn }) {
7827
8640
  );
7828
8641
  }
7829
8642
  var LABELS2 = {
7830
- 1: "Dados",
7831
- 2: "Entrega",
7832
- 3: "Pagamento",
7833
- 4: "Pronto"
8643
+ 1: "checkout.steps.1",
8644
+ 2: "checkout.steps.2",
8645
+ 3: "checkout.steps.3",
8646
+ 4: "checkout.steps.4"
7834
8647
  };
7835
8648
  function CheckoutSteps({ current, onGoBackTo, omit }) {
8649
+ const t = useT();
7836
8650
  const steps = [1, 2, 3, 4].filter((s2) => !omit?.includes(s2));
7837
- return /* @__PURE__ */ jsxs("nav", { "data-testid": TID.checkoutSteps, "aria-label": "Etapas do checkout", className: "mb-8", children: [
8651
+ return /* @__PURE__ */ jsxs("nav", { "data-testid": TID.checkoutSteps, "aria-label": t("checkout.steps.label"), className: "mb-8", children: [
7838
8652
  /* @__PURE__ */ jsx("ol", { className: "flex items-center gap-1.5 sm:gap-2", children: steps.map((step, index) => {
7839
8653
  const done = step < current;
7840
8654
  const active2 = step === current;
@@ -7874,7 +8688,7 @@ function CheckoutSteps({ current, onGoBackTo, omit }) {
7874
8688
  children: done ? /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5" }) : index + 1
7875
8689
  }
7876
8690
  ),
7877
- /* @__PURE__ */ jsx("span", { className: `hidden truncate text-sm sm:inline ${active2 ? "font-semibold" : ""}`, children: LABELS2[step] })
8691
+ /* @__PURE__ */ jsx("span", { className: `hidden truncate text-sm sm:inline ${active2 ? "font-semibold" : ""}`, children: t(LABELS2[step]) })
7878
8692
  ]
7879
8693
  }
7880
8694
  ),
@@ -7888,34 +8702,10 @@ function CheckoutSteps({ current, onGoBackTo, omit }) {
7888
8702
  /* @__PURE__ */ jsxs("p", { className: "mt-2 text-sm font-semibold sm:hidden", children: [
7889
8703
  steps.indexOf(current) + 1,
7890
8704
  ". ",
7891
- LABELS2[current]
8705
+ t(LABELS2[current])
7892
8706
  ] })
7893
8707
  ] });
7894
8708
  }
7895
- function Skeleton({ className = "", style }) {
7896
- return /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: `block rounded bg-muted ${className}`, style });
7897
- }
7898
- function SkeletonGroup({ label, className = "", children, ...rest }) {
7899
- return /* @__PURE__ */ jsxs(
7900
- "div",
7901
- {
7902
- role: "status",
7903
- "aria-busy": "true",
7904
- className: `animate-pulse motion-reduce:animate-none ${className}`,
7905
- ...rest,
7906
- children: [
7907
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: label }),
7908
- children
7909
- ]
7910
- }
7911
- );
7912
- }
7913
- function PulseDot({ className = "" }) {
7914
- return /* @__PURE__ */ jsxs("span", { "aria-hidden": true, className: `relative flex h-2.5 w-2.5 shrink-0 ${className}`, children: [
7915
- /* @__PURE__ */ jsx("span", { className: "absolute inset-0 animate-ping rounded-full bg-current opacity-60 motion-reduce:animate-none" }),
7916
- /* @__PURE__ */ jsx("span", { className: "relative inline-flex h-2.5 w-2.5 rounded-full bg-current" })
7917
- ] });
7918
- }
7919
8709
  var SDK_URL = "https://sdk.mercadopago.com/js/v2";
7920
8710
  var CONTAINER_ID = "fayz-mp-card-brick";
7921
8711
  var DEVICE_SCRIPT_URL = "https://www.mercadopago.com/v2/security.js";
@@ -8041,13 +8831,13 @@ function CardBrick({ publicKey, amount, email, onSubmit, onError }) {
8041
8831
  var POLL_MS = 3e3;
8042
8832
  var RESUME_KEY = "fz.checkout.resume";
8043
8833
  function useExpiry(expiresAt) {
8044
- const target = React37.useMemo(() => {
8834
+ const target = React38.useMemo(() => {
8045
8835
  if (!expiresAt) return null;
8046
8836
  const t = new Date(expiresAt).getTime();
8047
8837
  return Number.isFinite(t) ? t : null;
8048
8838
  }, [expiresAt]);
8049
- const [now, setNow] = React37.useState(() => Date.now());
8050
- React37.useEffect(() => {
8839
+ const [now, setNow] = React38.useState(() => Date.now());
8840
+ React38.useEffect(() => {
8051
8841
  if (target === null) return;
8052
8842
  const id = setInterval(() => setNow(Date.now()), 1e3);
8053
8843
  return () => clearInterval(id);
@@ -8580,30 +9370,49 @@ function pickLastAddress(orders) {
8580
9370
  }
8581
9371
  return null;
8582
9372
  }
9373
+ function toShippingAddress(form, country) {
9374
+ const schema = getCountrySchema(country);
9375
+ const isBrazil = schema.iso2 === "BR";
9376
+ const has = (key) => schema.fields.some((f2) => f2.key === key);
9377
+ return {
9378
+ postalCode: isBrazil ? form.zip.trim() : normalizePostalCode(form.zip, country),
9379
+ street: form.street.trim(),
9380
+ number: has("number") ? form.number.trim() || void 0 : void 0,
9381
+ complement: form.complement.trim() || void 0,
9382
+ district: has("district") ? form.district.trim() || void 0 : void 0,
9383
+ city: form.city.trim(),
9384
+ // A UF is a code and is upper-cased; a province is a name and keeps its case.
9385
+ state: schema.region.stores === "code" ? form.state.trim().toUpperCase() : form.state.trim(),
9386
+ country: schema.iso2,
9387
+ phone: form.phone.trim() || void 0,
9388
+ document: (isBrazil ? documentDigits(form.document) : form.document.trim().toUpperCase()) || void 0
9389
+ };
9390
+ }
8583
9391
  var PAYMENT_LABELS = {
8584
- pix: { label: "Pix", hint: "Voc\xEA recebe a chave para pagar ap\xF3s confirmar o pedido" },
9392
+ pix: { label: "payment.pix.label", hint: "payment.pix.hint" },
8585
9393
  // O cartão tem DOIS significados agora, e o texto muda com a loja: sem
8586
9394
  // adquirente é a maquininha do entregador; com adquirente é a página segura
8587
- // dele. Ver PAYMENT_HINTS abaixo — prometer "maquininha" para quem vai ser
8588
- // redirecionado é a loja mentindo sobre a própria entrega.
8589
- credit_card: { label: "Cart\xE3o de cr\xE9dito", hint: "Maquininha na entrega" },
8590
- debit_card: { label: "Cart\xE3o de d\xE9bito", hint: "Maquininha na entrega" },
8591
- boleto: { label: "Boleto", hint: "Enviado por e-mail ap\xF3s a confirma\xE7\xE3o" },
8592
- cash: { label: "Dinheiro", hint: "Pagamento na entrega" },
8593
- other: { label: "Combinar com a loja", hint: "A loja entra em contato para acertar o pagamento" }
9395
+ // dele — prometer "maquininha" para quem vai ser redirecionado é a loja
9396
+ // mentindo sobre a própria entrega.
9397
+ credit_card: { label: "payment.credit_card.label", hint: "payment.credit_card.hint" },
9398
+ debit_card: { label: "payment.debit_card.label", hint: "payment.debit_card.hint" },
9399
+ boleto: { label: "payment.boleto.label", hint: "payment.boleto.hint" },
9400
+ cash: { label: "payment.cash.label", hint: "payment.cash.hint" },
9401
+ other: { label: "payment.other.label", hint: "payment.other.hint" }
8594
9402
  };
8595
- function placeOrderMessage(err) {
9403
+ var BRAZIL_ONLY = ["pix", "boleto"];
9404
+ function placeOrderMessage(err, t) {
8596
9405
  const message = errorMessage5(err);
8597
9406
  if (/customer (email mismatch|does not belong|belongs to another)/i.test(message)) {
8598
- return "Sua sess\xE3o ficou presa a outro cadastro. Recarregue a p\xE1gina e tente de novo.";
9407
+ return t("error.sessionMismatch");
8599
9408
  }
8600
9409
  if (/out of stock|insufficient|estoque/i.test(message)) {
8601
- return "Um item do carrinho ficou sem estoque. Revise o carrinho e tente de novo.";
9410
+ return t("error.outOfStock");
8602
9411
  }
8603
9412
  if (/delivery not available|postal code/i.test(message)) {
8604
- return "Ainda n\xE3o entregamos nesse CEP. Tente outro endere\xE7o.";
9413
+ return t("error.unserved");
8605
9414
  }
8606
- return message.replace(/^shop_[a-z_]+:\s*/i, "") || "N\xE3o foi poss\xEDvel concluir o pedido.";
9415
+ return message.replace(/^shop_[a-z_]+:\s*/i, "") || t("error.placeOrder");
8607
9416
  }
8608
9417
  var DEV_BUILD = (() => {
8609
9418
  try {
@@ -8612,36 +9421,28 @@ var DEV_BUILD = (() => {
8612
9421
  return false;
8613
9422
  }
8614
9423
  })();
8615
- function field(label, testId, value, onChange, props) {
8616
- return /* @__PURE__ */ jsxs("label", { className: "block", children: [
8617
- /* @__PURE__ */ jsx("span", { className: "mb-1.5 block text-xs font-medium text-muted-foreground", children: label }),
8618
- /* @__PURE__ */ jsx(
8619
- "input",
8620
- {
8621
- "data-testid": testId,
8622
- "aria-label": label,
8623
- value,
8624
- onChange: (event) => onChange(event.target.value),
8625
- className: "w-full rounded-lg border bg-background px-3.5 py-3 text-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/10",
8626
- ...props
8627
- }
8628
- )
8629
- ] });
8630
- }
8631
9424
  function CheckoutPage() {
8632
9425
  const config = useStorefrontConfig();
8633
9426
  const cart = useCartStore();
8634
9427
  const session = useSessionStore();
8635
9428
  const delivery = useDeliveryStore();
8636
9429
  const validateDiscount2 = useDiscountValidator();
8637
- useStorefrontHead({ title: `Checkout \u2014 ${config.name}` });
8638
- const paymentMethods = config.payments.methods;
9430
+ const t = useT();
9431
+ useStorefrontHead({ title: t("checkout.title", { store: config.name }) });
9432
+ const buyer = useBuyerCountry();
9433
+ const country = buyer.country;
9434
+ const isBrazil = country === "BR";
9435
+ const countrySchema = getCountrySchema(country);
9436
+ const paymentMethods = isBrazil ? config.payments.methods : config.payments.methods.filter((method) => !BRAZIL_ONLY.includes(method));
8639
9437
  const policy = config.policy;
8640
9438
  const requiresAccount = policy?.guestCheckout === false;
8641
9439
  const fieldPolicy = policy?.checkoutFields ?? {};
8642
9440
  const gatewayCheckout = config.payments.mode === "gateway" || !!policy?.paymentProvider;
8643
- const shows = (key) => key === "document" ? gatewayCheckout || fieldPolicy.document?.visible === true : fieldPolicy[key]?.visible !== false;
8644
- const requires = (key) => key === "document" || key === "phone" ? gatewayCheckout || fieldPolicy[key]?.visible === true && fieldPolicy[key]?.required === true : fieldPolicy[key]?.visible !== false && fieldPolicy[key]?.required === true;
9441
+ const shows = (key) => key === "document" ? isBrazil && gatewayCheckout || fieldPolicy.document?.visible === true : fieldPolicy[key]?.visible !== false;
9442
+ const requires = (key) => (
9443
+ // A CPF is Brazil's; elsewhere the tax id is the buyer's to give or not.
9444
+ key === "document" && !isBrazil ? countrySchema.taxId?.required === "always" : key === "document" || key === "phone" ? gatewayCheckout || fieldPolicy[key]?.visible === true && fieldPolicy[key]?.required === true : fieldPolicy[key]?.visible !== false && fieldPolicy[key]?.required === true
9445
+ );
8645
9446
  const [selectedAddressId, setSelectedAddressId] = useState("new");
8646
9447
  const [savedAddresses, setSavedAddresses] = useState([]);
8647
9448
  const [addressesLoading, setAddressesLoading] = useState(false);
@@ -8660,6 +9461,9 @@ function CheckoutPage() {
8660
9461
  const [paymentMethod, setPaymentMethod] = useState(
8661
9462
  resume ? "credit_card" : paymentMethods[0] ?? "pix"
8662
9463
  );
9464
+ useEffect(() => {
9465
+ if (!paymentMethods.includes(paymentMethod) && paymentMethods[0]) setPaymentMethod(paymentMethods[0]);
9466
+ }, [paymentMethods, paymentMethod]);
8663
9467
  const known = useKnownCustomer();
8664
9468
  const [form, setForm] = useState({
8665
9469
  email: session.email ?? "",
@@ -8674,7 +9478,7 @@ function CheckoutPage() {
8674
9478
  district: "",
8675
9479
  state: ""
8676
9480
  });
8677
- React37.useEffect(() => {
9481
+ React38.useEffect(() => {
8678
9482
  if (!known.ready) return;
8679
9483
  setForm((current) => ({
8680
9484
  ...current,
@@ -8718,7 +9522,7 @@ function CheckoutPage() {
8718
9522
  const [applyingDiscount, setApplyingDiscount] = useState(false);
8719
9523
  const [showSignin, setShowSignin] = useState(false);
8720
9524
  const [placing, setPlacing] = useState(false);
8721
- const leaving = React37.useRef(false);
9525
+ const leaving = React38.useRef(false);
8722
9526
  const [zipLookup, setZipLookup] = useState("idle");
8723
9527
  const subtotal = selectSubtotal(cart);
8724
9528
  const discountTotal = selectDiscountTotal(cart);
@@ -8726,7 +9530,7 @@ function CheckoutPage() {
8726
9530
  const shipping = isPickup ? 0 : shippingRaw;
8727
9531
  const total = selectTotal(cart, config) - (isPickup ? shippingRaw : 0);
8728
9532
  const checkoutSlotContext = { subtotal, total };
8729
- const checkoutSessionInput = React37.useMemo(() => ({
9533
+ const checkoutSessionInput = React38.useMemo(() => ({
8730
9534
  items: cart.lines.map((line) => ({
8731
9535
  productId: line.productId,
8732
9536
  variantId: line.variantId ?? null,
@@ -8753,27 +9557,25 @@ function CheckoutPage() {
8753
9557
  document: documentDigits(form.document) || void 0,
8754
9558
  phone: form.phone.trim() || void 0
8755
9559
  },
8756
- shippingAddress: {
8757
- postalCode: form.zip.trim(),
8758
- street: form.street.trim(),
8759
- number: form.number.trim() || void 0,
8760
- complement: form.complement.trim() || void 0,
8761
- district: form.district.trim() || void 0,
8762
- city: form.city.trim(),
8763
- state: form.state.trim().toUpperCase(),
8764
- phone: form.phone.trim() || void 0,
8765
- document: documentDigits(form.document) || void 0
8766
- },
9560
+ shippingAddress: deliveryAddress(),
8767
9561
  discountCode: cart.discountCode ?? null,
8768
9562
  paymentMethod,
8769
9563
  // Qual adquirente cobra. Sai dos ajustes da loja e não de uma escolha do
8770
9564
  // comprador — a função reconfere de qualquer forma, mas mandar daqui é o
8771
9565
  // que faz o clique bater na função do gateway que a loja realmente conectou.
8772
- provider: policy?.paymentProvider ?? null
9566
+ provider: policy?.paymentProvider ?? null,
9567
+ // The market (0116) the acquirer's open function prices and charges in.
9568
+ market: config.market?.code ?? null,
9569
+ country
8773
9570
  // eslint-disable-next-line react-hooks/exhaustive-deps
8774
- }), [cart.lines, cart.discountCode, form, paymentMethod, policy?.paymentProvider]);
9571
+ }), [cart.lines, cart.discountCode, form, paymentMethod, policy?.paymentProvider, country, config.market?.code]);
8775
9572
  const [unavailable, setUnavailable] = useState([]);
8776
- const cardIsCharged = !unavailable.includes("credit_card") && (!policy?.paymentProvider || isChargeableProvider(policy.paymentProvider)) && (!policy?.paymentProvider || supportsCard(policy.paymentProvider));
9573
+ const cardIsCharged = (
9574
+ // Outside Brazil a card is charged online only by a real acquirer: with no
9575
+ // provider the online panel is the mock's Pix, which a Spanish buyer cannot
9576
+ // pay. Without one the order is placed pending, as an offline payment is.
9577
+ (isBrazil || !!policy?.paymentProvider) && !unavailable.includes("credit_card") && (!policy?.paymentProvider || isChargeableProvider(policy.paymentProvider)) && (!policy?.paymentProvider || supportsCard(policy.paymentProvider))
9578
+ );
8777
9579
  const acquirerMissing = unavailable.includes(paymentMethod);
8778
9580
  const chargesOnline = (
8779
9581
  // Pix é cobrado dentro da loja; cartão é pago na página do adquirente e
@@ -8792,17 +9594,17 @@ function CheckoutPage() {
8792
9594
  setForm((current) => ({ ...current, [key]: value }));
8793
9595
  };
8794
9596
  async function setZip(value) {
8795
- const masked = formatPostalCode(value);
9597
+ const masked = formatPostalCode(value, country);
8796
9598
  setError(null);
8797
9599
  setForm((current) => ({ ...current, zip: masked }));
8798
- if (normalizePostalCode(masked).length !== 8) {
9600
+ if (!countrySchema.postal.pattern.test(normalizePostalCode(masked, country))) {
8799
9601
  setZipLookup("idle");
8800
9602
  return;
8801
9603
  }
8802
9604
  setZipLookup("loading");
8803
- void delivery.resolve(masked, subtotal);
9605
+ void delivery.resolve(masked, subtotal, country);
8804
9606
  try {
8805
- const found = await lookupPostalCode(masked);
9607
+ const found = await lookupPostalCode(masked, country);
8806
9608
  if (!found) {
8807
9609
  setZipLookup("not-found");
8808
9610
  return;
@@ -8812,7 +9614,7 @@ function CheckoutPage() {
8812
9614
  ...current,
8813
9615
  street: found.street || current.street,
8814
9616
  district: found.district || current.district,
8815
- city: found.city,
9617
+ city: found.city || current.city,
8816
9618
  state: found.state
8817
9619
  }));
8818
9620
  } catch {
@@ -8829,12 +9631,12 @@ function CheckoutPage() {
8829
9631
  if (result.valid) {
8830
9632
  cart.applyDiscount(appliedCode, result.percent, { freeShipping: result.freeShipping });
8831
9633
  setDiscountCode(appliedCode);
8832
- const effect = result.freeShipping ? "frete gr\xE1tis" : `${result.percent}% de desconto`;
8833
- setDiscountSuccess(`${appliedCode} aplicado: ${effect}.`);
8834
- toast.success("Cupom aplicado!", `${appliedCode} \u2022 ${effect}`);
9634
+ const effect = result.freeShipping ? t("discount.freeShipping") : t("discount.percentOff", { percent: result.percent });
9635
+ setDiscountSuccess(t("discount.applied", { code: appliedCode, effect }));
9636
+ toast.success(t("discount.appliedToast"), `${appliedCode} \u2022 ${effect}`);
8835
9637
  } else {
8836
- setDiscountError(result.message ?? "Cupom inv\xE1lido.");
8837
- toast.error("Cupom inv\xE1lido", result.message ?? "Verifique o c\xF3digo e tente novamente.");
9638
+ setDiscountError(result.message ?? t("discount.invalid"));
9639
+ toast.error(t("discount.invalidToast"), result.message ?? t("discount.checkCode"));
8838
9640
  }
8839
9641
  } finally {
8840
9642
  setApplyingDiscount(false);
@@ -8865,7 +9667,8 @@ function CheckoutPage() {
8865
9667
  void listAddresses(customerId).then((addresses) => {
8866
9668
  if (cancelled || addresses.length === 0) return;
8867
9669
  setSavedAddresses(addresses);
8868
- applySavedAddress(addresses[0]);
9670
+ const here = addresses.find((address) => (address.country ?? "BR") === country);
9671
+ if (here) applySavedAddress(here);
8869
9672
  }).catch(() => {
8870
9673
  }).finally(() => {
8871
9674
  if (!cancelled) setAddressesLoading(false);
@@ -8896,17 +9699,26 @@ function CheckoutPage() {
8896
9699
  cancelled = true;
8897
9700
  };
8898
9701
  }, [session.customerId]);
9702
+ const shownCountry = React38.useRef(country);
9703
+ useEffect(() => {
9704
+ if (shownCountry.current === country) return;
9705
+ shownCountry.current = country;
9706
+ setZipLookup("idle");
9707
+ addNewAddress();
9708
+ }, [country]);
9709
+ const addressesHere = savedAddresses.filter((address) => (address.country ?? "BR") === country);
8899
9710
  useEffect(() => {
8900
9711
  if (addressMode !== "new") return;
8901
- const kept = delivery.savedAddresses.find((a) => a.id === delivery.selectedAddressId);
8902
- const looked = delivery.address;
9712
+ const keptAny = delivery.savedAddresses.find((a) => a.id === delivery.selectedAddressId);
9713
+ const kept = keptAny && (keptAny.country ?? "BR") === country ? keptAny : void 0;
9714
+ const looked = delivery.address && (delivery.address.country || "BR") === country ? delivery.address : null;
8903
9715
  if (!kept && !looked) return;
8904
9716
  setForm((current) => {
8905
9717
  if (current.zip.trim() || current.street.trim()) return current;
8906
9718
  if (kept) {
8907
9719
  return {
8908
9720
  ...current,
8909
- zip: formatPostalCode(kept.postalCode),
9721
+ zip: formatPostalCode(kept.postalCode, country),
8910
9722
  street: kept.street,
8911
9723
  number: kept.number,
8912
9724
  complement: kept.complement ?? "",
@@ -8917,14 +9729,14 @@ function CheckoutPage() {
8917
9729
  }
8918
9730
  return {
8919
9731
  ...current,
8920
- zip: formatPostalCode(looked.postalCode),
9732
+ zip: formatPostalCode(looked.postalCode, country),
8921
9733
  street: looked.street,
8922
9734
  district: looked.district,
8923
9735
  city: looked.city,
8924
9736
  state: looked.state
8925
9737
  };
8926
9738
  });
8927
- }, [delivery.address, delivery.savedAddresses, delivery.selectedAddressId, addressMode]);
9739
+ }, [delivery.address, delivery.savedAddresses, delivery.selectedAddressId, addressMode, country]);
8928
9740
  function applySavedAddress(address) {
8929
9741
  setAddressMode("saved");
8930
9742
  setSelectedAddressId(address.id);
@@ -8955,9 +9767,9 @@ function CheckoutPage() {
8955
9767
  function fail(message, testId) {
8956
9768
  setError(message);
8957
9769
  if (testId) {
8958
- const field2 = document.querySelector(`[data-testid="${testId}"]`);
8959
- field2?.scrollIntoView({ block: "center", behavior: prefersReducedMotion() ? "auto" : "smooth" });
8960
- field2?.focus({ preventScroll: true });
9770
+ const field = document.querySelector(`[data-testid="${testId}"]`);
9771
+ field?.scrollIntoView({ block: "center", behavior: prefersReducedMotion() ? "auto" : "smooth" });
9772
+ field?.focus({ preventScroll: true });
8961
9773
  }
8962
9774
  return false;
8963
9775
  }
@@ -8965,20 +9777,61 @@ function CheckoutPage() {
8965
9777
  setError(null);
8966
9778
  if (requiresAccount && !session.customerId) {
8967
9779
  setShowSignin(true);
8968
- return fail("Esta loja pede uma conta para finalizar a compra. Entre ou crie a sua.");
9780
+ return fail(t("error.requiresAccount"));
8969
9781
  }
8970
9782
  if (!form.email.trim() || !/.+@.+\..+/.test(form.email)) {
8971
- return fail("Informe um e-mail v\xE1lido.", TID.checkoutEmail);
9783
+ return fail(t("error.email"), TID.checkoutEmail);
8972
9784
  }
8973
- if (!form.name.trim()) return fail("Informe seu nome completo.", TID.checkoutName);
9785
+ if (!form.name.trim()) return fail(t("error.name"), TID.checkoutName);
8974
9786
  if (requires("phone") && !form.phone.trim()) {
8975
- return fail("Informe um telefone de contato.", "checkout-phone");
9787
+ return fail(t("error.phone"), "checkout-phone");
8976
9788
  }
8977
- if (requires("document") && !isValidDocument(form.document)) {
8978
- return fail(
8979
- form.document.trim() ? "CPF ou CNPJ inv\xE1lido \u2014 confira os n\xFAmeros." : "Informe o CPF ou CNPJ do comprador.",
8980
- TID.checkoutDocument
8981
- );
9789
+ return validateDocument();
9790
+ }
9791
+ function validateDocument() {
9792
+ if (isBrazil) {
9793
+ if (requires("document") && !isValidDocument(form.document)) {
9794
+ return fail(
9795
+ form.document.trim() ? t("error.documentInvalid") : t("error.documentMissing"),
9796
+ TID.checkoutDocument
9797
+ );
9798
+ }
9799
+ return true;
9800
+ }
9801
+ const taxId = countrySchema.taxId;
9802
+ if (!form.document.trim()) {
9803
+ return requires("document") ? fail(t("error.documentMissing"), TID.checkoutDocument) : true;
9804
+ }
9805
+ if (taxId && !taxId.validate(form.document)) return fail(t("error.taxIdInvalid"), TID.checkoutDocument);
9806
+ return true;
9807
+ }
9808
+ function validateAddressFields() {
9809
+ if (isBrazil) {
9810
+ if (!form.street.trim() || !form.city.trim() || !form.zip.trim() || !form.district.trim()) {
9811
+ return fail(t("error.address"), TID.checkoutStreet);
9812
+ }
9813
+ if (!form.number.trim()) return fail(t("error.number"), "checkout-number");
9814
+ if (requires("complement") && !form.complement.trim()) {
9815
+ return fail(t("error.complement"), "checkout-complement");
9816
+ }
9817
+ if (!/^[A-Za-z]{2}$/.test(form.state.trim())) {
9818
+ return fail(t("error.state"), "checkout-state");
9819
+ }
9820
+ return true;
9821
+ }
9822
+ const errors = validateAddress(
9823
+ { postalCode: form.zip, street: form.street, complement: form.complement, city: form.city, state: form.state },
9824
+ country,
9825
+ { complement: requires("complement") }
9826
+ );
9827
+ if (errors.postalCode === "invalid") {
9828
+ return fail(t("error.postalInvalid", { example: countrySchema.postal.example }), TID.checkoutZip);
9829
+ }
9830
+ if (errors.postalCode || errors.street || errors.city) return fail(t("error.address"), errors.postalCode ? TID.checkoutZip : TID.checkoutStreet);
9831
+ if (errors.complement) return fail(t("error.complement"), "checkout-complement");
9832
+ if (errors.region) {
9833
+ const label = countrySchema.fields.find((f2) => f2.key === "region")?.label[config.language] ?? "";
9834
+ return fail(t("error.region", { label: label.toLowerCase() }), "checkout-state");
8982
9835
  }
8983
9836
  return true;
8984
9837
  }
@@ -8986,21 +9839,9 @@ function CheckoutPage() {
8986
9839
  setError(null);
8987
9840
  if (isPickup) return true;
8988
9841
  if (!selectRequiresShipping(cart)) return true;
8989
- if (!form.street.trim() || !form.city.trim() || !form.zip.trim() || !form.district.trim()) {
8990
- return fail("Preencha ou selecione o endere\xE7o de entrega.", TID.checkoutStreet);
8991
- }
8992
- if (!form.number.trim()) return fail("Falta o n\xFAmero do endere\xE7o.", "checkout-number");
8993
- if (requires("complement") && !form.complement.trim()) {
8994
- return fail("Informe o complemento (apto, bloco).", "checkout-complement");
8995
- }
8996
- if (!/^[A-Za-z]{2}$/.test(form.state.trim())) {
8997
- return fail("Informe a UF com duas letras (ex.: RJ).", "checkout-state");
8998
- }
8999
- if (delivery.status === "unserved" && delivery.postalCode === normalizePostalCode(form.zip)) {
9000
- return fail(
9001
- delivery.refusedZone ? "Esta loja n\xE3o entrega nesse endere\xE7o. Tente outro." : "Ainda n\xE3o entregamos nesse CEP. Tente outro endere\xE7o.",
9002
- TID.checkoutZip
9003
- );
9842
+ if (!validateAddressFields()) return false;
9843
+ if (delivery.status === "unserved" && delivery.postalCode === normalizePostalCode(form.zip, country)) {
9844
+ return fail(delivery.refusedZone ? t("error.refusedZone") : t("error.unserved"), TID.checkoutZip);
9004
9845
  }
9005
9846
  return true;
9006
9847
  }
@@ -9017,17 +9858,10 @@ function CheckoutPage() {
9017
9858
  document: documentDigits(form.document) || void 0
9018
9859
  };
9019
9860
  }
9020
- return {
9021
- postalCode: form.zip.trim(),
9022
- street: form.street.trim(),
9023
- number: form.number.trim() || void 0,
9024
- complement: form.complement.trim() || void 0,
9025
- district: form.district.trim() || void 0,
9026
- city: form.city.trim(),
9027
- state: form.state.trim().toUpperCase(),
9028
- phone: form.phone.trim() || void 0,
9029
- document: documentDigits(form.document) || void 0
9030
- };
9861
+ return deliveryAddress();
9862
+ }
9863
+ function deliveryAddress() {
9864
+ return toShippingAddress(form, country);
9031
9865
  }
9032
9866
  function advance() {
9033
9867
  if (step === 1 && validateContact()) {
@@ -9074,7 +9908,7 @@ function CheckoutPage() {
9074
9908
  cart.clear();
9075
9909
  navigateTo(`/order/${order.id}`);
9076
9910
  } catch (err) {
9077
- setError(placeOrderMessage(err));
9911
+ setError(placeOrderMessage(err, t));
9078
9912
  setPlacing(false);
9079
9913
  }
9080
9914
  }
@@ -9082,41 +9916,22 @@ function CheckoutPage() {
9082
9916
  setError(null);
9083
9917
  if (requiresAccount && !session.customerId) {
9084
9918
  setShowSignin(true);
9085
- return fail("Esta loja pede uma conta para finalizar a compra. Entre ou crie a sua.");
9919
+ return fail(t("error.requiresAccount"));
9086
9920
  }
9087
9921
  if (!form.email.trim() || !/.+@.+\..+/.test(form.email)) {
9088
- return fail("Informe um e-mail v\xE1lido.", TID.checkoutEmail);
9922
+ return fail(t("error.email"), TID.checkoutEmail);
9089
9923
  }
9090
9924
  if (requires("phone") && !form.phone.trim()) {
9091
- return fail("Informe um telefone de contato.", "checkout-phone");
9925
+ return fail(t("error.phone"), "checkout-phone");
9092
9926
  }
9093
9927
  if (!form.name.trim()) {
9094
- return fail("Informe seu nome completo.", TID.checkoutName);
9095
- }
9096
- if (requires("document") && !isValidDocument(form.document)) {
9097
- return fail(
9098
- form.document.trim() ? "CPF ou CNPJ inv\xE1lido \u2014 confira os n\xFAmeros." : "Informe o CPF ou CNPJ do comprador.",
9099
- TID.checkoutDocument
9100
- );
9928
+ return fail(t("error.name"), TID.checkoutName);
9101
9929
  }
9930
+ if (!validateDocument()) return false;
9102
9931
  if (isPickup) return true;
9103
- if (!form.street.trim() || !form.city.trim() || !form.zip.trim() || !form.district.trim()) {
9104
- return fail("Preencha ou selecione o endere\xE7o de entrega.", TID.checkoutStreet);
9105
- }
9106
- if (!form.number.trim()) {
9107
- return fail("Falta o n\xFAmero do endere\xE7o.", "checkout-number");
9108
- }
9109
- if (requires("complement") && !form.complement.trim()) {
9110
- return fail("Informe o complemento (apto, bloco).", "checkout-complement");
9111
- }
9112
- if (form.state.trim().length !== 2) {
9113
- return fail("Informe a UF com duas letras (ex.: RJ).", "checkout-state");
9114
- }
9115
- if (selectRequiresShipping(cart) && delivery.status === "unserved" && delivery.postalCode === normalizePostalCode(form.zip)) {
9116
- return fail(
9117
- delivery.refusedZone ? "Esta loja n\xE3o entrega nesse endere\xE7o. Tente outro." : "Ainda n\xE3o entregamos nesse CEP. Tente outro endere\xE7o.",
9118
- TID.checkoutZip
9119
- );
9932
+ if (!validateAddressFields()) return false;
9933
+ if (selectRequiresShipping(cart) && delivery.status === "unserved" && delivery.postalCode === normalizePostalCode(form.zip, country)) {
9934
+ return fail(delivery.refusedZone ? t("error.refusedZone") : t("error.unserved"), TID.checkoutZip);
9120
9935
  }
9121
9936
  return true;
9122
9937
  }
@@ -9131,15 +9946,15 @@ function CheckoutPage() {
9131
9946
  }
9132
9947
  ),
9133
9948
  /* @__PURE__ */ jsx("header", { className: "border-b bg-background", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto flex max-w-6xl items-center justify-between gap-4 px-4 py-6 sm:px-6", children: [
9134
- /* @__PURE__ */ jsx(Link, { to: returnPath(config), className: "text-sm text-muted-foreground hover:text-foreground", children: "Voltar \xE0 loja" }),
9949
+ /* @__PURE__ */ jsx(Link, { to: returnPath(config), className: "text-sm text-muted-foreground hover:text-foreground", children: t("checkout.backToStore") }),
9135
9950
  /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
9136
9951
  /* @__PURE__ */ jsx("div", { className: "sf-heading text-2xl font-bold tracking-tight", children: config.logo ?? config.name }),
9137
9952
  /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center justify-center gap-2 text-xs text-muted-foreground", children: [
9138
9953
  /* @__PURE__ */ jsx(Lock, { className: "h-3.5 w-3.5" }),
9139
- "Checkout seguro"
9954
+ t("checkout.secure")
9140
9955
  ] })
9141
9956
  ] }),
9142
- /* @__PURE__ */ jsx("a", { href: "mailto:suporte@example.com", className: "text-sm text-muted-foreground hover:text-foreground", children: "Ajuda" })
9957
+ /* @__PURE__ */ jsx("a", { href: "mailto:suporte@example.com", className: "text-sm text-muted-foreground hover:text-foreground", children: t("checkout.help") })
9143
9958
  ] }) }),
9144
9959
  /* @__PURE__ */ jsxs("div", { className: "mx-auto grid max-w-6xl grid-cols-1 gap-8 px-4 py-8 sm:px-6 lg:grid-cols-5 lg:px-6", children: [
9145
9960
  /* @__PURE__ */ jsxs("section", { className: "lg:col-span-3 lg:pr-10", children: [
@@ -9162,35 +9977,32 @@ function CheckoutPage() {
9162
9977
  children: [
9163
9978
  step === 1 && /* @__PURE__ */ jsxs("section", { children: [
9164
9979
  /* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-center justify-between gap-4", children: [
9165
- /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold tracking-tight", children: "Informa\xE7\xF5es de contato" }),
9166
- session.email ? /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
9167
- "Conectado como ",
9168
- session.email
9169
- ] }) : /* @__PURE__ */ jsx(
9980
+ /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold tracking-tight", children: t("checkout.contact.title") }),
9981
+ session.email ? /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: t("checkout.contact.signedInAs", { email: session.email }) }) : /* @__PURE__ */ jsx(
9170
9982
  "button",
9171
9983
  {
9172
9984
  type: "button",
9173
9985
  onClick: () => setShowSignin((value) => !value),
9174
9986
  className: "text-sm font-medium text-primary hover:underline",
9175
- children: "J\xE1 tem conta? Entrar"
9987
+ children: t("checkout.contact.haveAccount")
9176
9988
  }
9177
9989
  )
9178
9990
  ] }),
9179
9991
  /* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [
9180
- field("E-mail", TID.checkoutEmail, form.email, set("email"), {
9992
+ checkoutField(t("checkout.contact.email"), TID.checkoutEmail, form.email, set("email"), {
9181
9993
  type: "email",
9182
- placeholder: "E-mail"
9994
+ placeholder: t("checkout.contact.email")
9183
9995
  }),
9184
- field("Nome completo", TID.checkoutName, form.name, set("name"), {
9185
- placeholder: "Nome completo"
9996
+ checkoutField(t("checkout.contact.name"), TID.checkoutName, form.name, set("name"), {
9997
+ placeholder: t("checkout.contact.name")
9186
9998
  }),
9187
- shows("phone") && field("Telefone", "checkout-phone", form.phone, set("phone"), {
9999
+ shows("phone") && checkoutField(t("checkout.contact.phone"), "checkout-phone", form.phone, set("phone"), {
9188
10000
  type: "tel",
9189
10001
  autoComplete: "tel",
9190
- placeholder: requires("phone") ? "Telefone" : "Telefone (opcional)"
10002
+ placeholder: requires("phone") ? t("checkout.contact.phone") : t("checkout.contact.phoneOptional")
9191
10003
  }),
9192
- shows("document") && field(
9193
- "CPF ou CNPJ",
10004
+ shows("document") && (isBrazil ? checkoutField(
10005
+ t("checkout.contact.document"),
9194
10006
  TID.checkoutDocument,
9195
10007
  form.document,
9196
10008
  (value) => {
@@ -9202,12 +10014,19 @@ function CheckoutPage() {
9202
10014
  // and a dash, which a number input silently refuses to hold.
9203
10015
  inputMode: "numeric",
9204
10016
  autoComplete: "off",
9205
- placeholder: requires("document") ? "CPF ou CNPJ" : "CPF ou CNPJ (opcional)"
10017
+ placeholder: requires("document") ? t("checkout.contact.document") : t("checkout.contact.documentOptional")
9206
10018
  }
9207
- )
10019
+ ) : checkoutField(
10020
+ // The country's own tax id (Spain: NIF/NIE), unmasked: it has letters.
10021
+ countrySchema.taxId?.label[config.language] ?? t("checkout.contact.documentOptional"),
10022
+ TID.checkoutDocument,
10023
+ form.document,
10024
+ set("document"),
10025
+ { autoComplete: "off", placeholder: countrySchema.taxId?.label[config.language] ?? "" }
10026
+ ))
9208
10027
  ] }),
9209
10028
  requiresAccount && !session.customerId && /* @__PURE__ */ jsxs("p", { className: "mt-3 rounded-lg border border-primary/30 bg-primary/5 px-3 py-2 text-sm", children: [
9210
- "Esta loja pede uma conta para finalizar a compra.",
10029
+ t("checkout.contact.requiresAccount"),
9211
10030
  " ",
9212
10031
  /* @__PURE__ */ jsx(
9213
10032
  "button",
@@ -9215,27 +10034,28 @@ function CheckoutPage() {
9215
10034
  type: "button",
9216
10035
  onClick: () => setShowSignin(true),
9217
10036
  className: "font-semibold text-primary hover:underline",
9218
- children: "Entrar ou criar conta"
10037
+ children: t("checkout.contact.signInOrCreate")
9219
10038
  }
9220
10039
  )
9221
10040
  ] })
9222
10041
  ] }),
9223
10042
  step === 2 && /* @__PURE__ */ jsxs("section", { children: [
9224
- /* @__PURE__ */ jsx("h2", { className: "mb-3 text-xl font-semibold tracking-tight", children: "Endere\xE7o de entrega" }),
10043
+ /* @__PURE__ */ jsx("h2", { className: "mb-3 text-xl font-semibold tracking-tight", children: t("checkout.address.title") }),
10044
+ buyer.allowed.length > 1 && /* @__PURE__ */ jsx(CountrySelect, { className: "mb-3", country, allowed: buyer.allowed, onChange: buyer.setCountry }),
9225
10045
  /* @__PURE__ */ jsxs("div", { className: "mb-3 grid gap-3", children: [
9226
- addressesLoading && savedAddresses.length === 0 && /* @__PURE__ */ jsx(SkeletonGroup, { label: "Buscando seus endere\xE7os salvos", className: "grid gap-3", children: [0, 1].map((row) => /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-3", children: [
10046
+ addressesLoading && savedAddresses.length === 0 && /* @__PURE__ */ jsx(SkeletonGroup, { label: t("checkout.address.loadingSaved"), className: "grid gap-3", children: [0, 1].map((row) => /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-3", children: [
9227
10047
  /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-28" }),
9228
10048
  /* @__PURE__ */ jsx(Skeleton, { className: "mt-2 h-3 w-3/4" }),
9229
10049
  /* @__PURE__ */ jsx(Skeleton, { className: "mt-1.5 h-3 w-1/2" })
9230
10050
  ] }, row)) }),
9231
- savedAddresses.map((address) => /* @__PURE__ */ jsx(
10051
+ addressesHere.map((address) => /* @__PURE__ */ jsx(
9232
10052
  "div",
9233
10053
  {
9234
10054
  className: `group relative rounded-lg border p-3 pr-11 text-left text-sm transition hover:bg-muted/40 ${selectedAddressId === address.id ? "border-primary bg-primary/5" : "border-border bg-background"}`,
9235
10055
  children: /* @__PURE__ */ jsxs("button", { type: "button", onClick: () => selectAddress(address.id), className: "block w-full text-left", children: [
9236
10056
  /* @__PURE__ */ jsxs("span", { className: "flex items-center justify-between gap-3 font-semibold", children: [
9237
10057
  address.label,
9238
- addressMode === "saved" && selectedAddressId === address.id && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-primary/10 px-2 py-0.5 text-[11px] font-bold text-primary", children: "Selecionado" })
10058
+ addressMode === "saved" && selectedAddressId === address.id && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-primary/10 px-2 py-0.5 text-[11px] font-bold text-primary", children: t("checkout.address.selected") })
9239
10059
  ] }),
9240
10060
  /* @__PURE__ */ jsxs("span", { className: "mt-1 block text-muted-foreground", children: [
9241
10061
  [address.street, address.number].filter(Boolean).join(", "),
@@ -9257,41 +10077,28 @@ function CheckoutPage() {
9257
10077
  onClick: addNewAddress,
9258
10078
  className: `rounded-lg border border-dashed p-3 text-left text-sm transition hover:bg-muted/40 ${addressMode === "new" ? "border-primary bg-primary/5" : "border-border bg-muted/20"}`,
9259
10079
  children: [
9260
- /* @__PURE__ */ jsx("span", { className: "block font-semibold text-primary", children: savedAddresses.length > 0 ? "+ Adicionar novo endere\xE7o" : "Informe o endere\xE7o de entrega" }),
9261
- /* @__PURE__ */ jsx("span", { className: "mt-1 block text-muted-foreground", children: "Preencher outro endere\xE7o para esta compra" })
10080
+ /* @__PURE__ */ jsx("span", { className: "block font-semibold text-primary", children: addressesHere.length > 0 ? t("checkout.address.addNew") : t("checkout.address.enter") }),
10081
+ /* @__PURE__ */ jsx("span", { className: "mt-1 block text-muted-foreground", children: t("checkout.address.enterHint") })
9262
10082
  ]
9263
10083
  }
9264
10084
  )
9265
10085
  ] }),
9266
- addressMode === "new" && /* @__PURE__ */ jsxs("div", { className: "grid gap-3", children: [
9267
- /* @__PURE__ */ jsxs("div", { className: "grid gap-1 sm:grid-cols-[200px_1fr] sm:items-center", children: [
9268
- field("CEP", TID.checkoutZip, form.zip, setZip, {
9269
- placeholder: "CEP",
9270
- inputMode: "numeric",
9271
- autoComplete: "postal-code"
9272
- }),
9273
- zipLookup === "loading" ? /* @__PURE__ */ jsxs(SkeletonGroup, { label: "Buscando o endere\xE7o deste CEP", className: "grid gap-1.5 px-1", children: [
9274
- /* @__PURE__ */ jsx(Skeleton, { className: "h-2.5 w-40" }),
9275
- /* @__PURE__ */ jsx(Skeleton, { className: "h-2.5 w-24" })
9276
- ] }) : /* @__PURE__ */ jsx("p", { className: "px-1 text-xs text-muted-foreground", children: zipLookup === "not-found" ? "CEP n\xE3o encontrado \u2014 preencha o endere\xE7o \xE0 m\xE3o." : "Preenchemos o endere\xE7o para voc\xEA." })
9277
- ] }),
9278
- field("Endere\xE7o", TID.checkoutStreet, form.street, set("street"), { placeholder: "Rua, avenida\u2026" }),
9279
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
9280
- field("N\xFAmero", "checkout-number", form.number, set("number"), { placeholder: "N\xFAmero" }),
9281
- shows("complement") && field("Complemento", "checkout-complement", form.complement, set("complement"), {
9282
- placeholder: requires("complement") ? "Apto, bloco" : "Apto, bloco (opcional)"
9283
- })
9284
- ] }),
9285
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
9286
- field("Bairro", "checkout-district", form.district, set("district"), { placeholder: "Bairro" }),
9287
- field("UF", "checkout-state", form.state, set("state"), { placeholder: "UF" })
9288
- ] }),
9289
- field("Cidade", TID.checkoutCity, form.city, set("city"), { placeholder: "Cidade" })
9290
- ] })
10086
+ addressMode === "new" && /* @__PURE__ */ jsx(
10087
+ AddressForm,
10088
+ {
10089
+ country,
10090
+ language: config.language,
10091
+ value: form,
10092
+ onChange: (key, value) => set(key)(value),
10093
+ onPostalCode: setZip,
10094
+ lookup: zipLookup,
10095
+ complement: { visible: shows("complement"), required: requires("complement") }
10096
+ }
10097
+ )
9291
10098
  ] }),
9292
10099
  step === 3 && placing && /* @__PURE__ */ jsxs("section", { children: [
9293
- /* @__PURE__ */ jsx("h2", { className: "mb-3 text-xl font-semibold tracking-tight", children: "Confirmando seu pedido" }),
9294
- /* @__PURE__ */ jsxs(SkeletonGroup, { label: "Criando seu pedido", className: "rounded-xl border bg-card p-6 sm:p-8", children: [
10100
+ /* @__PURE__ */ jsx("h2", { className: "mb-3 text-xl font-semibold tracking-tight", children: t("checkout.confirming.title") }),
10101
+ /* @__PURE__ */ jsxs(SkeletonGroup, { label: t("checkout.confirming.label"), className: "rounded-xl border bg-card p-6 sm:p-8", children: [
9295
10102
  /* @__PURE__ */ jsxs("div", { className: "grid gap-6 border-b pb-6 sm:grid-cols-[120px_minmax(0,1fr)]", children: [
9296
10103
  /* @__PURE__ */ jsx(Skeleton, { className: "mx-auto h-24 w-24 rounded-full" }),
9297
10104
  /* @__PURE__ */ jsxs("div", { children: [
@@ -9310,13 +10117,13 @@ function CheckoutPage() {
9310
10117
  /* @__PURE__ */ jsx(Skeleton, { className: "h-3.5 w-16" })
9311
10118
  ] }, line.lineId ?? line.productId)) })
9312
10119
  ] }),
9313
- /* @__PURE__ */ jsx("p", { className: "mt-3 text-center text-sm text-muted-foreground", children: "N\xE3o feche esta p\xE1gina \u2014 estamos registrando seu pedido na loja." })
10120
+ /* @__PURE__ */ jsx("p", { className: "mt-3 text-center text-sm text-muted-foreground", children: t("checkout.confirming.keepOpen") })
9314
10121
  ] }),
9315
10122
  step === 3 && !placing && /* @__PURE__ */ jsxs("section", { children: [
9316
- /* @__PURE__ */ jsx("h2", { className: "mb-3 text-xl font-semibold tracking-tight", children: "Pagamento" }),
9317
- /* @__PURE__ */ jsx("div", { className: "mb-3 grid gap-3", role: "radiogroup", "aria-label": "Forma de pagamento", children: paymentMethods.map((method) => {
9318
- const base = PAYMENT_LABELS[method];
9319
- const copy = method === "credit_card" && cardIsCharged ? { ...base, hint: "Voc\xEA paga na p\xE1gina segura do provedor e volta para a loja" } : base;
10123
+ /* @__PURE__ */ jsx("h2", { className: "mb-3 text-xl font-semibold tracking-tight", children: t("checkout.payment.title") }),
10124
+ /* @__PURE__ */ jsx("div", { className: "mb-3 grid gap-3", role: "radiogroup", "aria-label": t("checkout.payment.label"), children: paymentMethods.map((method) => {
10125
+ const base = { label: t(PAYMENT_LABELS[method].label), hint: t(PAYMENT_LABELS[method].hint) };
10126
+ const copy = method === "credit_card" && cardIsCharged ? { ...base, hint: t("checkout.payment.cardOnline") } : base;
9320
10127
  const selected = paymentMethod === method;
9321
10128
  return (
9322
10129
  // Cada forma de pagamento abre o que ELA pede, embaixo dela
@@ -9338,7 +10145,7 @@ function CheckoutPage() {
9338
10145
  /* @__PURE__ */ jsx(CreditCard, { className: "h-4 w-4" }),
9339
10146
  copy.label
9340
10147
  ] }),
9341
- selected && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-primary/10 px-2 py-0.5 text-[11px] font-bold text-primary", children: "Selecionado" })
10148
+ selected && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-primary/10 px-2 py-0.5 text-[11px] font-bold text-primary", children: t("checkout.address.selected") })
9342
10149
  ] }),
9343
10150
  /* @__PURE__ */ jsx("span", { className: "mt-1 block text-muted-foreground", children: copy.hint })
9344
10151
  ]
@@ -9376,10 +10183,10 @@ function CheckoutPage() {
9376
10183
  void confirmWithoutCharge();
9377
10184
  },
9378
10185
  className: "min-h-12 w-full rounded-xl bg-primary px-6 py-3 font-semibold text-primary-foreground transition hover:opacity-90 disabled:opacity-60",
9379
- children: `Fazer pedido - ${money(total)}`
10186
+ children: t("checkout.payment.placeOrder", { total: money(total) })
9380
10187
  }
9381
10188
  ),
9382
- /* @__PURE__ */ jsx("p", { className: "mt-2 text-center text-xs text-muted-foreground", children: "O pedido fica aguardando pagamento at\xE9 a loja confirmar." })
10189
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-center text-xs text-muted-foreground", children: t("checkout.payment.pendingNote") })
9383
10190
  ] }),
9384
10191
  DEV_BUILD && chargesOnline && /* @__PURE__ */ jsxs("div", { className: "mt-6 rounded-xl border border-dashed border-amber-500/60 bg-amber-500/5 p-4", children: [
9385
10192
  /* @__PURE__ */ jsx("p", { className: "text-xs font-semibold uppercase tracking-wide text-amber-600", children: "Somente em desenvolvimento" }),
@@ -9405,15 +10212,15 @@ function CheckoutPage() {
9405
10212
  ] }),
9406
10213
  step === 4 && paidOrderId && /* @__PURE__ */ jsxs("section", { "data-testid": TID.checkoutDone, className: "rounded-xl border bg-card p-8 text-center", children: [
9407
10214
  /* @__PURE__ */ jsx(SuccessMark, {}),
9408
- /* @__PURE__ */ jsx("h2", { className: "mt-4 text-2xl font-bold tracking-tight", children: "Pagamento confirmado!" }),
9409
- /* @__PURE__ */ jsx("p", { className: "mt-2 text-muted-foreground", children: "Seu pedido foi criado e a loja j\xE1 foi avisada." }),
10215
+ /* @__PURE__ */ jsx("h2", { className: "mt-4 text-2xl font-bold tracking-tight", children: t("checkout.done.title") }),
10216
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-muted-foreground", children: t("checkout.done.text") }),
9410
10217
  /* @__PURE__ */ jsx(
9411
10218
  "button",
9412
10219
  {
9413
10220
  type: "button",
9414
10221
  onClick: () => navigateTo(`/order/${paidOrderId}`),
9415
10222
  className: "mt-6 inline-flex min-h-11 items-center rounded-lg bg-primary px-6 py-3 text-sm font-semibold text-primary-foreground transition hover:opacity-90",
9416
- children: "Ver meu pedido"
10223
+ children: t("checkout.done.viewOrder")
9417
10224
  }
9418
10225
  )
9419
10226
  ] }),
@@ -9425,7 +10232,7 @@ function CheckoutPage() {
9425
10232
  type: "submit",
9426
10233
  "data-testid": TID.checkoutContinue,
9427
10234
  className: "min-h-12 rounded-lg bg-primary px-6 py-4 text-sm font-bold text-primary-foreground transition hover:opacity-90",
9428
- children: step === 1 ? isPickup ? `Ir para o pagamento - ${money(total)}` : "Continuar para a entrega" : `Ir para o pagamento - ${money(total)}`
10235
+ children: step === 1 ? isPickup ? t("checkout.goToPayment", { total: money(total) }) : t("checkout.continueToDelivery") : t("checkout.goToPayment", { total: money(total) })
9429
10236
  }
9430
10237
  ),
9431
10238
  step === 2 && /* @__PURE__ */ jsx(
@@ -9435,17 +10242,17 @@ function CheckoutPage() {
9435
10242
  "data-testid": TID.checkoutBack,
9436
10243
  onClick: () => goToStep(1),
9437
10244
  className: "min-h-11 rounded-lg border px-6 py-3 text-sm font-medium transition hover:bg-muted",
9438
- children: "Voltar aos dados"
10245
+ children: t("checkout.backToContact")
9439
10246
  }
9440
10247
  ),
9441
- /* @__PURE__ */ jsx(Link, { to: returnPath(config), className: "text-center text-sm text-muted-foreground hover:text-foreground", children: "Voltar ao carrinho" })
10248
+ /* @__PURE__ */ jsx(Link, { to: returnPath(config), className: "text-center text-sm text-muted-foreground hover:text-foreground", children: t("checkout.backToCart") })
9442
10249
  ] })
9443
10250
  ]
9444
10251
  }
9445
10252
  )
9446
10253
  ] }),
9447
10254
  /* @__PURE__ */ jsxs("aside", { className: "rounded-xl border bg-muted/20 p-5 lg:sticky lg:top-6 lg:col-span-2 lg:self-start", children: [
9448
- /* @__PURE__ */ jsx("h2", { className: "sr-only", children: "Resumo do pedido" }),
10255
+ /* @__PURE__ */ jsx("h2", { className: "sr-only", children: t("summary.title") }),
9449
10256
  /* @__PURE__ */ jsx("ul", { className: "space-y-4", children: cart.lines.map((line) => /* @__PURE__ */ jsxs("li", { className: "flex gap-3 text-sm", children: [
9450
10257
  /* @__PURE__ */ jsxs("div", { className: "relative h-16 w-16 flex-none overflow-hidden rounded-lg border bg-background", children: [
9451
10258
  line.imageUrl && /* @__PURE__ */ jsx(SmoothImage, { src: line.imageUrl, alt: line.name, className: "h-full w-full object-cover", variant: { width: 96 } }),
@@ -9470,7 +10277,7 @@ function CheckoutPage() {
9470
10277
  {
9471
10278
  "data-testid": TID.discountInput,
9472
10279
  type: "text",
9473
- placeholder: "Cupom de desconto",
10280
+ placeholder: t("discount.placeholder"),
9474
10281
  value: discountCode,
9475
10282
  onChange: (event) => {
9476
10283
  setDiscountCode(event.target.value);
@@ -9488,7 +10295,7 @@ function CheckoutPage() {
9488
10295
  onClick: applyDiscountCode,
9489
10296
  disabled: applyingDiscount || !discountCode.trim(),
9490
10297
  className: "rounded-lg border px-3 py-2 text-sm font-semibold hover:bg-muted disabled:opacity-50",
9491
- children: "Aplicar"
10298
+ children: t("discount.apply")
9492
10299
  }
9493
10300
  )
9494
10301
  ] }),
@@ -9497,12 +10304,12 @@ function CheckoutPage() {
9497
10304
  ] }),
9498
10305
  /* @__PURE__ */ jsxs("dl", { className: "mt-8 space-y-3 border-t pt-6 text-sm", children: [
9499
10306
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
9500
- /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: "Subtotal" }),
10307
+ /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: t("summary.subtotal") }),
9501
10308
  /* @__PURE__ */ jsx("dd", { "data-price": subtotal.toFixed(2), children: money(subtotal) })
9502
10309
  ] }),
9503
10310
  discountTotal > 0 && /* @__PURE__ */ jsxs("div", { className: "flex justify-between text-emerald-700", "data-testid": TID.discountRow, children: [
9504
10311
  /* @__PURE__ */ jsxs("dt", { children: [
9505
- "Desconto",
10312
+ t("summary.discount"),
9506
10313
  " ",
9507
10314
  /* @__PURE__ */ jsxs(
9508
10315
  "button",
@@ -9525,7 +10332,7 @@ function CheckoutPage() {
9525
10332
  ] }),
9526
10333
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
9527
10334
  /* @__PURE__ */ jsxs("dt", { className: cart.discountFreeShipping ? "text-emerald-700" : "text-muted-foreground", children: [
9528
- isPickup ? "Retirada na loja" : "Entrega",
10335
+ isPickup ? t("summary.pickup") : t("summary.delivery"),
9529
10336
  cart.discountFreeShipping && /* @__PURE__ */ jsxs(
9530
10337
  "button",
9531
10338
  {
@@ -9540,23 +10347,23 @@ function CheckoutPage() {
9540
10347
  }
9541
10348
  )
9542
10349
  ] }),
9543
- /* @__PURE__ */ jsx("dd", { "data-price": shipping.toFixed(2), children: isPickup ? "Sem taxa" : shipping === 0 ? "Gr\xE1tis" : money(shipping) })
10350
+ /* @__PURE__ */ jsx("dd", { "data-price": shipping.toFixed(2), children: isPickup ? t("summary.noFee") : shipping === 0 ? t("summary.free") : money(shipping) })
9544
10351
  ] }),
9545
10352
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between border-t pt-5 text-lg font-bold", children: [
9546
- /* @__PURE__ */ jsx("dt", { children: "Total" }),
10353
+ /* @__PURE__ */ jsx("dt", { children: t("summary.total") }),
9547
10354
  /* @__PURE__ */ jsx("dd", { "data-price": total.toFixed(2), children: money(total) })
9548
10355
  ] })
9549
10356
  ] }),
9550
10357
  /* @__PURE__ */ jsxs("div", { className: "mt-6 flex items-center gap-2 text-xs text-muted-foreground", children: [
9551
10358
  /* @__PURE__ */ jsx(ShieldCheck, { className: "h-4 w-4 text-primary" }),
9552
- "Compra protegida e dados criptografados."
10359
+ t("summary.protected")
9553
10360
  ] }),
9554
10361
  /* @__PURE__ */ jsx("div", { className: "mt-6 border-t pt-5", children: /* @__PURE__ */ jsx(Slot, { area: "checkout", name: "afterForm", context: checkoutSlotContext }) })
9555
10362
  ] }),
9556
10363
  /* @__PURE__ */ jsxs("footer", { className: "flex flex-wrap gap-4 border-t pt-5 text-xs text-muted-foreground lg:col-span-5", children: [
9557
- /* @__PURE__ */ jsx(Link, { to: "/privacy", className: "hover:text-foreground", children: "Privacidade" }),
9558
- /* @__PURE__ */ jsx(Link, { to: "/terms", className: "hover:text-foreground", children: "Termos" }),
9559
- /* @__PURE__ */ jsx(Link, { to: "/refunds", className: "hover:text-foreground", children: "Trocas e devolu\xE7\xF5es" })
10364
+ /* @__PURE__ */ jsx(Link, { to: "/privacy", className: "hover:text-foreground", children: t("legal.privacy") }),
10365
+ /* @__PURE__ */ jsx(Link, { to: "/terms", className: "hover:text-foreground", children: t("legal.terms") }),
10366
+ /* @__PURE__ */ jsx(Link, { to: "/refunds", className: "hover:text-foreground", children: t("legal.refunds") })
9560
10367
  ] })
9561
10368
  ] })
9562
10369
  ] });
@@ -9759,17 +10566,17 @@ function MenuToolbar({
9759
10566
  onQuery,
9760
10567
  autoFocusSearch
9761
10568
  }) {
9762
- const inputRef = React37.useRef(null);
9763
- const [active2, setActive] = React37.useState(null);
9764
- React37.useEffect(() => {
10569
+ const inputRef = React38.useRef(null);
10570
+ const [active2, setActive] = React38.useState(null);
10571
+ React38.useEffect(() => {
9765
10572
  setActive(
9766
10573
  (current) => current && sections.some((s2) => s2.slug === current) ? current : sections[0]?.slug ?? null
9767
10574
  );
9768
10575
  }, [sections]);
9769
- React37.useEffect(() => {
10576
+ React38.useEffect(() => {
9770
10577
  if (autoFocusSearch) inputRef.current?.focus();
9771
10578
  }, [autoFocusSearch]);
9772
- React37.useEffect(() => {
10579
+ React38.useEffect(() => {
9773
10580
  if (typeof IntersectionObserver === "undefined") return;
9774
10581
  const seen = /* @__PURE__ */ new Map();
9775
10582
  const observer = new IntersectionObserver(
@@ -9956,10 +10763,10 @@ function ItemSheet({
9956
10763
  }) {
9957
10764
  const config = useStorefrontConfig();
9958
10765
  const money = (v) => formatMoney(v, config.currency, config.locale);
9959
- const groups = React37.useMemo(() => getProductOptionGroups(product), [product]);
9960
- const [options, setOptions] = React37.useState({});
9961
- const [notes, setNotes] = React37.useState("");
9962
- const [quantity, setQuantity] = React37.useState(1);
10766
+ const groups = React38.useMemo(() => getProductOptionGroups(product), [product]);
10767
+ const [options, setOptions] = React38.useState({});
10768
+ const [notes, setNotes] = React38.useState("");
10769
+ const [quantity, setQuantity] = React38.useState(1);
9963
10770
  const image = product.images?.find((i) => i.isPrimary) ?? product.images?.[0];
9964
10771
  const stock = product.inventoryCount;
9965
10772
  const missing = groups.filter((g) => !options[g.label]);
@@ -10153,8 +10960,8 @@ function ScheduleSheet({ onClose }) {
10153
10960
  const scheduledFor = useDeliveryStore((s2) => s2.scheduledFor);
10154
10961
  const setScheduledFor = useDeliveryStore((s2) => s2.setScheduledFor);
10155
10962
  const timezone = useServiceStore((s2) => s2.service?.timezone) ?? "America/Sao_Paulo";
10156
- const [slots, setSlots] = React37.useState(null);
10157
- React37.useEffect(() => {
10963
+ const [slots, setSlots] = React38.useState(null);
10964
+ React38.useEffect(() => {
10158
10965
  let alive = true;
10159
10966
  void (async () => {
10160
10967
  const rows = await getShopProvider()?.listScheduleSlots?.(fulfillmentType) ?? [];
@@ -10164,7 +10971,7 @@ function ScheduleSheet({ onClose }) {
10164
10971
  alive = false;
10165
10972
  };
10166
10973
  }, [fulfillmentType]);
10167
- const days = React37.useMemo(() => {
10974
+ const days = React38.useMemo(() => {
10168
10975
  const fmtDay = new Intl.DateTimeFormat("pt-BR", {
10169
10976
  weekday: "long",
10170
10977
  day: "2-digit",
@@ -10250,8 +11057,8 @@ function hhmm(time) {
10250
11057
  }
10251
11058
  function ServiceHoursModal({ onClose }) {
10252
11059
  const fulfillmentType = useServiceStore((s2) => s2.fulfillmentType);
10253
- const [hours, setHours] = React37.useState(null);
10254
- React37.useEffect(() => {
11060
+ const [hours, setHours] = React38.useState(null);
11061
+ React38.useEffect(() => {
10255
11062
  let alive = true;
10256
11063
  void (async () => {
10257
11064
  const rows = await getShopProvider()?.listServiceHours?.(fulfillmentType) ?? [];
@@ -10261,7 +11068,7 @@ function ServiceHoursModal({ onClose }) {
10261
11068
  alive = false;
10262
11069
  };
10263
11070
  }, [fulfillmentType]);
10264
- const byDay = React37.useMemo(() => {
11071
+ const byDay = React38.useMemo(() => {
10265
11072
  const map = /* @__PURE__ */ new Map();
10266
11073
  for (const h of hours ?? []) {
10267
11074
  const list = map.get(h.weekday) ?? [];
@@ -10338,7 +11145,7 @@ function AddressSheet({ onClose }) {
10338
11145
  const selectAddress = useDeliveryStore((s2) => s2.selectAddress);
10339
11146
  const removeAddress = useDeliveryStore((s2) => s2.removeAddress);
10340
11147
  const subtotal = selectSubtotal(useCartStore());
10341
- const [adding, setAdding] = React37.useState(saved.length === 0);
11148
+ const [adding, setAdding] = React38.useState(saved.length === 0);
10342
11149
  return /* @__PURE__ */ jsx(
10343
11150
  "div",
10344
11151
  {
@@ -10372,7 +11179,7 @@ function AddressSheet({ onClose }) {
10372
11179
  )
10373
11180
  ] }),
10374
11181
  adding ? /* @__PURE__ */ jsx(
10375
- AddressForm,
11182
+ AddressForm2,
10376
11183
  {
10377
11184
  onDone: () => {
10378
11185
  setAdding(false);
@@ -10436,7 +11243,7 @@ function AddressSheet({ onClose }) {
10436
11243
  }
10437
11244
  );
10438
11245
  }
10439
- function AddressForm({ onDone }) {
11246
+ function AddressForm2({ onDone }) {
10440
11247
  const resolve = useDeliveryStore((s2) => s2.resolve);
10441
11248
  const saveAddress = useDeliveryStore((s2) => s2.saveAddress);
10442
11249
  const looked = useDeliveryStore((s2) => s2.address);
@@ -10444,16 +11251,16 @@ function AddressForm({ onDone }) {
10444
11251
  const storeError = useDeliveryStore((s2) => s2.error);
10445
11252
  const refusedZone = useDeliveryStore((s2) => s2.refusedZone);
10446
11253
  const subtotal = selectSubtotal(useCartStore());
10447
- const [cep, setCep] = React37.useState("");
10448
- const [number, setNumber] = React37.useState("");
10449
- const [complement, setComplement] = React37.useState("");
10450
- const [reference, setReference] = React37.useState("");
10451
- const [label, setLabel] = React37.useState("");
10452
- const [touched, setTouched] = React37.useState(false);
10453
- const numberRef = React37.useRef(null);
11254
+ const [cep, setCep] = React38.useState("");
11255
+ const [number, setNumber] = React38.useState("");
11256
+ const [complement, setComplement] = React38.useState("");
11257
+ const [reference, setReference] = React38.useState("");
11258
+ const [label, setLabel] = React38.useState("");
11259
+ const [touched, setTouched] = React38.useState(false);
11260
+ const numberRef = React38.useRef(null);
10454
11261
  const digits = normalizePostalCode(cep);
10455
11262
  const found = Boolean(looked) && normalizePostalCode(looked.postalCode) === digits;
10456
- React37.useEffect(() => {
11263
+ React38.useEffect(() => {
10457
11264
  if (found) numberRef.current?.focus();
10458
11265
  }, [found]);
10459
11266
  async function lookUp() {
@@ -10616,16 +11423,16 @@ var HIGHLIGHT_LIMIT = 6;
10616
11423
  function MenuPage() {
10617
11424
  const config = useStorefrontConfig();
10618
11425
  const addItem = useCartStore((s2) => s2.addItem);
10619
- const [openProduct, setOpenProduct] = React37.useState(null);
10620
- const [showHours, setShowHours] = React37.useState(false);
10621
- const [showClosed, setShowClosed] = React37.useState(false);
10622
- const [showAddress, setShowAddress] = React37.useState(false);
10623
- const [showSchedule, setShowSchedule] = React37.useState(false);
10624
- const [query, setQuery] = React37.useState("");
11426
+ const [openProduct, setOpenProduct] = React38.useState(null);
11427
+ const [showHours, setShowHours] = React38.useState(false);
11428
+ const [showClosed, setShowClosed] = React38.useState(false);
11429
+ const [showAddress, setShowAddress] = React38.useState(false);
11430
+ const [showSchedule, setShowSchedule] = React38.useState(false);
11431
+ const [query, setQuery] = React38.useState("");
10625
11432
  const serviceState = useServiceStore();
10626
11433
  const refreshService = useServiceStore((s2) => s2.refresh);
10627
11434
  const isOpen = selectIsOpen(serviceState);
10628
- React37.useEffect(() => {
11435
+ React38.useEffect(() => {
10629
11436
  void refreshService();
10630
11437
  }, [refreshService]);
10631
11438
  const cart = useCartStore();
@@ -10645,7 +11452,7 @@ function MenuPage() {
10645
11452
  const loading = products.status === "loading" || products.status === "idle";
10646
11453
  const items = products.data ?? [];
10647
11454
  const cats = categories.data ?? [];
10648
- const allSections = React37.useMemo(() => {
11455
+ const allSections = React38.useMemo(() => {
10649
11456
  const byCategory = /* @__PURE__ */ new Map();
10650
11457
  const loose = [];
10651
11458
  for (const p of items) {
@@ -10673,7 +11480,7 @@ function MenuPage() {
10673
11480
  }
10674
11481
  return ordered;
10675
11482
  }, [items, cats]);
10676
- const highlights = React37.useMemo(() => {
11483
+ const highlights = React38.useMemo(() => {
10677
11484
  const slugs = config.delivery?.highlightSlugs;
10678
11485
  if (slugs?.length) {
10679
11486
  const bySlug = new Map(items.map((p) => [p.slug, p]));
@@ -10682,7 +11489,7 @@ function MenuPage() {
10682
11489
  return items.filter((p) => p.compareAtPrice != null && p.compareAtPrice > p.price && p.inventoryCount > 0).slice(0, HIGHLIGHT_LIMIT);
10683
11490
  }, [items, config.delivery?.highlightSlugs]);
10684
11491
  const normalized = query.trim().toLowerCase();
10685
- const sections = React37.useMemo(() => {
11492
+ const sections = React38.useMemo(() => {
10686
11493
  if (!normalized) return allSections;
10687
11494
  return allSections.map((section) => ({
10688
11495
  ...section,
@@ -10835,7 +11642,7 @@ function MenuPage() {
10835
11642
  );
10836
11643
  }
10837
11644
  function BottomBarSpace() {
10838
- React37.useEffect(() => {
11645
+ React38.useEffect(() => {
10839
11646
  const root = document.documentElement;
10840
11647
  root.style.setProperty("--fayz-bottom-bar", "4.5rem");
10841
11648
  return () => {
@@ -11106,7 +11913,7 @@ function OrderConfirmationPage({ orderId }) {
11106
11913
  const [loading, setLoading] = useState(true);
11107
11914
  const money = (v) => formatMoney(v, config.currency, config.locale);
11108
11915
  useStorefrontHead({ title: order ? `Pedido #${order.orderNumber} \u2014 ${config.name}` : config.name });
11109
- const reload = React37.useCallback(() => {
11916
+ const reload = React38.useCallback(() => {
11110
11917
  let cancelled = false;
11111
11918
  getShopProvider().getOrder(orderId).then((o) => {
11112
11919
  if (!cancelled) setOrder(o);
@@ -11135,7 +11942,7 @@ function OrderConfirmationPage({ orderId }) {
11135
11942
  ] }, column)) }),
11136
11943
  /* @__PURE__ */ jsxs("div", { className: "mt-6", children: [
11137
11944
  /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-32" }),
11138
- /* @__PURE__ */ jsx("div", { className: "mt-3 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(React37.Fragment, { children: [
11945
+ /* @__PURE__ */ jsx("div", { className: "mt-3 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(React38.Fragment, { children: [
11139
11946
  /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-7 shrink-0 rounded-full" }),
11140
11947
  node < 3 && /* @__PURE__ */ jsx(Skeleton, { className: "h-px flex-1" })
11141
11948
  ] }, node)) })
@@ -11422,7 +12229,7 @@ function OrdersPanel() {
11422
12229
  /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-24 rounded-full" })
11423
12230
  ] }),
11424
12231
  /* @__PURE__ */ jsx(Skeleton, { className: "mt-2 h-3 w-20" }),
11425
- /* @__PURE__ */ jsx("div", { className: "mt-4 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(React37.Fragment, { children: [
12232
+ /* @__PURE__ */ jsx("div", { className: "mt-4 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(React38.Fragment, { children: [
11426
12233
  /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-6 shrink-0 rounded-full" }),
11427
12234
  node < 3 && /* @__PURE__ */ jsx(Skeleton, { className: "h-px flex-1" })
11428
12235
  ] }, node)) }),
@@ -11678,7 +12485,7 @@ function PolicyPage({ kind }) {
11678
12485
  ] }) })
11679
12486
  ] });
11680
12487
  }
11681
- var StorefrontErrorBoundary = class extends React37.Component {
12488
+ var StorefrontErrorBoundary = class extends React38.Component {
11682
12489
  constructor() {
11683
12490
  super(...arguments);
11684
12491
  this.state = { error: null };
@@ -12162,7 +12969,7 @@ function sectionToJsonSchema(name) {
12162
12969
  }
12163
12970
  };
12164
12971
  const required = ["version"];
12165
- for (const [field2, fieldSpec] of Object.entries(spec.fields)) {
12972
+ for (const [field, fieldSpec] of Object.entries(spec.fields)) {
12166
12973
  const node = { type: fieldSpec.type, description: fieldSpec.description };
12167
12974
  if (fieldSpec.enum) node.enum = [...fieldSpec.enum];
12168
12975
  if (fieldSpec.deprecated) {
@@ -12171,8 +12978,8 @@ function sectionToJsonSchema(name) {
12171
12978
  node["x-fayz-replacement"] = fieldSpec.deprecated.replacement;
12172
12979
  node["x-fayz-removed-at-section-version"] = fieldSpec.deprecated.removedAtVersion;
12173
12980
  }
12174
- properties[field2] = node;
12175
- if (fieldSpec.required) required.push(field2);
12981
+ properties[field] = node;
12982
+ if (fieldSpec.required) required.push(field);
12176
12983
  }
12177
12984
  return {
12178
12985
  type: "object",
@@ -12467,22 +13274,22 @@ function collectSettingIds(settings) {
12467
13274
  }
12468
13275
  var TOKEN_KEY = /^[a-zA-Z][a-zA-Z0-9-]*$/;
12469
13276
  function validateTheme(errors, section) {
12470
- for (const field2 of THEME_SCALE_FIELDS) {
12471
- const scale = section[field2];
13277
+ for (const field of THEME_SCALE_FIELDS) {
13278
+ const scale = section[field];
12472
13279
  if (scale === void 0) continue;
12473
13280
  if (!isRecord(scale)) continue;
12474
13281
  for (const [key, value] of Object.entries(scale)) {
12475
- const path = `theme.${field2}.${key}`;
13282
+ const path = `theme.${field}.${key}`;
12476
13283
  if (!TOKEN_KEY.test(key)) {
12477
13284
  push(
12478
13285
  errors,
12479
13286
  path,
12480
13287
  "invalid-token-key",
12481
- `"${key}" cannot become the CSS custom property ${THEME_SCALE_VAR_PREFIX[field2]}-${key} \u2014 token keys match ${TOKEN_KEY}`
13288
+ `"${key}" cannot become the CSS custom property ${THEME_SCALE_VAR_PREFIX[field]}-${key} \u2014 token keys match ${TOKEN_KEY}`
12482
13289
  );
12483
13290
  }
12484
13291
  if (typeof value !== "string") {
12485
- push(errors, path, "invalid-value", `a ${field2} token is a CSS value string, got ${typeof value}`);
13292
+ push(errors, path, "invalid-value", `a ${field} token is a CSS value string, got ${typeof value}`);
12486
13293
  }
12487
13294
  }
12488
13295
  }
@@ -12540,9 +13347,9 @@ function validateSectionEnvelope(errors, name, section) {
12540
13347
  );
12541
13348
  }
12542
13349
  }
12543
- for (const [field2, fieldSpec] of Object.entries(spec.fields)) {
12544
- if (fieldSpec.required && section[field2] === void 0) {
12545
- push(errors, `${name}.${field2}`, "missing-field", `section "${name}" requires "${field2}"`);
13350
+ for (const [field, fieldSpec] of Object.entries(spec.fields)) {
13351
+ if (fieldSpec.required && section[field] === void 0) {
13352
+ push(errors, `${name}.${field}`, "missing-field", `section "${name}" requires "${field}"`);
12546
13353
  }
12547
13354
  }
12548
13355
  return true;
@@ -12704,7 +13511,7 @@ function validateEntitiesSection(errors, section) {
12704
13511
  }
12705
13512
  const fields = declaration.fields;
12706
13513
  const fieldNames = Object.keys(fields);
12707
- for (const [name, field2] of Object.entries(fields)) {
13514
+ for (const [name, field] of Object.entries(fields)) {
12708
13515
  const fieldPath = `${path}.fields.${name}`;
12709
13516
  if (!ENTITY_FIELD_RE.test(name)) {
12710
13517
  push(errors, fieldPath, "invalid-value", `"${name}" is not a valid field name \u2014 fields are snake_case`);
@@ -12713,19 +13520,19 @@ function validateEntitiesSection(errors, section) {
12713
13520
  push(errors, fieldPath, "invalid-value", `"${name}" is a structural record column`, RESERVED_ENTITY_FIELDS);
12714
13521
  continue;
12715
13522
  }
12716
- if (!isRecord(field2) || typeof field2.type !== "string") {
13523
+ if (!isRecord(field) || typeof field.type !== "string") {
12717
13524
  push(errors, fieldPath, "invalid-value", "a field is {type: <entity field type>, label?, required?, \u2026}");
12718
13525
  continue;
12719
13526
  }
12720
- if (!ENTITY_FIELD_TYPES.includes(field2.type)) {
12721
- push(errors, `${fieldPath}.type`, "unknown-entity-field-type", `"${field2.type}" is not an entity field type`, ENTITY_FIELD_TYPES);
13527
+ if (!ENTITY_FIELD_TYPES.includes(field.type)) {
13528
+ push(errors, `${fieldPath}.type`, "unknown-entity-field-type", `"${field.type}" is not an entity field type`, ENTITY_FIELD_TYPES);
12722
13529
  continue;
12723
13530
  }
12724
- if (field2.type === "ref") {
12725
- if (typeof field2.entity !== "string" || !field2.entity) {
13531
+ if (field.type === "ref") {
13532
+ if (typeof field.entity !== "string" || !field.entity) {
12726
13533
  push(errors, fieldPath, "invalid-value", `a ref field names its target: {type: 'ref', entity: '<key>'}`);
12727
13534
  } else {
12728
- checkEntityRef(errors, `${fieldPath}.entity`, field2.entity);
13535
+ checkEntityRef(errors, `${fieldPath}.entity`, field.entity);
12729
13536
  }
12730
13537
  }
12731
13538
  }
@@ -12856,10 +13663,10 @@ function validatePromotionsSection(errors, section) {
12856
13663
  if (method.allocation !== void 0 && !APPLICATION_METHOD_ALLOCATIONS.includes(method.allocation)) {
12857
13664
  push(errors, `${methodPath}.allocation`, "invalid-value", `"${String(method.allocation)}" is not an allocation`, APPLICATION_METHOD_ALLOCATIONS);
12858
13665
  }
12859
- for (const field2 of ["maxQuantity", "applyToQuantity", "buyRulesMinQuantity"]) {
12860
- const value = method[field2];
13666
+ for (const field of ["maxQuantity", "applyToQuantity", "buyRulesMinQuantity"]) {
13667
+ const value = method[field];
12861
13668
  if (value !== void 0 && value !== null && (typeof value !== "number" || value < 1)) {
12862
- push(errors, `${methodPath}.${field2}`, "invalid-value", `${field2} is a positive integer when set`);
13669
+ push(errors, `${methodPath}.${field}`, "invalid-value", `${field} is a positive integer when set`);
12863
13670
  }
12864
13671
  }
12865
13672
  validateRuleList(errors, `${methodPath}.targetRules`, method.targetRules);
@@ -12876,8 +13683,8 @@ function validateHandleRef(errors, path, name) {
12876
13683
  }
12877
13684
  }
12878
13685
  function validateCode(errors, section) {
12879
- for (const field2 of ["logo", "provider", "auth", "footerCredit"]) {
12880
- if (section[field2] !== void 0) validateHandleRef(errors, `code.${field2}`, section[field2]);
13686
+ for (const field of ["logo", "provider", "auth", "footerCredit"]) {
13687
+ if (section[field] !== void 0) validateHandleRef(errors, `code.${field}`, section[field]);
12881
13688
  }
12882
13689
  const components = section.components;
12883
13690
  if (isRecord(components)) {
@@ -13294,6 +14101,6 @@ ${formatErrors(report.errors)}`;
13294
14101
  return config;
13295
14102
  }
13296
14103
 
13297
- export { AddressSheet, AddressStrip, BEFORE_PLACE_ORDER_VALVE, BLOCK_STRUCTURAL_KEYS, BenefitsRow, BlockDataError, CART_LINE_ANNOTATION_POINT, CATALOG_BODY_BLOCK, CHECKOUT_FIELD_POINT, CartDrawer, CatalogPage, CategoryShowcase, CheckoutPage, ClosedStoreDialog, CollectionCta, CollectionHero, ContentPage, CountdownBand, EmailConfirmationRequiredError, EntityListBlock, FaqSection, FiltersPanel, FormBlock, HeroSection, ImageTiles, ItemSheet, Link, 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, StorefrontConfigHost, StorefrontConfigProvider, StorefrontFooter, StorefrontHeader, StorefrontPage, StorefrontRouterProvider, StorefrontShell, StorefrontThemeStyle, StoryQuote, THEME_SCALE_FIELDS, THEME_SCALE_VAR_PREFIX, TID, Testimonials, TierCards, applyStoreSettings, bannerPlaceholder, blockInstanceId, buildEnquiryFromForm, checkPageBlocks, collectDataNeeds, collectOrderMetadata, contentPagePath, createStorefront, createStorefrontApp, currentStaticRenderPass, defaultPageBlocks, entityListBlockMeta, establishCustomerSession, exportStore, formatMoney, formatProductOptionSelection, getCartLineAnnotations, getCheckoutFieldContributions, getCustomerAuthAdapter, getProductCardBadges, getProductOptionGroups, hydrateStoreDocument, hydratedEntriesFor, initStorefrontRuntime, isJsonValue, isKnownPath, isNestedBlockRef, isPublicPath, isRecord, listSlots, matchContentPage, matchPath, matchesFacets, mergeCollectionFacet, mergePageTheme, navigateTo, nextMilestone, normalizeProductOptionSelection, orderGalleryImages, overrideComponent, overrideProps, pageSeo, pageThemeSelector, pickProductCardImage, placeStorefrontOrder, prefersReducedMotion, primaryImageUrl, productCardComponentContract, productJsonLd, productOptionSelectionKey, productPlaceholder, productSeo, readHydratedPageData, registerStorefrontBlocks, registerStorefrontEntities, registerStorefrontExtensionPoints, registerStorefrontLoaders, resetPageDiagnostics, resetProductOptionsDeprecationWarnings, resetStorefrontExtensionPoints, resolveAuthAdapter, resolveConfig, resolveDataParams, resolveOverride, resolvePageData, resolvePageDataNeed, resolvePaymentTerms, resolveStorefrontProvider, resolveStorefrontRoute, resolveVariantForSelection, roundCents, routePathParams, runBeforePlaceOrderValve, sectionToJsonSchema, sectionsToBlocks, selectCount, selectDiscountTotal, selectIsOpen, selectRequiresShipping, selectShipping, selectShowsHours, selectSubtotal, selectTotal, selectionPrice, serializePageData, shellRouterAdapter, signInByEmail, signOutCustomer, signUpCustomer, slugifyStoreName, storefrontComponentContracts, storefrontPaths, themeToCss, toBlockNodes, toFacetMap, useBlockData, useCartStore, useCatalogStore, useCategories, useDeliveryStore, useDiscountValidator, useEnquiry, useHashPath, useInView, useLoader, useMyOrders, useNavigate, usePopOnChange, useProduct, useProducts, useRoutePath, useRouterAdapter, useScrollToTopOnNavigate, useScrolled, useServiceStore, useSessionStore, useSlotContext, useStorefrontActions, useStorefrontConfig, useStorefrontConfigOptional, useStorefrontHead, useStorefrontPage, useStorefrontPageOptional, usedSlots, validateStore, withFacet, withStaticRenderPass };
13298
- //# sourceMappingURL=chunk-NH55KVUY.js.map
13299
- //# sourceMappingURL=chunk-NH55KVUY.js.map
14104
+ 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, StorefrontConfigHost, StorefrontConfigProvider, StorefrontFooter, StorefrontHeader, StorefrontPage, StorefrontRouterProvider, StorefrontShell, StorefrontThemeStyle, StoryQuote, THEME_SCALE_FIELDS, THEME_SCALE_VAR_PREFIX, TID, Testimonials, TierCards, applyStoreSettings, bannerPlaceholder, blockInstanceId, buildEnquiryFromForm, checkPageBlocks, collectDataNeeds, collectOrderMetadata, contentPagePath, createStorefront, createStorefrontApp, currentStaticRenderPass, defaultPageBlocks, entityListBlockMeta, establishCustomerSession, exportStore, formatMoney, formatProductOptionSelection, getCartLineAnnotations, getCheckoutFieldContributions, getCustomerAuthAdapter, getProductCardBadges, getProductOptionGroups, hydrateStoreDocument, hydratedEntriesFor, initStorefrontRuntime, isJsonValue, isKnownPath, isNestedBlockRef, isPublicPath, isRecord, listSlots, marketForCountry, marketUnitPrice, matchContentPage, matchPath, matchesFacets, mergeCollectionFacet, mergePageTheme, navigateTo, nextMilestone, normalizeLanguage, normalizeProductOptionSelection, orderGalleryImages, overrideComponent, overrideProps, pageSeo, pageThemeSelector, pickProductCardImage, placeStorefrontOrder, prefersReducedMotion, primaryImageUrl, productCardComponentContract, productJsonLd, productOptionSelectionKey, productPlaceholder, productSeo, readHydratedPageData, registerStorefrontBlocks, registerStorefrontEntities, registerStorefrontExtensionPoints, registerStorefrontLoaders, resetPageDiagnostics, resetProductOptionsDeprecationWarnings, resetStorefrontExtensionPoints, resolveAuthAdapter, resolveConfig, resolveDataParams, resolveOverride, resolvePageData, resolvePageDataNeed, resolvePaymentTerms, resolveStorefrontProvider, resolveStorefrontRoute, resolveVariantForSelection, roundCents, routePathParams, runBeforePlaceOrderValve, sectionToJsonSchema, sectionsToBlocks, selectCount, selectDiscountTotal, selectIsOpen, selectRequiresShipping, selectShipping, selectShowsHours, selectSubtotal, selectTotal, selectionPrice, serializePageData, shellRouterAdapter, signInByEmail, signOutCustomer, signUpCustomer, slugifyStoreName, storefrontComponentContracts, storefrontPaths, themeToCss, toBlockNodes, toFacetMap, 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 };
14105
+ //# sourceMappingURL=chunk-DK3KK373.js.map
14106
+ //# sourceMappingURL=chunk-DK3KK373.js.map