@fayz-ai/storefront 0.60.0 → 0.63.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.
@@ -7,7 +7,7 @@ import { setShopCarrierQuotesResolver, setShopAccessTokenResolver, setShopShippi
7
7
  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';
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
- import { isStorageImageUrl, imageVariantUrl, imageSrcSet, IMAGE_SRCSET_WIDTHS, validateDiscount, documentDigits, isChargeableProvider, supportsCard, formatDocument, gatewayLabel, isValidDocument } from '@fayz-ai/shop';
10
+ import { isStorageImageUrl, imageVariantUrl, imageSrcSet, IMAGE_SRCSET_WIDTHS, validateDiscount, documentDigits, isChargeableProvider, supportsCard, formatDocument, gatewayLabel, isValidDocument, isValidCpf } from '@fayz-ai/shop';
11
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';
@@ -5193,7 +5193,7 @@ function buildEnquiryFromForm(fields, values, subject, sourceUrl) {
5193
5193
  const phoneField = fields.find((f2) => f2.type === "phone");
5194
5194
  const nameField = fields.find((f2) => f2.id === "name") ?? fields.find((f2) => (f2.type ?? "text") === "text" && f2 !== emailField && f2 !== phoneField);
5195
5195
  const identity = /* @__PURE__ */ new Set([emailField?.id, phoneField?.id, nameField?.id]);
5196
- 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}`);
5196
+ 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}`);
5197
5197
  return {
5198
5198
  productName: subject,
5199
5199
  customerName: nameField && values[nameField.id]?.trim() || "Visitante",
@@ -5207,31 +5207,31 @@ function buildEnquiryFromForm(fields, values, subject, sourceUrl) {
5207
5207
  }
5208
5208
  var INPUT_CLASS = "w-full border bg-background px-3 py-2 text-sm outline-none focus:border-primary";
5209
5209
  function Field({
5210
- field,
5210
+ field: field2,
5211
5211
  value,
5212
5212
  onChange
5213
5213
  }) {
5214
5214
  const common = {
5215
- "data-testid": TID.formBlockField(field.id),
5216
- required: field.required,
5215
+ "data-testid": TID.formBlockField(field2.id),
5216
+ required: field2.required,
5217
5217
  value,
5218
- placeholder: field.placeholder,
5218
+ placeholder: field2.placeholder,
5219
5219
  className: INPUT_CLASS,
5220
5220
  style: { borderRadius: "var(--sf-radius-input)" }
5221
5221
  };
5222
- return /* @__PURE__ */ jsxs("label", { className: `space-y-1.5 text-sm font-medium ${field.type === "textarea" ? "block" : ""}`, children: [
5222
+ return /* @__PURE__ */ jsxs("label", { className: `space-y-1.5 text-sm font-medium ${field2.type === "textarea" ? "block" : ""}`, children: [
5223
5223
  /* @__PURE__ */ jsxs("span", { children: [
5224
- field.label,
5225
- field.required ? "" : " (opcional)"
5224
+ field2.label,
5225
+ field2.required ? "" : " (opcional)"
5226
5226
  ] }),
5227
- 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: [
5227
+ 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: [
5228
5228
  /* @__PURE__ */ jsx("option", { value: "", children: "\u2014" }),
5229
- (field.options ?? []).map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
5229
+ (field2.options ?? []).map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
5230
5230
  ] }) : /* @__PURE__ */ jsx(
5231
5231
  "input",
5232
5232
  {
5233
5233
  ...common,
5234
- type: field.type === "email" ? "email" : field.type === "phone" ? "tel" : "text",
5234
+ type: field2.type === "email" ? "email" : field2.type === "phone" ? "tel" : "text",
5235
5235
  onChange: (e) => onChange(e.target.value)
5236
5236
  }
5237
5237
  )
@@ -5278,14 +5278,14 @@ function FormBlock({
5278
5278
  subtitle && /* @__PURE__ */ jsx("p", { className: "mt-2 text-muted-foreground", children: subtitle })
5279
5279
  ] }),
5280
5280
  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: [
5281
- fields.map((field) => /* @__PURE__ */ jsx(
5281
+ fields.map((field2) => /* @__PURE__ */ jsx(
5282
5282
  Field,
5283
5283
  {
5284
- field,
5285
- value: values[field.id] ?? "",
5286
- onChange: (value) => setValues((prev) => ({ ...prev, [field.id]: value }))
5284
+ field: field2,
5285
+ value: values[field2.id] ?? "",
5286
+ onChange: (value) => setValues((prev) => ({ ...prev, [field2.id]: value }))
5287
5287
  },
5288
- field.id
5288
+ field2.id
5289
5289
  )),
5290
5290
  /* @__PURE__ */ jsx(
5291
5291
  "button",
@@ -5379,9 +5379,9 @@ var formBlockMeta = {
5379
5379
  // A form is a destination, not merchandising — editorial pages and the home.
5380
5380
  enabledOn: ["home", "catalog", "collection", "content"]
5381
5381
  };
5382
- function fieldValue(field, value) {
5382
+ function fieldValue(field2, value) {
5383
5383
  if (value === null || value === void 0 || value === "") return null;
5384
- switch (field.type) {
5384
+ switch (field2.type) {
5385
5385
  case "image":
5386
5386
  return /* @__PURE__ */ jsx(
5387
5387
  "img",
@@ -5420,12 +5420,12 @@ function EntityCard({ declaration, record, fields }) {
5420
5420
  children: [
5421
5421
  typeof title === "string" && title && /* @__PURE__ */ jsx("h3", { className: "sf-heading mb-2 text-lg font-semibold", children: title }),
5422
5422
  /* @__PURE__ */ jsx("dl", { className: "space-y-1.5", children: detailFields.map((name) => {
5423
- const field = declaration.fields[name];
5424
- if (!field) return null;
5425
- const rendered = fieldValue(field, record.data[name]);
5423
+ const field2 = declaration.fields[name];
5424
+ if (!field2) return null;
5425
+ const rendered = fieldValue(field2, record.data[name]);
5426
5426
  if (rendered === null) return null;
5427
5427
  return /* @__PURE__ */ jsxs("div", { children: [
5428
- /* @__PURE__ */ jsx("dt", { className: "text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: field.label ?? name }),
5428
+ /* @__PURE__ */ jsx("dt", { className: "text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: field2.label ?? name }),
5429
5429
  /* @__PURE__ */ jsx("dd", { className: "text-sm text-foreground/90", children: rendered })
5430
5430
  ] }, name);
5431
5431
  }) })
@@ -6962,8 +6962,8 @@ function themeToCss(theme, options = {}) {
6962
6962
  if (theme.font.display) lines.push(`--sf-font-display: '${theme.font.display}', ${fallback};`);
6963
6963
  if (theme.font.serif) lines.push(`--sf-font-serif: '${theme.font.serif}', serif;`);
6964
6964
  }
6965
- for (const [field, prefix] of Object.entries(THEME_SCALE_VAR_PREFIX)) {
6966
- for (const [key, value] of Object.entries(theme[field] ?? {})) {
6965
+ for (const [field2, prefix] of Object.entries(THEME_SCALE_VAR_PREFIX)) {
6966
+ for (const [key, value] of Object.entries(theme[field2] ?? {})) {
6967
6967
  lines.push(`${prefix}-${key}: ${value};`);
6968
6968
  }
6969
6969
  }
@@ -9835,9 +9835,9 @@ function CheckoutPage() {
9835
9835
  function fail(message, testId) {
9836
9836
  setError(message);
9837
9837
  if (testId) {
9838
- const field = document.querySelector(`[data-testid="${testId}"]`);
9839
- field?.scrollIntoView({ block: "center", behavior: prefersReducedMotion() ? "auto" : "smooth" });
9840
- field?.focus({ preventScroll: true });
9838
+ const field2 = document.querySelector(`[data-testid="${testId}"]`);
9839
+ field2?.scrollIntoView({ block: "center", behavior: prefersReducedMotion() ? "auto" : "smooth" });
9840
+ field2?.focus({ preventScroll: true });
9841
9841
  }
9842
9842
  return false;
9843
9843
  }
@@ -12051,9 +12051,9 @@ var FINANCIAL = {
12051
12051
  voided: { label: "Cancelado", tone: "negative" }
12052
12052
  };
12053
12053
  var TONE_CLASS = {
12054
- positive: "bg-emerald-100 text-emerald-800",
12055
- pending: "bg-amber-100 text-amber-800",
12056
- negative: "bg-rose-100 text-rose-800"
12054
+ positive: "bg-emerald-500/15 text-emerald-600 ring-1 ring-inset ring-emerald-500/30",
12055
+ pending: "bg-amber-500/15 text-amber-600 ring-1 ring-inset ring-amber-500/30",
12056
+ negative: "bg-destructive/15 text-destructive ring-1 ring-inset ring-destructive/30"
12057
12057
  };
12058
12058
  function financialStatusBadge(status) {
12059
12059
  const entry = FINANCIAL[status] ?? { label: status, tone: "pending" };
@@ -12081,7 +12081,7 @@ function deliverySteps(order) {
12081
12081
  received,
12082
12082
  {
12083
12083
  id: "closed",
12084
- label: stage === "rejected" ? "Pedido n\xE3o aceito" : "Pedido cancelado",
12084
+ label: stage === "rejected" ? "Pedido recusado" : "Pedido cancelado",
12085
12085
  description: [order.rejectReason, refunded ? "Valor estornado" : null].filter(Boolean).join(" \xB7 ") || "A loja cancelou este pedido",
12086
12086
  state: "cancelled",
12087
12087
  icon: XCircle
@@ -12113,9 +12113,16 @@ function orderTrackingSteps(order) {
12113
12113
  icon: Check
12114
12114
  };
12115
12115
  if (order.status === "cancelled" || order.financialStatus === "voided") {
12116
+ const refunded = isRefunded(order.financialStatus);
12116
12117
  return [
12117
12118
  received,
12118
- { id: "payment", label: "Pedido cancelado", description: "Este pedido foi cancelado", state: "cancelled", icon: XCircle }
12119
+ {
12120
+ id: "payment",
12121
+ label: "Pedido cancelado",
12122
+ description: [order.rejectReason, refunded ? "Valor estornado" : null].filter(Boolean).join(" \xB7 ") || "Este pedido foi cancelado",
12123
+ state: "cancelled",
12124
+ icon: XCircle
12125
+ }
12119
12126
  ];
12120
12127
  }
12121
12128
  if (isRefunded(order.financialStatus)) {
@@ -12186,7 +12193,7 @@ function OrderTrackingTimeline({ order, compact: compact2 = false }) {
12186
12193
  "data-state": step.state,
12187
12194
  className: [
12188
12195
  "relative min-w-0 rounded-xl border p-3",
12189
- cancelled ? "border-rose-200 bg-rose-50 text-rose-700" : active2 ? "border-primary/35 bg-primary/5" : "bg-muted/20 text-muted-foreground",
12196
+ cancelled ? "border-destructive/40 bg-destructive/10" : active2 ? "border-primary/35 bg-primary/5" : "bg-muted/20 text-muted-foreground",
12190
12197
  compact2 ? "text-xs" : "text-sm"
12191
12198
  ].join(" "),
12192
12199
  children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
@@ -12195,7 +12202,7 @@ function OrderTrackingTimeline({ order, compact: compact2 = false }) {
12195
12202
  {
12196
12203
  className: [
12197
12204
  "grid h-7 w-7 shrink-0 place-items-center rounded-full border",
12198
- cancelled ? "border-rose-300 bg-rose-500 text-white" : done ? "border-primary bg-primary text-primary-foreground" : current ? "border-primary bg-background text-primary" : "border-muted-foreground/30 bg-background"
12205
+ cancelled ? "border-destructive bg-destructive text-destructive-foreground" : done ? "border-primary bg-primary text-primary-foreground" : current ? "border-primary bg-background text-primary" : "border-muted-foreground/30 bg-background"
12199
12206
  ].join(" "),
12200
12207
  "aria-hidden": true,
12201
12208
  children: /* @__PURE__ */ jsx(Icon2, { className: "h-3.5 w-3.5" })
@@ -12458,7 +12465,7 @@ function OrderConfirmationPage({ orderId }) {
12458
12465
  /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: "Subtotal" }),
12459
12466
  /* @__PURE__ */ jsx("dd", { "data-price": order.subtotal.toFixed(2), children: money(order.subtotal) })
12460
12467
  ] }),
12461
- order.discountTotal > 0 && /* @__PURE__ */ jsxs("div", { className: "flex justify-between text-emerald-700", children: [
12468
+ order.discountTotal > 0 && /* @__PURE__ */ jsxs("div", { className: "flex justify-between text-emerald-600", children: [
12462
12469
  /* @__PURE__ */ jsxs("dt", { children: [
12463
12470
  "Desconto ",
12464
12471
  order.discountCode ? `(${order.discountCode})` : ""
@@ -12604,7 +12611,7 @@ function AuthForm() {
12604
12611
  style: { borderRadius: "var(--sf-radius-input)" }
12605
12612
  }
12606
12613
  ),
12607
- notice && /* @__PURE__ */ jsx("p", { "data-testid": TID.authNotice, className: "text-sm font-medium text-emerald-700", children: notice }),
12614
+ notice && /* @__PURE__ */ jsx("p", { "data-testid": TID.authNotice, className: "text-sm font-medium text-emerald-600", children: notice }),
12608
12615
  error && /* @__PURE__ */ jsx("p", { "data-testid": TID.authError, className: "text-sm text-destructive", children: error }),
12609
12616
  /* @__PURE__ */ jsx(
12610
12617
  "button",
@@ -12686,77 +12693,175 @@ function OrdersPanel() {
12686
12693
  order.id
12687
12694
  )) });
12688
12695
  }
12696
+ function maskPhone(raw) {
12697
+ const d = raw.replace(/\D/g, "").replace(/^55(?=\d{10,11}$)/, "").slice(0, 11);
12698
+ if (d.length <= 2) return d ? `(${d}` : "";
12699
+ if (d.length <= 6) return `(${d.slice(0, 2)}) ${d.slice(2)}`;
12700
+ const head = d.length === 11 ? 7 : 6;
12701
+ return `(${d.slice(0, 2)}) ${d.slice(2, head)}-${d.slice(head)}`;
12702
+ }
12703
+ function maskCpf(raw) {
12704
+ const d = raw.replace(/\D/g, "").slice(0, 11);
12705
+ return [d.slice(0, 3), d.slice(3, 6), d.slice(6, 9)].filter(Boolean).join(".") + (d.length > 9 ? `-${d.slice(9)}` : "");
12706
+ }
12707
+ var field = "mt-1 w-full rounded-lg border bg-background px-3 py-2.5 text-sm";
12689
12708
  function ProfilePanel() {
12690
12709
  const session = useSessionStore();
12710
+ const provider = getShopProvider();
12711
+ const supported = typeof provider.getMyProfile === "function" && typeof provider.saveMyProfile === "function";
12691
12712
  const [name, setName] = useState(session.name ?? "");
12713
+ const [phone, setPhone] = useState("");
12714
+ const [cpf, setCpf] = useState("");
12715
+ const [birthDate, setBirthDate] = useState("");
12716
+ const [loading, setLoading] = useState(supported);
12692
12717
  const [saving, setSaving] = useState(false);
12693
12718
  const [saved, setSaved] = useState(false);
12694
12719
  const [error, setError] = useState(null);
12720
+ React38.useEffect(() => {
12721
+ if (!supported) return;
12722
+ let cancelled = false;
12723
+ provider.getMyProfile().then((p) => {
12724
+ if (cancelled || !p) return;
12725
+ const full = [p.firstName, p.lastName].filter(Boolean).join(" ").trim();
12726
+ if (full) setName(full);
12727
+ setPhone(maskPhone(p.phone ?? ""));
12728
+ setCpf(maskCpf(p.document ?? ""));
12729
+ setBirthDate(p.birthDate ?? "");
12730
+ }).catch(() => {
12731
+ }).finally(() => {
12732
+ if (!cancelled) setLoading(false);
12733
+ });
12734
+ return () => {
12735
+ cancelled = true;
12736
+ };
12737
+ }, [supported]);
12738
+ const edit = (set) => (v) => {
12739
+ set(v);
12740
+ setSaved(false);
12741
+ setError(null);
12742
+ };
12695
12743
  async function save(e) {
12696
12744
  e.preventDefault();
12697
12745
  const trimmed = name.trim();
12698
- if (!trimmed) return;
12746
+ if (!trimmed) {
12747
+ setError("Informe seu nome.");
12748
+ return;
12749
+ }
12750
+ const phoneDigits = phone.replace(/\D/g, "");
12751
+ if (phoneDigits && phoneDigits.length !== 10 && phoneDigits.length !== 11) {
12752
+ setError("Celular inv\xE1lido: use o DDD e o n\xFAmero.");
12753
+ return;
12754
+ }
12755
+ const cpfDigits = cpf.replace(/\D/g, "");
12756
+ if (cpfDigits && !isValidCpf(cpfDigits)) {
12757
+ setError("CPF inv\xE1lido. Confira os n\xFAmeros.");
12758
+ return;
12759
+ }
12699
12760
  setSaving(true);
12700
12761
  setSaved(false);
12701
12762
  setError(null);
12702
12763
  try {
12703
- if (session.customerId) {
12704
- const parts = trimmed.split(/\s+/).filter(Boolean);
12705
- await getShopProvider().updateCustomer(session.customerId, {
12706
- firstName: parts[0] ?? trimmed,
12707
- lastName: parts.slice(1).join(" ")
12764
+ if (supported) {
12765
+ await provider.saveMyProfile({
12766
+ name: trimmed,
12767
+ phone: phoneDigits || null,
12768
+ document: cpfDigits || null,
12769
+ birthDate: birthDate || null
12708
12770
  });
12771
+ } else if (session.customerId) {
12772
+ const parts = trimmed.split(/\s+/).filter(Boolean);
12773
+ await provider.updateCustomer(session.customerId, { firstName: parts[0] ?? trimmed, lastName: parts.slice(1).join(" ") });
12709
12774
  }
12710
12775
  useSessionStore.setState({ name: trimmed });
12711
12776
  setSaved(true);
12712
- } catch {
12713
- setError("N\xE3o foi poss\xEDvel salvar seu nome agora. Tente novamente em instantes.");
12777
+ } catch (err) {
12778
+ setError(err instanceof Error && err.message ? err.message : "N\xE3o foi poss\xEDvel salvar agora. Tente novamente em instantes.");
12714
12779
  } finally {
12715
12780
  setSaving(false);
12716
12781
  }
12717
12782
  }
12718
- return /* @__PURE__ */ jsxs("form", { onSubmit: save, className: "max-w-md rounded-2xl border bg-card p-6", children: [
12783
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
12784
+ return /* @__PURE__ */ jsxs("form", { onSubmit: save, className: "max-w-md rounded-2xl border bg-card p-6", "data-testid": "account-profile", children: [
12719
12785
  /* @__PURE__ */ jsx("h2", { className: "sf-heading text-lg font-semibold", children: "Perfil" }),
12720
- /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Seus dados para os pr\xF3ximos checkouts." }),
12721
- /* @__PURE__ */ jsxs("label", { className: "mt-5 block text-sm font-medium", children: [
12722
- "Nome completo",
12723
- /* @__PURE__ */ jsx(
12724
- "input",
12725
- {
12726
- value: name,
12727
- onChange: (e) => {
12728
- setName(e.target.value);
12729
- setSaved(false);
12730
- },
12731
- className: "mt-1 w-full rounded-lg border bg-background px-3 py-2.5 text-sm",
12732
- placeholder: "Seu nome"
12733
- }
12734
- )
12735
- ] }),
12736
- /* @__PURE__ */ jsxs("label", { className: "mt-4 block text-sm font-medium", children: [
12737
- "E-mail",
12738
- /* @__PURE__ */ jsx(
12739
- "input",
12740
- {
12741
- value: session.email ?? "",
12742
- readOnly: true,
12743
- className: "mt-1 w-full cursor-not-allowed rounded-lg border bg-muted/40 px-3 py-2.5 text-sm text-muted-foreground"
12744
- }
12745
- )
12786
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Seus dados para os pr\xF3ximos pedidos." }),
12787
+ /* @__PURE__ */ jsxs("fieldset", { disabled: loading || saving, className: "contents", children: [
12788
+ /* @__PURE__ */ jsxs("label", { className: "mt-5 block text-sm font-medium", children: [
12789
+ "Nome completo",
12790
+ /* @__PURE__ */ jsx("input", { value: name, onChange: (e) => edit(setName)(e.target.value), className: field, placeholder: "Seu nome", autoComplete: "name" })
12791
+ ] }),
12792
+ /* @__PURE__ */ jsxs("label", { className: "mt-4 block text-sm font-medium", children: [
12793
+ "E-mail",
12794
+ /* @__PURE__ */ jsx(
12795
+ "input",
12796
+ {
12797
+ value: session.email ?? "",
12798
+ readOnly: true,
12799
+ className: "mt-1 w-full cursor-not-allowed rounded-lg border bg-muted/40 px-3 py-2.5 text-sm text-muted-foreground"
12800
+ }
12801
+ )
12802
+ ] }),
12803
+ /* @__PURE__ */ jsxs("label", { className: "mt-4 block text-sm font-medium", children: [
12804
+ "Celular",
12805
+ /* @__PURE__ */ jsx(
12806
+ "input",
12807
+ {
12808
+ value: phone,
12809
+ onChange: (e) => edit(setPhone)(maskPhone(e.target.value)),
12810
+ className: field,
12811
+ placeholder: "(21) 99999-9999",
12812
+ inputMode: "tel",
12813
+ autoComplete: "tel-national",
12814
+ "data-testid": "profile-phone"
12815
+ }
12816
+ )
12817
+ ] }),
12818
+ /* @__PURE__ */ jsxs("div", { className: "mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2", children: [
12819
+ /* @__PURE__ */ jsxs("label", { className: "block text-sm font-medium", children: [
12820
+ "CPF",
12821
+ /* @__PURE__ */ jsx(
12822
+ "input",
12823
+ {
12824
+ value: cpf,
12825
+ onChange: (e) => edit(setCpf)(maskCpf(e.target.value)),
12826
+ className: field,
12827
+ placeholder: "000.000.000-00",
12828
+ inputMode: "numeric",
12829
+ "data-testid": "profile-cpf"
12830
+ }
12831
+ )
12832
+ ] }),
12833
+ /* @__PURE__ */ jsxs("label", { className: "block text-sm font-medium", children: [
12834
+ "Data de nascimento",
12835
+ /* @__PURE__ */ jsx(
12836
+ "input",
12837
+ {
12838
+ type: "date",
12839
+ value: birthDate,
12840
+ max: today,
12841
+ min: "1900-01-01",
12842
+ onChange: (e) => edit(setBirthDate)(e.target.value),
12843
+ className: `${field} [color-scheme:light] dark:[color-scheme:dark]`,
12844
+ autoComplete: "bday",
12845
+ "data-testid": "profile-birth-date"
12846
+ }
12847
+ )
12848
+ ] })
12849
+ ] })
12746
12850
  ] }),
12747
12851
  /* @__PURE__ */ jsxs("div", { className: "mt-5 flex items-center gap-3", children: [
12748
12852
  /* @__PURE__ */ jsx(
12749
12853
  "button",
12750
12854
  {
12751
12855
  type: "submit",
12752
- disabled: saving,
12856
+ disabled: saving || loading,
12753
12857
  className: "sf-cta rounded-lg bg-primary px-5 py-2.5 text-sm font-semibold text-primary-foreground disabled:opacity-60",
12858
+ "data-testid": "profile-save",
12754
12859
  children: saving ? "Salvando\u2026" : "Salvar"
12755
12860
  }
12756
12861
  ),
12757
- saved && /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-emerald-700", children: "Salvo" })
12862
+ saved && /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-emerald-600", children: "Salvo" })
12758
12863
  ] }),
12759
- error && /* @__PURE__ */ jsx("p", { className: "mt-3 text-sm text-destructive", children: error })
12864
+ error && /* @__PURE__ */ jsx("p", { role: "alert", className: "mt-3 text-sm text-destructive", children: error })
12760
12865
  ] });
12761
12866
  }
12762
12867
  function AddressesPanel() {
@@ -13389,7 +13494,7 @@ function sectionToJsonSchema(name) {
13389
13494
  }
13390
13495
  };
13391
13496
  const required = ["version"];
13392
- for (const [field, fieldSpec] of Object.entries(spec.fields)) {
13497
+ for (const [field2, fieldSpec] of Object.entries(spec.fields)) {
13393
13498
  const node = { type: fieldSpec.type, description: fieldSpec.description };
13394
13499
  if (fieldSpec.enum) node.enum = [...fieldSpec.enum];
13395
13500
  if (fieldSpec.deprecated) {
@@ -13398,8 +13503,8 @@ function sectionToJsonSchema(name) {
13398
13503
  node["x-fayz-replacement"] = fieldSpec.deprecated.replacement;
13399
13504
  node["x-fayz-removed-at-section-version"] = fieldSpec.deprecated.removedAtVersion;
13400
13505
  }
13401
- properties[field] = node;
13402
- if (fieldSpec.required) required.push(field);
13506
+ properties[field2] = node;
13507
+ if (fieldSpec.required) required.push(field2);
13403
13508
  }
13404
13509
  return {
13405
13510
  type: "object",
@@ -13694,22 +13799,22 @@ function collectSettingIds(settings) {
13694
13799
  }
13695
13800
  var TOKEN_KEY = /^[a-zA-Z][a-zA-Z0-9-]*$/;
13696
13801
  function validateTheme(errors, section) {
13697
- for (const field of THEME_SCALE_FIELDS) {
13698
- const scale = section[field];
13802
+ for (const field2 of THEME_SCALE_FIELDS) {
13803
+ const scale = section[field2];
13699
13804
  if (scale === void 0) continue;
13700
13805
  if (!isRecord(scale)) continue;
13701
13806
  for (const [key, value] of Object.entries(scale)) {
13702
- const path = `theme.${field}.${key}`;
13807
+ const path = `theme.${field2}.${key}`;
13703
13808
  if (!TOKEN_KEY.test(key)) {
13704
13809
  push(
13705
13810
  errors,
13706
13811
  path,
13707
13812
  "invalid-token-key",
13708
- `"${key}" cannot become the CSS custom property ${THEME_SCALE_VAR_PREFIX[field]}-${key} \u2014 token keys match ${TOKEN_KEY}`
13813
+ `"${key}" cannot become the CSS custom property ${THEME_SCALE_VAR_PREFIX[field2]}-${key} \u2014 token keys match ${TOKEN_KEY}`
13709
13814
  );
13710
13815
  }
13711
13816
  if (typeof value !== "string") {
13712
- push(errors, path, "invalid-value", `a ${field} token is a CSS value string, got ${typeof value}`);
13817
+ push(errors, path, "invalid-value", `a ${field2} token is a CSS value string, got ${typeof value}`);
13713
13818
  }
13714
13819
  }
13715
13820
  }
@@ -13767,9 +13872,9 @@ function validateSectionEnvelope(errors, name, section) {
13767
13872
  );
13768
13873
  }
13769
13874
  }
13770
- for (const [field, fieldSpec] of Object.entries(spec.fields)) {
13771
- if (fieldSpec.required && section[field] === void 0) {
13772
- push(errors, `${name}.${field}`, "missing-field", `section "${name}" requires "${field}"`);
13875
+ for (const [field2, fieldSpec] of Object.entries(spec.fields)) {
13876
+ if (fieldSpec.required && section[field2] === void 0) {
13877
+ push(errors, `${name}.${field2}`, "missing-field", `section "${name}" requires "${field2}"`);
13773
13878
  }
13774
13879
  }
13775
13880
  return true;
@@ -13931,7 +14036,7 @@ function validateEntitiesSection(errors, section) {
13931
14036
  }
13932
14037
  const fields = declaration.fields;
13933
14038
  const fieldNames = Object.keys(fields);
13934
- for (const [name, field] of Object.entries(fields)) {
14039
+ for (const [name, field2] of Object.entries(fields)) {
13935
14040
  const fieldPath = `${path}.fields.${name}`;
13936
14041
  if (!ENTITY_FIELD_RE.test(name)) {
13937
14042
  push(errors, fieldPath, "invalid-value", `"${name}" is not a valid field name \u2014 fields are snake_case`);
@@ -13940,19 +14045,19 @@ function validateEntitiesSection(errors, section) {
13940
14045
  push(errors, fieldPath, "invalid-value", `"${name}" is a structural record column`, RESERVED_ENTITY_FIELDS);
13941
14046
  continue;
13942
14047
  }
13943
- if (!isRecord(field) || typeof field.type !== "string") {
14048
+ if (!isRecord(field2) || typeof field2.type !== "string") {
13944
14049
  push(errors, fieldPath, "invalid-value", "a field is {type: <entity field type>, label?, required?, \u2026}");
13945
14050
  continue;
13946
14051
  }
13947
- if (!ENTITY_FIELD_TYPES.includes(field.type)) {
13948
- push(errors, `${fieldPath}.type`, "unknown-entity-field-type", `"${field.type}" is not an entity field type`, ENTITY_FIELD_TYPES);
14052
+ if (!ENTITY_FIELD_TYPES.includes(field2.type)) {
14053
+ push(errors, `${fieldPath}.type`, "unknown-entity-field-type", `"${field2.type}" is not an entity field type`, ENTITY_FIELD_TYPES);
13949
14054
  continue;
13950
14055
  }
13951
- if (field.type === "ref") {
13952
- if (typeof field.entity !== "string" || !field.entity) {
14056
+ if (field2.type === "ref") {
14057
+ if (typeof field2.entity !== "string" || !field2.entity) {
13953
14058
  push(errors, fieldPath, "invalid-value", `a ref field names its target: {type: 'ref', entity: '<key>'}`);
13954
14059
  } else {
13955
- checkEntityRef(errors, `${fieldPath}.entity`, field.entity);
14060
+ checkEntityRef(errors, `${fieldPath}.entity`, field2.entity);
13956
14061
  }
13957
14062
  }
13958
14063
  }
@@ -14083,10 +14188,10 @@ function validatePromotionsSection(errors, section) {
14083
14188
  if (method.allocation !== void 0 && !APPLICATION_METHOD_ALLOCATIONS.includes(method.allocation)) {
14084
14189
  push(errors, `${methodPath}.allocation`, "invalid-value", `"${String(method.allocation)}" is not an allocation`, APPLICATION_METHOD_ALLOCATIONS);
14085
14190
  }
14086
- for (const field of ["maxQuantity", "applyToQuantity", "buyRulesMinQuantity"]) {
14087
- const value = method[field];
14191
+ for (const field2 of ["maxQuantity", "applyToQuantity", "buyRulesMinQuantity"]) {
14192
+ const value = method[field2];
14088
14193
  if (value !== void 0 && value !== null && (typeof value !== "number" || value < 1)) {
14089
- push(errors, `${methodPath}.${field}`, "invalid-value", `${field} is a positive integer when set`);
14194
+ push(errors, `${methodPath}.${field2}`, "invalid-value", `${field2} is a positive integer when set`);
14090
14195
  }
14091
14196
  }
14092
14197
  validateRuleList(errors, `${methodPath}.targetRules`, method.targetRules);
@@ -14103,8 +14208,8 @@ function validateHandleRef(errors, path, name) {
14103
14208
  }
14104
14209
  }
14105
14210
  function validateCode(errors, section) {
14106
- for (const field of ["logo", "provider", "auth", "footerCredit"]) {
14107
- if (section[field] !== void 0) validateHandleRef(errors, `code.${field}`, section[field]);
14211
+ for (const field2 of ["logo", "provider", "auth", "footerCredit"]) {
14212
+ if (section[field2] !== void 0) validateHandleRef(errors, `code.${field2}`, section[field2]);
14108
14213
  }
14109
14214
  const components = section.components;
14110
14215
  if (isRecord(components)) {
@@ -14522,5 +14627,5 @@ ${formatErrors(report.errors)}`;
14522
14627
  }
14523
14628
 
14524
14629
  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 };
14525
- //# sourceMappingURL=chunk-HTVC74PL.js.map
14526
- //# sourceMappingURL=chunk-HTVC74PL.js.map
14630
+ //# sourceMappingURL=chunk-WFJH7SUO.js.map
14631
+ //# sourceMappingURL=chunk-WFJH7SUO.js.map