@fayz-ai/storefront 0.57.0 → 0.59.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.
@@ -8,7 +8,7 @@ import { normalizePostalCode, getCountrySchema, lookupPostalCode, defaultRouterA
8
8
  import React38, { createContext, useContext, useEffect, useRef, useState, useSyncExternalStore, useMemo, useCallback } from 'react';
9
9
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
10
10
  import { isStorageImageUrl, imageVariantUrl, imageSrcSet, IMAGE_SRCSET_WIDTHS, validateDiscount, documentDigits, isChargeableProvider, supportsCard, formatDocument, gatewayLabel, isValidDocument } from '@fayz-ai/shop';
11
- 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
+ import { ChevronLeft, ChevronRight, ShoppingBag, X, Minus, Plus, Send, MessageCircle, Mail, Truck, RefreshCcw, ShieldCheck, ChevronDown, Check, Search, Menu, Trash2, MapPin, Lock, CreditCard, UserRound, Store, Bike, Clock, Pencil, Star, Phone, User, UserCircle, Package, LogOut, QrCode, Copy, XCircle, RotateCcw, PackageCheck, ChefHat, Info, AlertCircle } from 'lucide-react';
12
12
  import { getLucideIcon } from '@fayz-ai/ui/icons';
13
13
  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';
14
14
  import { createMockShopProvider } from '@fayz-ai/shop/mock';
@@ -10483,7 +10483,8 @@ function etaParts(minutes) {
10483
10483
  }
10484
10484
  return { approx: false, text: `${Math.ceil(m / 60)} h` };
10485
10485
  }
10486
- function StoreCover({ onShowHours }) {
10486
+ function StoreCover({ onShowHours, onOpenAccount }) {
10487
+ const sessionName = useSessionStore((s2) => s2.name || s2.email);
10487
10488
  const config = useStorefrontConfig();
10488
10489
  const t = useT();
10489
10490
  const cover = config.delivery?.coverImage;
@@ -10517,7 +10518,18 @@ function StoreCover({ onShowHours }) {
10517
10518
  className: "absolute inset-0 -z-10 bg-gradient-to-b from-black/30 via-black/45 to-black/75"
10518
10519
  }
10519
10520
  ),
10520
- /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-3xl px-4 pb-4 pt-8", children: [
10521
+ /* @__PURE__ */ jsxs("div", { className: "relative mx-auto w-full max-w-3xl px-4 pb-4 pt-8", children: [
10522
+ onOpenAccount && /* @__PURE__ */ jsx(
10523
+ "button",
10524
+ {
10525
+ type: "button",
10526
+ onClick: onOpenAccount,
10527
+ "data-testid": "store-account",
10528
+ "aria-label": sessionName ? "Sua conta" : "Entrar ou cadastrar",
10529
+ className: "absolute right-4 top-3 grid h-10 w-10 place-items-center rounded-full bg-black/40 text-sm font-bold ring-1 ring-white/25 backdrop-blur",
10530
+ children: sessionName ? sessionName.slice(0, 1).toUpperCase() : /* @__PURE__ */ jsx(UserRound, { className: "h-5 w-5" })
10531
+ }
10532
+ ),
10521
10533
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 [text-shadow:0_1px_3px_rgb(0_0_0_/_0.7)]", children: [
10522
10534
  /* @__PURE__ */ jsx("div", { className: "grid h-14 w-14 shrink-0 place-items-center overflow-hidden rounded-xl bg-white/10 ring-1 ring-white/20", children: logo ? /* @__PURE__ */ jsx("img", { src: logo, alt: "", "aria-hidden": true, className: "h-full w-full object-cover" }) : /* @__PURE__ */ jsx("span", { className: "text-xl font-bold", children: config.name.slice(0, 1) }) }),
10523
10535
  /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
@@ -10600,11 +10612,21 @@ function AddressStrip({
10600
10612
  const type = delivery.fulfillmentType;
10601
10613
  const isPickup = type === "pickup";
10602
10614
  const money = (v) => formatMoney(v, config.currency, config.locale);
10615
+ const subtotal = selectSubtotal(useCartStore());
10616
+ const resolve = useDeliveryStore((s2) => s2.resolve);
10617
+ const quotedOnce = React38.useRef(false);
10618
+ React38.useEffect(() => {
10619
+ if (quotedOnce.current || isPickup) return;
10620
+ if (delivery.status !== "idle" || delivery.options.length > 0 || !delivery.postalCode) return;
10621
+ quotedOnce.current = true;
10622
+ void resolve(delivery.postalCode, subtotal, delivery.country);
10623
+ }, [isPickup, delivery.status, delivery.options.length, delivery.postalCode, delivery.country, subtotal, resolve]);
10603
10624
  const option = delivery.options.find((o) => o.zoneId === delivery.selectedZoneId) ?? delivery.options[0];
10604
10625
  const chosen = delivery.savedAddresses.find((a) => a.id === delivery.selectedAddressId);
10605
10626
  const pickup = config.delivery?.pickupAddress;
10606
- const feeLine = isPickup ? "Sem taxa de entrega" : option ? option.free ? "Entrega gr\xE1tis" : money(option.rate) : `A partir de ${money(config.shipping.flatRate)}`;
10607
- const etaLine = option?.etaMaxDays != null ? ` \u2022 at\xE9 ${option.etaMaxDays} dia(s)` : "";
10627
+ const rate = option ? resolveOptionRate(option, subtotal) : null;
10628
+ const feeLine = isPickup ? "Sem taxa de entrega" : delivery.status === "loading" ? "Calculando a taxa\u2026" : delivery.status === "unserved" ? "N\xE3o entregamos neste endere\xE7o" : rate != null ? rate === 0 ? "Entrega gr\xE1tis" : money(rate) : config.shipping.flatRate > 0 ? `A partir de ${money(config.shipping.flatRate)}` : "Taxa conforme o endere\xE7o";
10629
+ const etaLine = option?.etaMaxDays != null && !config.delivery?.etaMinutes ? ` \u2022 at\xE9 ${option.etaMaxDays} ${option.etaMaxDays === 1 ? "dia" : "dias"}` : "";
10608
10630
  return /* @__PURE__ */ jsxs("div", { "data-testid": TID.addressStrip, className: "border-b border-border bg-background", children: [
10609
10631
  /* @__PURE__ */ jsxs(
10610
10632
  "button",
@@ -11229,13 +11251,51 @@ function ClosedStoreDialog({
11229
11251
  );
11230
11252
  }
11231
11253
  var LABELS3 = ["Casa", "Trabalho"];
11232
- function AddressSheet({ onClose }) {
11254
+ function AddressSheet({ onClose, onSignIn }) {
11233
11255
  const saved = useDeliveryStore((s2) => s2.savedAddresses);
11234
11256
  const selectedId = useDeliveryStore((s2) => s2.selectedAddressId);
11235
11257
  const selectAddress = useDeliveryStore((s2) => s2.selectAddress);
11236
11258
  const removeAddress = useDeliveryStore((s2) => s2.removeAddress);
11259
+ const saveAddress = useDeliveryStore((s2) => s2.saveAddress);
11260
+ const current = useDeliveryStore((s2) => s2.address);
11237
11261
  const subtotal = selectSubtotal(useCartStore());
11238
- const [adding, setAdding] = React38.useState(saved.length === 0);
11262
+ const customerId = useSessionStore((s2) => s2.customerId);
11263
+ const accountBook = useAccountAddresses(customerId);
11264
+ const unsavedCurrent = current && !saved.some((a) => a.id === selectedId) ? current : null;
11265
+ const fromAccount = accountBook.filter((a) => !saved.some((b) => normalizePostalCode(b.postalCode) === normalizePostalCode(a.postalCode) && b.number.trim().toLowerCase() === (a.number ?? "").trim().toLowerCase()));
11266
+ const nothingToList = saved.length === 0 && !unsavedCurrent && fromAccount.length === 0 && !customerId;
11267
+ const [editing, setEditing] = React38.useState(
11268
+ nothingToList && !onSignIn ? {} : null
11269
+ );
11270
+ function pickAccountAddress(a) {
11271
+ const id = saveAddress({
11272
+ label: a.label ?? null,
11273
+ postalCode: a.postalCode,
11274
+ street: a.street,
11275
+ number: a.number ?? "",
11276
+ complement: a.complement ?? null,
11277
+ reference: null,
11278
+ district: a.district ?? "",
11279
+ city: a.city,
11280
+ state: a.state,
11281
+ country: a.country
11282
+ });
11283
+ void selectAddress(id, subtotal);
11284
+ onClose();
11285
+ }
11286
+ const closeRef = React38.useRef(() => {
11287
+ });
11288
+ closeRef.current = () => {
11289
+ if (editing && !nothingToList) setEditing(null);
11290
+ else onClose();
11291
+ };
11292
+ React38.useEffect(() => {
11293
+ const onKey = (e) => {
11294
+ if (e.key === "Escape") closeRef.current();
11295
+ };
11296
+ window.addEventListener("keydown", onKey);
11297
+ return () => window.removeEventListener("keydown", onKey);
11298
+ }, []);
11239
11299
  return /* @__PURE__ */ jsx(
11240
11300
  "div",
11241
11301
  {
@@ -11243,20 +11303,23 @@ function AddressSheet({ onClose }) {
11243
11303
  "aria-modal": "true",
11244
11304
  "aria-label": "Endere\xE7o de entrega",
11245
11305
  "data-testid": TID.addressSheet,
11306
+ onClick: (e) => {
11307
+ if (e.target === e.currentTarget) onClose();
11308
+ },
11246
11309
  className: "fixed inset-0 z-50 flex flex-col justify-end bg-black/50 sm:items-center sm:justify-center sm:p-6",
11247
11310
  children: /* @__PURE__ */ jsxs("div", { className: "flex max-h-[85vh] w-full flex-col overflow-hidden rounded-t-2xl bg-background sm:max-w-md sm:rounded-2xl", children: [
11248
11311
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-border p-4", children: [
11249
- adding && saved.length > 0 && /* @__PURE__ */ jsx(
11312
+ editing && !nothingToList && /* @__PURE__ */ jsx(
11250
11313
  "button",
11251
11314
  {
11252
11315
  type: "button",
11253
- onClick: () => setAdding(false),
11316
+ onClick: () => setEditing(null),
11254
11317
  "aria-label": "Voltar",
11255
11318
  className: "-ml-2 grid h-9 w-9 place-items-center rounded-full",
11256
11319
  children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-5 w-5" })
11257
11320
  }
11258
11321
  ),
11259
- /* @__PURE__ */ jsx("h2", { className: "flex-1 text-lg font-semibold", children: adding ? "Novo endere\xE7o" : "Onde voc\xEA quer receber?" }),
11322
+ /* @__PURE__ */ jsx("h2", { className: "flex-1 text-lg font-semibold", children: editing ? editing.replaces ? "Editar endere\xE7o" : "Novo endere\xE7o" : "Onde voc\xEA quer receber?" }),
11260
11323
  /* @__PURE__ */ jsx(
11261
11324
  "button",
11262
11325
  {
@@ -11268,60 +11331,122 @@ function AddressSheet({ onClose }) {
11268
11331
  }
11269
11332
  )
11270
11333
  ] }),
11271
- adding ? /* @__PURE__ */ jsx(
11334
+ editing ? /* @__PURE__ */ jsx(
11272
11335
  AddressForm2,
11273
11336
  {
11337
+ initial: editing.initial,
11338
+ replaces: editing.replaces,
11274
11339
  onDone: () => {
11275
- setAdding(false);
11340
+ setEditing(null);
11276
11341
  onClose();
11277
11342
  }
11278
11343
  }
11279
11344
  ) : /* @__PURE__ */ jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto p-4", children: [
11280
- /* @__PURE__ */ jsx("ul", { className: "space-y-2", children: saved.map((address) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2", children: [
11281
- /* @__PURE__ */ jsxs(
11345
+ unsavedCurrent && /* @__PURE__ */ jsxs("section", { className: "mb-4", "data-testid": "address-current", children: [
11346
+ /* @__PURE__ */ jsx("h3", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Endere\xE7o atual" }),
11347
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 rounded-lg border border-primary p-3", children: [
11348
+ /* @__PURE__ */ jsx(MapPin, { className: "mt-0.5 h-5 w-5 shrink-0 text-primary" }),
11349
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
11350
+ /* @__PURE__ */ jsx("span", { className: "block truncate text-sm", children: unsavedCurrent.street }),
11351
+ /* @__PURE__ */ jsx("span", { className: "block truncate text-xs text-muted-foreground", children: [unsavedCurrent.district, unsavedCurrent.city].filter(Boolean).join(" \xB7 ") })
11352
+ ] }),
11353
+ /* @__PURE__ */ jsx(
11354
+ "button",
11355
+ {
11356
+ type: "button",
11357
+ "data-testid": "address-complete-current",
11358
+ onClick: () => setEditing({ initial: { postalCode: unsavedCurrent.postalCode } }),
11359
+ className: "shrink-0 text-sm font-semibold text-primary",
11360
+ children: "Completar"
11361
+ }
11362
+ )
11363
+ ] })
11364
+ ] }),
11365
+ saved.length > 0 && /* @__PURE__ */ jsxs("section", { className: "mb-4", children: [
11366
+ /* @__PURE__ */ jsx("h3", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Seus endere\xE7os" }),
11367
+ /* @__PURE__ */ jsx("ul", { className: "space-y-2", children: saved.map((address) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-1", children: [
11368
+ /* @__PURE__ */ jsxs(
11369
+ "button",
11370
+ {
11371
+ type: "button",
11372
+ "data-testid": TID.savedAddress(address.id),
11373
+ "aria-pressed": selectedId === address.id,
11374
+ onClick: () => {
11375
+ void selectAddress(address.id, subtotal);
11376
+ onClose();
11377
+ },
11378
+ className: `flex min-w-0 flex-1 items-start gap-3 rounded-lg border p-3 text-left ${selectedId === address.id ? "border-primary" : "border-border"}`,
11379
+ children: [
11380
+ selectedId === address.id ? /* @__PURE__ */ jsx(Check, { className: "mt-0.5 h-5 w-5 shrink-0 text-primary" }) : /* @__PURE__ */ jsx(MapPin, { className: "mt-0.5 h-5 w-5 shrink-0 text-muted-foreground" }),
11381
+ /* @__PURE__ */ jsx(AddressLines, { address })
11382
+ ]
11383
+ }
11384
+ ),
11385
+ /* @__PURE__ */ jsx(
11386
+ "button",
11387
+ {
11388
+ type: "button",
11389
+ "data-testid": `edit-address-${address.id}`,
11390
+ onClick: () => setEditing({ initial: address, replaces: address.id }),
11391
+ "aria-label": `Editar ${address.street}, ${address.number}`,
11392
+ className: "mt-1 grid h-10 w-10 shrink-0 place-items-center rounded-full text-muted-foreground",
11393
+ children: /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4" })
11394
+ }
11395
+ ),
11396
+ /* @__PURE__ */ jsx(
11397
+ "button",
11398
+ {
11399
+ type: "button",
11400
+ onClick: () => removeAddress(address.id),
11401
+ "aria-label": `Remover ${address.street}, ${address.number}`,
11402
+ className: "mt-1 grid h-10 w-10 shrink-0 place-items-center rounded-full text-muted-foreground",
11403
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
11404
+ }
11405
+ )
11406
+ ] }, address.id)) })
11407
+ ] }),
11408
+ fromAccount.length > 0 && /* @__PURE__ */ jsxs("section", { className: "mb-4", "data-testid": "address-account-book", children: [
11409
+ /* @__PURE__ */ jsx("h3", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Da sua conta" }),
11410
+ /* @__PURE__ */ jsx("ul", { className: "space-y-2", children: fromAccount.map((address) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
11282
11411
  "button",
11283
11412
  {
11284
11413
  type: "button",
11285
- "data-testid": TID.savedAddress(address.id),
11286
- "aria-pressed": selectedId === address.id,
11287
- onClick: () => {
11288
- void selectAddress(address.id, subtotal);
11289
- onClose();
11290
- },
11291
- className: `flex min-w-0 flex-1 items-start gap-3 rounded-lg border p-3 text-left ${selectedId === address.id ? "border-primary" : "border-border"}`,
11414
+ onClick: () => pickAccountAddress(address),
11415
+ className: "flex w-full min-w-0 items-start gap-3 rounded-lg border border-border p-3 text-left",
11292
11416
  children: [
11293
11417
  /* @__PURE__ */ jsx(MapPin, { className: "mt-0.5 h-5 w-5 shrink-0 text-muted-foreground" }),
11294
- /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
11295
- address.label && /* @__PURE__ */ jsx("span", { className: "block text-sm font-semibold", children: address.label }),
11296
- /* @__PURE__ */ jsxs("span", { className: "block truncate text-sm", children: [
11297
- address.street,
11298
- ", ",
11299
- address.number
11300
- ] }),
11301
- /* @__PURE__ */ jsx("span", { className: "block truncate text-xs text-muted-foreground", children: [address.complement, address.district, address.city].filter(Boolean).join(" \xB7 ") }),
11302
- address.reference && /* @__PURE__ */ jsx("span", { className: "mt-0.5 block truncate text-xs text-muted-foreground", children: address.reference })
11303
- ] })
11418
+ /* @__PURE__ */ jsx(AddressLines, { address: {
11419
+ label: address.label ?? null,
11420
+ street: address.street,
11421
+ number: address.number ?? "",
11422
+ complement: address.complement ?? null,
11423
+ district: address.district ?? "",
11424
+ city: address.city,
11425
+ reference: null
11426
+ } })
11304
11427
  ]
11305
11428
  }
11306
- ),
11429
+ ) }, address.id)) })
11430
+ ] }),
11431
+ !customerId && onSignIn && /* @__PURE__ */ jsxs("div", { "data-testid": "address-sign-in", className: "mb-4 rounded-lg bg-muted/40 p-3 text-sm", children: [
11432
+ /* @__PURE__ */ jsx("p", { children: "Entre na sua conta para usar os endere\xE7os salvos nela." }),
11307
11433
  /* @__PURE__ */ jsx(
11308
11434
  "button",
11309
11435
  {
11310
11436
  type: "button",
11311
- onClick: () => removeAddress(address.id),
11312
- "aria-label": `Remover ${address.street}, ${address.number}`,
11313
- className: "mt-1 grid h-10 w-10 shrink-0 place-items-center rounded-full text-muted-foreground",
11314
- children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
11437
+ onClick: onSignIn,
11438
+ className: "mt-2 font-semibold text-primary",
11439
+ children: "Entrar ou criar conta"
11315
11440
  }
11316
11441
  )
11317
- ] }, address.id)) }),
11442
+ ] }),
11318
11443
  /* @__PURE__ */ jsxs(
11319
11444
  "button",
11320
11445
  {
11321
11446
  type: "button",
11322
11447
  "data-testid": TID.addressAddNew,
11323
- onClick: () => setAdding(true),
11324
- className: "mt-4 flex w-full items-center justify-center gap-2 rounded-full border border-border px-4 py-3 text-sm font-semibold",
11448
+ onClick: () => setEditing({}),
11449
+ className: "flex w-full items-center justify-center gap-2 rounded-full border border-border px-4 py-3 text-sm font-semibold",
11325
11450
  children: [
11326
11451
  /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
11327
11452
  "Adicionar novo endere\xE7o"
@@ -11333,19 +11458,52 @@ function AddressSheet({ onClose }) {
11333
11458
  }
11334
11459
  );
11335
11460
  }
11336
- function AddressForm2({ onDone }) {
11461
+ function AddressLines({ address }) {
11462
+ return /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
11463
+ address.label && /* @__PURE__ */ jsx("span", { className: "block text-sm font-semibold", children: address.label }),
11464
+ /* @__PURE__ */ jsxs("span", { className: "block truncate text-sm", children: [
11465
+ address.street,
11466
+ address.number ? `, ${address.number}` : ""
11467
+ ] }),
11468
+ /* @__PURE__ */ jsx("span", { className: "block truncate text-xs text-muted-foreground", children: [address.complement, address.district, address.city].filter(Boolean).join(" \xB7 ") }),
11469
+ address.reference && /* @__PURE__ */ jsx("span", { className: "mt-0.5 block truncate text-xs text-muted-foreground", children: address.reference })
11470
+ ] });
11471
+ }
11472
+ function useAccountAddresses(customerId) {
11473
+ const [rows, setRows] = React38.useState([]);
11474
+ React38.useEffect(() => {
11475
+ if (!customerId) {
11476
+ setRows([]);
11477
+ return;
11478
+ }
11479
+ const shop = getShopProvider();
11480
+ if (typeof shop.listCustomerAddresses !== "function") return;
11481
+ let cancelled = false;
11482
+ shop.listCustomerAddresses(customerId).then((list) => {
11483
+ if (!cancelled) setRows(list);
11484
+ }).catch(() => {
11485
+ if (!cancelled) setRows([]);
11486
+ });
11487
+ return () => {
11488
+ cancelled = true;
11489
+ };
11490
+ }, [customerId]);
11491
+ return rows;
11492
+ }
11493
+ function AddressForm2({ onDone, initial: initial2, replaces }) {
11337
11494
  const resolve = useDeliveryStore((s2) => s2.resolve);
11338
11495
  const saveAddress = useDeliveryStore((s2) => s2.saveAddress);
11496
+ const removeAddress = useDeliveryStore((s2) => s2.removeAddress);
11339
11497
  const looked = useDeliveryStore((s2) => s2.address);
11340
11498
  const status = useDeliveryStore((s2) => s2.status);
11341
11499
  const storeError = useDeliveryStore((s2) => s2.error);
11342
11500
  const refusedZone = useDeliveryStore((s2) => s2.refusedZone);
11343
11501
  const subtotal = selectSubtotal(useCartStore());
11344
- const [cep, setCep] = React38.useState("");
11345
- const [number, setNumber] = React38.useState("");
11346
- const [complement, setComplement] = React38.useState("");
11347
- const [reference, setReference] = React38.useState("");
11348
- const [label, setLabel] = React38.useState("");
11502
+ const [cep, setCep] = React38.useState(initial2?.postalCode ? formatPostalCode(initial2.postalCode) : "");
11503
+ const [number, setNumber] = React38.useState(initial2?.number ?? "");
11504
+ const [complement, setComplement] = React38.useState(initial2?.complement ?? "");
11505
+ const [reference, setReference] = React38.useState(initial2?.reference ?? "");
11506
+ const [label, setLabel] = React38.useState(initial2?.label ?? "");
11349
11507
  const [touched, setTouched] = React38.useState(false);
11350
11508
  const numberRef = React38.useRef(null);
11351
11509
  const digits = normalizePostalCode(cep);
@@ -11357,10 +11515,17 @@ function AddressForm2({ onDone }) {
11357
11515
  if (digits.length !== 8) return;
11358
11516
  await resolve(digits, subtotal);
11359
11517
  }
11518
+ const prefilled = React38.useRef(false);
11519
+ React38.useEffect(() => {
11520
+ if (prefilled.current || !initial2?.postalCode) return;
11521
+ prefilled.current = true;
11522
+ if (!found) void lookUp();
11523
+ }, []);
11360
11524
  function submit(event) {
11361
11525
  event.preventDefault();
11362
11526
  setTouched(true);
11363
11527
  if (!found || !number.trim()) return;
11528
+ if (replaces) removeAddress(replaces);
11364
11529
  saveAddress({
11365
11530
  label: label.trim() || null,
11366
11531
  postalCode: looked.postalCode,
@@ -11509,6 +11674,117 @@ function AddressForm2({ onDone }) {
11509
11674
  ] })
11510
11675
  ] });
11511
11676
  }
11677
+
11678
+ // src/components/account/section.ts
11679
+ var ACCOUNT_SECTIONS = [
11680
+ "profile",
11681
+ "orders",
11682
+ "addresses",
11683
+ "payments"
11684
+ ];
11685
+ var DEFAULT_ACCOUNT_SECTION = "orders";
11686
+ function isAccountSection(value) {
11687
+ return ACCOUNT_SECTIONS.includes(value);
11688
+ }
11689
+ function parseAccountSection(path) {
11690
+ const query = path.split("?")[1];
11691
+ if (!query) return DEFAULT_ACCOUNT_SECTION;
11692
+ for (const pair of query.split("&")) {
11693
+ const [key, raw = ""] = pair.split("=");
11694
+ if (key !== "section") continue;
11695
+ const value = decodeURIComponent(raw);
11696
+ return isAccountSection(value) ? value : DEFAULT_ACCOUNT_SECTION;
11697
+ }
11698
+ return DEFAULT_ACCOUNT_SECTION;
11699
+ }
11700
+ function accountSectionPath(section) {
11701
+ return `/account?section=${section}`;
11702
+ }
11703
+ function AccountDrawer({ onClose, onSignIn, onAddresses, onShowHours }) {
11704
+ const session = useSessionStore();
11705
+ const signedIn = Boolean(session.email);
11706
+ const name = session.name || session.email?.split("@")[0] || "";
11707
+ React38.useEffect(() => {
11708
+ const onKey = (event) => {
11709
+ if (event.key === "Escape") onClose();
11710
+ };
11711
+ document.addEventListener("keydown", onKey);
11712
+ return () => document.removeEventListener("keydown", onKey);
11713
+ }, [onClose]);
11714
+ const go = (path) => {
11715
+ onClose();
11716
+ navigateTo(path);
11717
+ };
11718
+ const row = "flex w-full items-center gap-3 px-5 py-3.5 text-left text-sm font-medium hover:bg-muted/50";
11719
+ return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-50 flex justify-end", role: "dialog", "aria-modal": "true", "aria-label": "Sua conta", "data-testid": "account-drawer", children: [
11720
+ /* @__PURE__ */ jsx("button", { type: "button", "aria-label": "Fechar", onClick: onClose, className: "absolute inset-0 bg-black/50" }),
11721
+ /* @__PURE__ */ jsxs("div", { className: "relative flex h-full w-[85%] max-w-sm flex-col overflow-y-auto bg-background text-foreground shadow-xl", children: [
11722
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-end p-2", children: /* @__PURE__ */ jsx("button", { type: "button", onClick: onClose, "aria-label": "Fechar", className: "grid h-10 w-10 place-items-center rounded-full", children: /* @__PURE__ */ jsx(X, { className: "h-5 w-5" }) }) }),
11723
+ signedIn ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 border-b border-border px-5 pb-4", "data-testid": "account-drawer-user", children: [
11724
+ /* @__PURE__ */ jsx("span", { className: "grid h-11 w-11 shrink-0 place-items-center rounded-full bg-primary/15 font-bold text-primary", children: name.slice(0, 1).toUpperCase() }),
11725
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0", children: [
11726
+ /* @__PURE__ */ jsx("span", { className: "block truncate font-semibold", children: name }),
11727
+ /* @__PURE__ */ jsx("span", { className: "block truncate text-xs text-muted-foreground", children: session.email })
11728
+ ] })
11729
+ ] }) : /* @__PURE__ */ jsxs(
11730
+ "button",
11731
+ {
11732
+ type: "button",
11733
+ "data-testid": "account-drawer-sign-in",
11734
+ onClick: () => {
11735
+ onClose();
11736
+ onSignIn();
11737
+ },
11738
+ className: "flex items-center gap-3 border-b border-border px-5 pb-4 text-left",
11739
+ children: [
11740
+ /* @__PURE__ */ jsx("span", { className: "grid h-11 w-11 shrink-0 place-items-center rounded-full bg-muted", children: /* @__PURE__ */ jsx(User, { className: "h-5 w-5" }) }),
11741
+ /* @__PURE__ */ jsx("span", { className: "flex-1 font-semibold", children: "Entre ou cadastre-se" }),
11742
+ /* @__PURE__ */ jsx(ChevronRight, { className: "h-5 w-5 text-muted-foreground" })
11743
+ ]
11744
+ }
11745
+ ),
11746
+ /* @__PURE__ */ jsxs("nav", { className: "py-2", "aria-label": "Sua conta", children: [
11747
+ /* @__PURE__ */ jsxs("button", { type: "button", className: row, "data-testid": "account-drawer-orders", onClick: () => go(accountSectionPath("orders")), children: [
11748
+ /* @__PURE__ */ jsx(Package, { className: "h-5 w-5 text-muted-foreground" }),
11749
+ " Meus pedidos"
11750
+ ] }),
11751
+ /* @__PURE__ */ jsxs("button", { type: "button", className: row, "data-testid": "account-drawer-addresses", onClick: () => {
11752
+ onClose();
11753
+ onAddresses();
11754
+ }, children: [
11755
+ /* @__PURE__ */ jsx(MapPin, { className: "h-5 w-5 text-muted-foreground" }),
11756
+ " Meus endere\xE7os"
11757
+ ] }),
11758
+ signedIn && /* @__PURE__ */ jsxs("button", { type: "button", className: row, "data-testid": "account-drawer-profile", onClick: () => go(accountSectionPath("profile")), children: [
11759
+ /* @__PURE__ */ jsx(User, { className: "h-5 w-5 text-muted-foreground" }),
11760
+ " Meus dados"
11761
+ ] }),
11762
+ onShowHours && /* @__PURE__ */ jsxs("button", { type: "button", className: row, onClick: () => {
11763
+ onClose();
11764
+ onShowHours();
11765
+ }, children: [
11766
+ /* @__PURE__ */ jsx(Clock, { className: "h-5 w-5 text-muted-foreground" }),
11767
+ " Hor\xE1rios de funcionamento"
11768
+ ] })
11769
+ ] }),
11770
+ signedIn && /* @__PURE__ */ jsx("div", { className: "mt-auto border-t border-border py-2", children: /* @__PURE__ */ jsxs(
11771
+ "button",
11772
+ {
11773
+ type: "button",
11774
+ className: `${row} text-destructive`,
11775
+ "data-testid": "account-drawer-sign-out",
11776
+ onClick: () => {
11777
+ void signOutCustomer().finally(onClose);
11778
+ },
11779
+ children: [
11780
+ /* @__PURE__ */ jsx(LogOut, { className: "h-5 w-5" }),
11781
+ " Sair"
11782
+ ]
11783
+ }
11784
+ ) })
11785
+ ] })
11786
+ ] });
11787
+ }
11512
11788
  var HIGHLIGHT_LIMIT = 6;
11513
11789
  function MenuPage() {
11514
11790
  const config = useStorefrontConfig();
@@ -11517,6 +11793,8 @@ function MenuPage() {
11517
11793
  const [showHours, setShowHours] = React38.useState(false);
11518
11794
  const [showClosed, setShowClosed] = React38.useState(false);
11519
11795
  const [showAddress, setShowAddress] = React38.useState(false);
11796
+ const [showAccount, setShowAccount] = React38.useState(false);
11797
+ const [showSignIn, setShowSignIn] = React38.useState(false);
11520
11798
  const [showSchedule, setShowSchedule] = React38.useState(false);
11521
11799
  const [query, setQuery] = React38.useState("");
11522
11800
  const serviceState = useServiceStore();
@@ -11618,7 +11896,7 @@ function MenuPage() {
11618
11896
  // pb-28 reserva o espaço da barra fixa do carrinho: conteúdo escondido
11619
11897
  // atrás de um elemento fixo é a falha mais comum de barra inferior.
11620
11898
  /* @__PURE__ */ jsxs("main", { "data-testid": TID.menuPage, className: "w-full pb-28", children: [
11621
- /* @__PURE__ */ jsx(StoreCover, { onShowHours: () => setShowHours(true) }),
11899
+ /* @__PURE__ */ jsx(StoreCover, { onShowHours: () => setShowHours(true), onOpenAccount: () => setShowAccount(true) }),
11622
11900
  /* @__PURE__ */ jsx(
11623
11901
  AddressStrip,
11624
11902
  {
@@ -11716,7 +11994,26 @@ function MenuPage() {
11716
11994
  )
11717
11995
  }
11718
11996
  ),
11719
- showAddress && /* @__PURE__ */ jsx(AddressSheet, { onClose: () => setShowAddress(false) }),
11997
+ showAddress && /* @__PURE__ */ jsx(
11998
+ AddressSheet,
11999
+ {
12000
+ onClose: () => setShowAddress(false),
12001
+ onSignIn: () => {
12002
+ setShowAddress(false);
12003
+ setShowSignIn(true);
12004
+ }
12005
+ }
12006
+ ),
12007
+ showAccount && /* @__PURE__ */ jsx(
12008
+ AccountDrawer,
12009
+ {
12010
+ onClose: () => setShowAccount(false),
12011
+ onSignIn: () => setShowSignIn(true),
12012
+ onAddresses: () => setShowAddress(true),
12013
+ onShowHours: () => setShowHours(true)
12014
+ }
12015
+ ),
12016
+ showSignIn && /* @__PURE__ */ jsx(SignInModal, { onClose: () => setShowSignIn(false), onSignedIn: () => setShowSignIn(false) }),
11720
12017
  showHours && /* @__PURE__ */ jsx(ServiceHoursModal, { onClose: () => setShowHours(false) }),
11721
12018
  showSchedule && /* @__PURE__ */ jsx(ScheduleSheet, { onClose: () => setShowSchedule(false) }),
11722
12019
  showClosed && /* @__PURE__ */ jsx(
@@ -11768,7 +12065,46 @@ function isPaid(status) {
11768
12065
  function isRefunded(status) {
11769
12066
  return status === "refunded" || status === "partially_refunded";
11770
12067
  }
12068
+ function deliverySteps(order) {
12069
+ const stage = order.deliveryStage;
12070
+ const pickup = order.fulfillmentType === "pickup";
12071
+ const received = {
12072
+ id: "received",
12073
+ label: "Pedido recebido",
12074
+ description: `#${order.orderNumber}`,
12075
+ state: "complete",
12076
+ icon: Check
12077
+ };
12078
+ if (stage === "rejected" || stage === "cancelled") {
12079
+ const refunded = isRefunded(order.financialStatus) || order.financialStatus === "voided";
12080
+ return [
12081
+ received,
12082
+ {
12083
+ id: "closed",
12084
+ label: stage === "rejected" ? "Pedido n\xE3o aceito" : "Pedido cancelado",
12085
+ description: [order.rejectReason, refunded ? "Valor estornado" : null].filter(Boolean).join(" \xB7 ") || "A loja cancelou este pedido",
12086
+ state: "cancelled",
12087
+ icon: XCircle
12088
+ }
12089
+ ];
12090
+ }
12091
+ const rank = { new: 0, accepted: 1, out_for_delivery: 2, delivered: 3 }[stage] ?? 0;
12092
+ const state = (step) => rank > step ? "complete" : rank === step ? "current" : "pending";
12093
+ return [
12094
+ { ...received, state: rank === 0 ? "current" : "complete", description: rank === 0 ? "Aguardando a loja aceitar" : received.description },
12095
+ { id: "accepted", label: "Em preparo", description: "A loja aceitou seu pedido", state: state(1), icon: ChefHat },
12096
+ {
12097
+ id: "out",
12098
+ label: pickup ? "Pronto para retirada" : "Saiu para entrega",
12099
+ description: pickup ? "Pode vir buscar" : "A caminho de voc\xEA",
12100
+ state: state(2),
12101
+ icon: pickup ? Store : Bike
12102
+ },
12103
+ { id: "delivered", label: pickup ? "Retirado" : "Entregue", description: "Bom apetite!", state: rank === 3 ? "complete" : "pending", icon: PackageCheck }
12104
+ ];
12105
+ }
11771
12106
  function orderTrackingSteps(order) {
12107
+ if (order.deliveryStage) return deliverySteps(order);
11772
12108
  const received = {
11773
12109
  id: "received",
11774
12110
  label: "Pedido recebido",
@@ -11877,32 +12213,6 @@ function OrderTrackingTimeline({ order, compact: compact2 = false }) {
11877
12213
  }
11878
12214
  );
11879
12215
  }
11880
-
11881
- // src/components/account/section.ts
11882
- var ACCOUNT_SECTIONS = [
11883
- "profile",
11884
- "orders",
11885
- "addresses",
11886
- "payments"
11887
- ];
11888
- var DEFAULT_ACCOUNT_SECTION = "orders";
11889
- function isAccountSection(value) {
11890
- return ACCOUNT_SECTIONS.includes(value);
11891
- }
11892
- function parseAccountSection(path) {
11893
- const query = path.split("?")[1];
11894
- if (!query) return DEFAULT_ACCOUNT_SECTION;
11895
- for (const pair of query.split("&")) {
11896
- const [key, raw = ""] = pair.split("=");
11897
- if (key !== "section") continue;
11898
- const value = decodeURIComponent(raw);
11899
- return isAccountSection(value) ? value : DEFAULT_ACCOUNT_SECTION;
11900
- }
11901
- return DEFAULT_ACCOUNT_SECTION;
11902
- }
11903
- function accountSectionPath(section) {
11904
- return `/account?section=${section}`;
11905
- }
11906
12216
  var menuItems = [
11907
12217
  { id: "profile", label: "Perfil", icon: User },
11908
12218
  { id: "orders", label: "Meus pedidos", icon: Package },
@@ -12451,12 +12761,30 @@ function ProfilePanel() {
12451
12761
  }
12452
12762
  function AddressesPanel() {
12453
12763
  const config = useStorefrontConfig();
12454
- return /* @__PURE__ */ jsxs("div", { className: "rounded-2xl border bg-card p-6", children: [
12764
+ const customerId = useSessionStore((s2) => s2.customerId);
12765
+ const account = useAccountAddresses(customerId);
12766
+ const browser = useDeliveryStore((s2) => s2.savedAddresses);
12767
+ const removeAddress = useDeliveryStore((s2) => s2.removeAddress);
12768
+ const empty = account.length === 0 && browser.length === 0;
12769
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-2xl border bg-card p-6", "data-testid": "account-addresses", children: [
12455
12770
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
12456
12771
  /* @__PURE__ */ jsx(MapPin, { className: "h-5 w-5 text-primary" }),
12457
12772
  /* @__PURE__ */ jsx("h2", { className: "sf-heading text-lg font-semibold", children: "Endere\xE7os" })
12458
12773
  ] }),
12459
- /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "Voc\xEA informa o endere\xE7o de entrega no checkout. Em breve ser\xE1 poss\xEDvel salvar endere\xE7os para reutilizar nas pr\xF3ximas compras." }),
12774
+ empty ? /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "Nenhum endere\xE7o salvo ainda. Ele fica salvo quando voc\xEA informa onde receber no card\xE1pio ou no checkout." }) : /* @__PURE__ */ jsxs("ul", { className: "mt-4 space-y-2", children: [
12775
+ account.map((a) => /* @__PURE__ */ jsxs("li", { className: "rounded-lg border p-3 text-sm", children: [
12776
+ /* @__PURE__ */ jsx("span", { className: "block font-medium", children: a.label ?? `${a.street}${a.number ? `, ${a.number}` : ""}` }),
12777
+ /* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: [a.label ? `${a.street}${a.number ? `, ${a.number}` : ""}` : null, a.complement, a.district, a.city].filter(Boolean).join(" \xB7 ") })
12778
+ ] }, `account-${a.id}`)),
12779
+ browser.map((a) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2 rounded-lg border p-3 text-sm", children: [
12780
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
12781
+ /* @__PURE__ */ jsx("span", { className: "block font-medium", children: a.label ?? `${a.street}, ${a.number}` }),
12782
+ /* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: [a.label ? `${a.street}, ${a.number}` : null, a.complement, a.district, a.city].filter(Boolean).join(" \xB7 ") }),
12783
+ /* @__PURE__ */ jsx("span", { className: "mt-0.5 block text-[11px] text-muted-foreground", children: "Salvo neste aparelho" })
12784
+ ] }),
12785
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => removeAddress(a.id), className: "text-xs font-semibold text-destructive", children: "Remover" })
12786
+ ] }, a.id))
12787
+ ] }),
12460
12788
  /* @__PURE__ */ jsx(Link, { to: config.catalogPath, className: "mt-4 inline-block text-sm font-semibold text-primary underline", children: "Continuar comprando" })
12461
12789
  ] });
12462
12790
  }
@@ -14194,5 +14522,5 @@ ${formatErrors(report.errors)}`;
14194
14522
  }
14195
14523
 
14196
14524
  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, applyDeliveryPolicy, applyStoreSettings, bannerPlaceholder, blockInstanceId, buildEnquiryFromForm, checkPageBlocks, collectDataNeeds, collectOrderMetadata, contentPagePath, createStorefront, createStorefrontApp, currentStaticRenderPass, defaultPageBlocks, entityListBlockMeta, establishCustomerSession, exportStore, formatMoney, formatProductOptionSelection, getCartLineAnnotations, getCheckoutFieldContributions, getCustomerAuthAdapter, getProductCardBadges, getProductOptionGroups, hydrateStoreDocument, hydratedEntriesFor, 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 };
14197
- //# sourceMappingURL=chunk-XH6JP63K.js.map
14198
- //# sourceMappingURL=chunk-XH6JP63K.js.map
14525
+ //# sourceMappingURL=chunk-HTVC74PL.js.map
14526
+ //# sourceMappingURL=chunk-HTVC74PL.js.map