@fayz-ai/storefront 0.77.0 → 0.77.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analytics/StorefrontAnalytics.d.ts +22 -0
- package/dist/analytics/StorefrontAnalytics.d.ts.map +1 -0
- package/dist/analytics/bus.d.ts +32 -0
- package/dist/analytics/bus.d.ts.map +1 -0
- package/dist/analytics/edge.d.ts +18 -0
- package/dist/analytics/edge.d.ts.map +1 -0
- package/dist/analytics/identity.d.ts +10 -0
- package/dist/analytics/identity.d.ts.map +1 -0
- package/dist/analytics/index.d.ts +5 -0
- package/dist/analytics/index.d.ts.map +1 -0
- package/dist/analytics/posthog.d.ts +31 -0
- package/dist/analytics/posthog.d.ts.map +1 -0
- package/dist/app/createStorefrontApp.d.ts.map +1 -1
- package/dist/app/router.d.ts +1 -1
- package/dist/{chunk-AUARAE26.js → chunk-3XECLBVJ.js} +487 -254
- package/dist/chunk-3XECLBVJ.js.map +1 -0
- package/dist/document/config.d.ts +6 -0
- package/dist/document/config.d.ts.map +1 -1
- package/dist/edge.d.ts +2 -0
- package/dist/edge.d.ts.map +1 -0
- package/dist/edge.js +27 -0
- package/dist/edge.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/render.js +1 -1
- package/dist/ui.d.ts +1 -1
- package/dist/ui.d.ts.map +1 -1
- package/dist/views/CheckoutPage.d.ts.map +1 -1
- package/dist/views/MenuPage.d.ts.map +1 -1
- package/dist/views/ProductDetailPage.d.ts.map +1 -1
- package/package.json +8 -3
- package/dist/chunk-AUARAE26.js.map +0 -1
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { create } from 'zustand';
|
|
2
2
|
import { persist } from 'zustand/middleware';
|
|
3
|
+
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';
|
|
4
|
+
import { getShopProvider, setShopProvider } from '@fayz-ai/shop/runtime';
|
|
5
|
+
import * as React39 from 'react';
|
|
6
|
+
import React39__default, { createContext, useContext, useEffect, useRef, useState, useSyncExternalStore, useMemo, useCallback } from 'react';
|
|
3
7
|
import { createMockAuthAdapter } from '@fayz-ai/auth';
|
|
4
8
|
import { createAuthRuntime } from '@fayz-ai/auth/lib/runtime';
|
|
5
|
-
import { getShopProvider, setShopProvider } from '@fayz-ai/shop/runtime';
|
|
6
9
|
import { setShopCarrierQuotesResolver, setShopAccessTokenResolver, setShopShippingItemsResolver } from '@fayz-ai/sdk/shop';
|
|
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
|
-
import React38, { createContext, useContext, useEffect, useRef, useState, useSyncExternalStore, useMemo, useCallback } from 'react';
|
|
9
10
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
10
11
|
import { isStorageImageUrl, imageVariantUrl, imageSrcSet, IMAGE_SRCSET_WIDTHS, validateDiscount, documentDigits, isChargeableProvider, supportsCard, formatDocument, isValidDocument, gatewayLabel, isValidCpf } from '@fayz-ai/shop';
|
|
11
12
|
import { ChevronLeft, ChevronRight, ShoppingBag, X, Minus, Plus, Send, MessageCircle, Mail, Truck, RefreshCcw, ShieldCheck, ChevronDown, Check, Search, Menu, Trash2, MapPin, Lock, CreditCard, UserRound, Store, Bike, Clock, Pencil, Star, Phone, User, UserCircle, Package, LogOut, QrCode, Copy, XCircle, RotateCcw, PackageCheck, ChefHat, Info, AlertCircle } from 'lucide-react';
|
|
@@ -13,164 +14,7 @@ import { getLucideIcon } from '@fayz-ai/ui/icons';
|
|
|
13
14
|
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
15
|
import { createMockShopProvider } from '@fayz-ai/shop/mock';
|
|
15
16
|
|
|
16
|
-
// src/stores/
|
|
17
|
-
var useSessionStore = create()(
|
|
18
|
-
persist(
|
|
19
|
-
(set) => ({
|
|
20
|
-
customerId: null,
|
|
21
|
-
email: null,
|
|
22
|
-
name: null,
|
|
23
|
-
setSession: ({ customerId, email, name }) => set({ customerId, email, name: name ?? null }),
|
|
24
|
-
signOut: () => set({ customerId: null, email: null, name: null })
|
|
25
|
-
}),
|
|
26
|
-
{ name: "fayz.storefront.session.v1" }
|
|
27
|
-
)
|
|
28
|
-
);
|
|
29
|
-
var EmailConfirmationRequiredError = class extends Error {
|
|
30
|
-
constructor(email) {
|
|
31
|
-
super("Cadastro realizado. Confirme seu e-mail para continuar.");
|
|
32
|
-
this.name = "EmailConfirmationRequiredError";
|
|
33
|
-
this.email = email;
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
var _adapter = null;
|
|
37
|
-
function isAuthAdapter(value) {
|
|
38
|
-
return Boolean(
|
|
39
|
-
value && typeof value === "object" && "getSession" in value && "signIn" in value && "signOut" in value
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
function normalizeAuthConfig(configured) {
|
|
43
|
-
if (!configured) return {};
|
|
44
|
-
if (typeof configured === "string" || isAuthAdapter(configured)) return { adapter: configured };
|
|
45
|
-
return configured;
|
|
46
|
-
}
|
|
47
|
-
function resolveAuthAdapter(configured, fallback) {
|
|
48
|
-
const config = normalizeAuthConfig(configured);
|
|
49
|
-
return createAuthRuntime({
|
|
50
|
-
provider: config.provider ?? config.adapter ?? (fallback?.supabaseUrl ? "supabase" : "mock"),
|
|
51
|
-
adapter: config.adapter,
|
|
52
|
-
routes: config.routes,
|
|
53
|
-
requireAuth: false,
|
|
54
|
-
supabase: {
|
|
55
|
-
url: config.supabase?.url ?? fallback?.supabaseUrl,
|
|
56
|
-
anonKey: config.supabase?.anonKey ?? fallback?.supabaseAnonKey,
|
|
57
|
-
client: config.supabase?.client,
|
|
58
|
-
callbackUrl: config.supabase?.callbackUrl,
|
|
59
|
-
resetPasswordUrl: config.supabase?.resetPasswordUrl
|
|
60
|
-
}
|
|
61
|
-
}).adapter;
|
|
62
|
-
}
|
|
63
|
-
var _accessToken = null;
|
|
64
|
-
var _hadAuthUser = false;
|
|
65
|
-
async function syncAccessToken(adapter) {
|
|
66
|
-
try {
|
|
67
|
-
const existing = await adapter.getSession();
|
|
68
|
-
_accessToken = existing?.session.accessToken ?? null;
|
|
69
|
-
} catch {
|
|
70
|
-
_accessToken = null;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
function initCustomerAuth(adapter) {
|
|
74
|
-
_adapter = adapter;
|
|
75
|
-
setShopAccessTokenResolver(() => _accessToken);
|
|
76
|
-
adapter.getSession().then((existing) => {
|
|
77
|
-
_accessToken = existing?.session.accessToken ?? null;
|
|
78
|
-
if (!existing) return;
|
|
79
|
-
_hadAuthUser = true;
|
|
80
|
-
void linkCustomer(existing.user).catch(() => {
|
|
81
|
-
});
|
|
82
|
-
}).catch(() => {
|
|
83
|
-
});
|
|
84
|
-
adapter.onAuthStateChange((user) => {
|
|
85
|
-
if (!user) {
|
|
86
|
-
_accessToken = null;
|
|
87
|
-
if (_hadAuthUser) {
|
|
88
|
-
_hadAuthUser = false;
|
|
89
|
-
useSessionStore.getState().signOut();
|
|
90
|
-
}
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
_hadAuthUser = true;
|
|
94
|
-
const linked = useSessionStore.getState();
|
|
95
|
-
const needsLink = !linked.customerId || (linked.email ?? "").toLowerCase() !== (user.email ?? "").toLowerCase();
|
|
96
|
-
void syncAccessToken(adapter).then(() => {
|
|
97
|
-
if (needsLink && user.email) return linkCustomer(user).then(() => void 0);
|
|
98
|
-
}).catch(() => {
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
function hasCustomerAuth() {
|
|
103
|
-
return _hadAuthUser;
|
|
104
|
-
}
|
|
105
|
-
async function relinkCustomer() {
|
|
106
|
-
if (!_hadAuthUser) return null;
|
|
107
|
-
const existing = await getCustomerAuthAdapter().getSession().catch(() => null);
|
|
108
|
-
if (!existing?.user.email) return null;
|
|
109
|
-
const customer = await resolveShopCustomer(existing.user.email.trim().toLowerCase(), existing.user.fullName ?? "");
|
|
110
|
-
const store = useSessionStore.getState();
|
|
111
|
-
store.setSession({ customerId: customer.id, email: existing.user.email.trim().toLowerCase(), name: store.name });
|
|
112
|
-
return { customerId: customer.id, phone: customer.phone ?? null, document: customer.document ?? null };
|
|
113
|
-
}
|
|
114
|
-
function getCustomerAuthAdapter() {
|
|
115
|
-
if (!_adapter) _adapter = createMockAuthAdapter();
|
|
116
|
-
return _adapter;
|
|
117
|
-
}
|
|
118
|
-
async function resolveShopCustomer(email, name) {
|
|
119
|
-
const provider = getShopProvider();
|
|
120
|
-
if (provider.resolveCustomer) return provider.resolveCustomer({ email, name });
|
|
121
|
-
const matches = await provider.listCustomers({ search: email, limit: 10 });
|
|
122
|
-
const existing = matches.find((c) => (c.email ?? "").toLowerCase() === email);
|
|
123
|
-
if (existing) return existing;
|
|
124
|
-
const parts = name.trim().split(/\s+/).filter(Boolean);
|
|
125
|
-
return provider.createCustomer({
|
|
126
|
-
firstName: parts[0] ?? email.split("@")[0] ?? "Cliente",
|
|
127
|
-
lastName: parts.slice(1).join(" "),
|
|
128
|
-
email
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
async function linkCustomer(user, fullName) {
|
|
132
|
-
const email = (user.email ?? "").trim().toLowerCase();
|
|
133
|
-
const name = fullName ?? user.fullName ?? "";
|
|
134
|
-
const customer = await resolveShopCustomer(email, name);
|
|
135
|
-
useSessionStore.getState().setSession({
|
|
136
|
-
customerId: customer.id,
|
|
137
|
-
email,
|
|
138
|
-
name: name || `${customer.firstName} ${customer.lastName}`.trim()
|
|
139
|
-
});
|
|
140
|
-
return { customerId: customer.id };
|
|
141
|
-
}
|
|
142
|
-
async function establishCustomerSession(email, opts) {
|
|
143
|
-
const normalized = email.trim().toLowerCase();
|
|
144
|
-
if (opts?.password) {
|
|
145
|
-
const adapter = getCustomerAuthAdapter();
|
|
146
|
-
const session = await adapter.signIn(normalized, opts.password);
|
|
147
|
-
_accessToken = session.accessToken ?? null;
|
|
148
|
-
_hadAuthUser = true;
|
|
149
|
-
return linkCustomer(session.user.email ? session.user : { ...session.user, email: normalized }, opts.name);
|
|
150
|
-
}
|
|
151
|
-
return linkCustomer({ email: normalized }, opts?.name);
|
|
152
|
-
}
|
|
153
|
-
function signInByEmail(email, name) {
|
|
154
|
-
return establishCustomerSession(email, { name });
|
|
155
|
-
}
|
|
156
|
-
async function signUpCustomer(email, password, name) {
|
|
157
|
-
const adapter = getCustomerAuthAdapter();
|
|
158
|
-
const normalized = email.trim().toLowerCase();
|
|
159
|
-
const session = await adapter.signUp(normalized, password, name);
|
|
160
|
-
if (!session.accessToken) throw new EmailConfirmationRequiredError(normalized);
|
|
161
|
-
_accessToken = session.accessToken;
|
|
162
|
-
_hadAuthUser = true;
|
|
163
|
-
return linkCustomer(session.user.email ? session.user : { ...session.user, email: normalized }, name);
|
|
164
|
-
}
|
|
165
|
-
async function signOutCustomer() {
|
|
166
|
-
try {
|
|
167
|
-
await getCustomerAuthAdapter().signOut();
|
|
168
|
-
} finally {
|
|
169
|
-
_accessToken = null;
|
|
170
|
-
_hadAuthUser = false;
|
|
171
|
-
useSessionStore.getState().signOut();
|
|
172
|
-
}
|
|
173
|
-
}
|
|
17
|
+
// src/stores/market.store.ts
|
|
174
18
|
var useMarketStore = create()((set) => ({
|
|
175
19
|
markets: [],
|
|
176
20
|
active: null,
|
|
@@ -607,6 +451,339 @@ var selectShipping = (s2, cfg) => {
|
|
|
607
451
|
};
|
|
608
452
|
var selectTotal = (s2, cfg) => roundCents(selectSubtotal(s2) - selectDiscountTotal(s2) + selectShipping(s2, cfg));
|
|
609
453
|
|
|
454
|
+
// src/analytics/bus.ts
|
|
455
|
+
var MAX_PENDING = 50;
|
|
456
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
457
|
+
var pending = [];
|
|
458
|
+
var identifier = null;
|
|
459
|
+
var pendingEmail = null;
|
|
460
|
+
var lastAt = /* @__PURE__ */ new Map();
|
|
461
|
+
function trackStorefront(name, properties = {}) {
|
|
462
|
+
if (typeof window === "undefined") return;
|
|
463
|
+
const event = { name, properties, at: Date.now() };
|
|
464
|
+
lastAt.set(name, event.at);
|
|
465
|
+
if (listeners.size === 0) {
|
|
466
|
+
pending.push(event);
|
|
467
|
+
if (pending.length > MAX_PENDING) pending = pending.slice(-MAX_PENDING);
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
for (const listener of listeners) {
|
|
471
|
+
try {
|
|
472
|
+
listener(event);
|
|
473
|
+
} catch {
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
function onStorefrontEvent(listener) {
|
|
478
|
+
listeners.add(listener);
|
|
479
|
+
if (pending.length) {
|
|
480
|
+
const held = pending;
|
|
481
|
+
pending = [];
|
|
482
|
+
for (const event of held) {
|
|
483
|
+
try {
|
|
484
|
+
listener(event);
|
|
485
|
+
} catch {
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
return () => {
|
|
490
|
+
listeners.delete(listener);
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
function identifyStorefrontBuyer(email) {
|
|
494
|
+
const clean = email.trim().toLowerCase();
|
|
495
|
+
if (!clean.includes("@")) return;
|
|
496
|
+
if (identifier) identifier(clean);
|
|
497
|
+
else pendingEmail = clean;
|
|
498
|
+
}
|
|
499
|
+
function setStorefrontIdentifier(fn) {
|
|
500
|
+
identifier = fn;
|
|
501
|
+
if (fn && pendingEmail) {
|
|
502
|
+
fn(pendingEmail);
|
|
503
|
+
pendingEmail = null;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
function lastStorefrontEventAt(name) {
|
|
507
|
+
return lastAt.get(name) ?? 0;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// src/analytics/identity.ts
|
|
511
|
+
async function storeBuyerId(storeId, email) {
|
|
512
|
+
const clean = email.trim().toLowerCase();
|
|
513
|
+
if (!storeId || !clean.includes("@")) return null;
|
|
514
|
+
const subtle = globalThis.crypto?.subtle;
|
|
515
|
+
if (!subtle) return null;
|
|
516
|
+
const digest = await subtle.digest("SHA-256", new TextEncoder().encode(clean));
|
|
517
|
+
const hex = Array.from(new Uint8Array(digest), (b) => b.toString(16).padStart(2, "0")).join("");
|
|
518
|
+
return `store:${storeId}:${hex}`;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// src/analytics/posthog.ts
|
|
522
|
+
var started = null;
|
|
523
|
+
function startStorefrontPostHog(config, context) {
|
|
524
|
+
if (typeof window === "undefined" || !config.key || !config.storeId) return null;
|
|
525
|
+
if (started) return started;
|
|
526
|
+
started = (async () => {
|
|
527
|
+
const { default: posthog } = await import('posthog-js');
|
|
528
|
+
const store = { store_id: config.storeId, store_name: context.storeName, commerce_mode: context.commerceMode };
|
|
529
|
+
posthog.init(config.key, {
|
|
530
|
+
api_host: config.apiHost ?? "/ingest",
|
|
531
|
+
ui_host: config.uiHost ?? "https://us.posthog.com",
|
|
532
|
+
defaults: "2026-08-30",
|
|
533
|
+
person_profiles: "identified_only",
|
|
534
|
+
capture_pageview: "history_change",
|
|
535
|
+
capture_dead_clicks: true,
|
|
536
|
+
capture_heatmaps: true,
|
|
537
|
+
disable_session_recording: config.replay === false,
|
|
538
|
+
session_recording: { maskAllInputs: true },
|
|
539
|
+
before_send: (event) => {
|
|
540
|
+
if (!event) return event;
|
|
541
|
+
const groups = event.properties.$groups ?? {};
|
|
542
|
+
event.properties.$groups = { ...groups, store: config.storeId };
|
|
543
|
+
return event;
|
|
544
|
+
}
|
|
545
|
+
});
|
|
546
|
+
posthog.register(store);
|
|
547
|
+
onStorefrontEvent((event) => {
|
|
548
|
+
posthog.capture(event.name, event.properties, { timestamp: new Date(event.at) });
|
|
549
|
+
});
|
|
550
|
+
setStorefrontIdentifier((email) => {
|
|
551
|
+
void storeBuyerId(config.storeId, email).then((id) => {
|
|
552
|
+
if (id && posthog.get_distinct_id() !== id) posthog.identify(id, { store_id: config.storeId });
|
|
553
|
+
});
|
|
554
|
+
});
|
|
555
|
+
})().catch(() => {
|
|
556
|
+
started = null;
|
|
557
|
+
});
|
|
558
|
+
return started;
|
|
559
|
+
}
|
|
560
|
+
function isOrderingPath(path, menuPath) {
|
|
561
|
+
const p = path.split(/[?#]/)[0] || "/";
|
|
562
|
+
if (menuPath && menuPath !== "/" && (p === menuPath || p.startsWith(`${menuPath}/`))) return true;
|
|
563
|
+
return /^\/(product|checkout|cart|order|account)(\/|$)/.test(p);
|
|
564
|
+
}
|
|
565
|
+
function cartChanges(prev, next) {
|
|
566
|
+
const key = (l) => l.lineId ?? l.productId;
|
|
567
|
+
const before = new Map(prev.lines.map((l) => [key(l), l]));
|
|
568
|
+
const after = new Map(next.lines.map((l) => [key(l), l]));
|
|
569
|
+
const out = [];
|
|
570
|
+
for (const [id, line] of after) {
|
|
571
|
+
const delta = line.quantity - (before.get(id)?.quantity ?? 0);
|
|
572
|
+
if (delta > 0) out.push({ kind: "added", line, quantity: delta });
|
|
573
|
+
if (delta < 0) out.push({ kind: "removed", line, quantity: -delta });
|
|
574
|
+
}
|
|
575
|
+
for (const [id, line] of before) if (!after.has(id)) out.push({ kind: "removed", line, quantity: line.quantity });
|
|
576
|
+
return out;
|
|
577
|
+
}
|
|
578
|
+
function StorefrontAnalytics({ config, path }) {
|
|
579
|
+
const posthog = config.analytics?.posthog;
|
|
580
|
+
const menuPath = config.delivery?.menuPath;
|
|
581
|
+
const previous = React39.useRef(null);
|
|
582
|
+
React39.useEffect(() => {
|
|
583
|
+
if (!posthog) return;
|
|
584
|
+
startStorefrontPostHog(posthog, { storeName: config.name, commerceMode: config.commerceMode });
|
|
585
|
+
}, [posthog, config.name, config.commerceMode]);
|
|
586
|
+
React39.useEffect(() => {
|
|
587
|
+
if (!posthog) return;
|
|
588
|
+
let ready = useCartStore.persist?.hasHydrated?.() ?? true;
|
|
589
|
+
const unhydrated = useCartStore.persist?.onFinishHydration?.(() => {
|
|
590
|
+
ready = true;
|
|
591
|
+
});
|
|
592
|
+
const unsubscribe = useCartStore.subscribe((next, prev) => {
|
|
593
|
+
if (!ready) return;
|
|
594
|
+
const totals = { cart_count: selectCount(next), cart_subtotal: selectSubtotal(next) };
|
|
595
|
+
const justOrdered = next.lines.length === 0 && Date.now() - lastStorefrontEventAt("checkout_completed") < 1e4;
|
|
596
|
+
for (const change of justOrdered ? [] : cartChanges(prev, next)) {
|
|
597
|
+
trackStorefront(change.kind === "added" ? "product_added_to_cart" : "product_removed_from_cart", {
|
|
598
|
+
product_id: change.line.productId,
|
|
599
|
+
product_name: change.line.name,
|
|
600
|
+
variant_id: change.line.variantId ?? null,
|
|
601
|
+
options: change.line.optionsLabel ?? null,
|
|
602
|
+
price: change.line.unitPrice,
|
|
603
|
+
quantity: change.quantity,
|
|
604
|
+
...totals
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
if (next.isOpen && !prev.isOpen) trackStorefront("cart_viewed", totals);
|
|
608
|
+
if (next.discountCode && next.discountCode !== prev.discountCode) {
|
|
609
|
+
trackStorefront("coupon_applied", { coupon: next.discountCode, discount_percent: next.discountPercent, ...totals });
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
return () => {
|
|
613
|
+
unsubscribe();
|
|
614
|
+
unhydrated?.();
|
|
615
|
+
};
|
|
616
|
+
}, [posthog]);
|
|
617
|
+
React39.useEffect(() => {
|
|
618
|
+
if (!posthog) return;
|
|
619
|
+
const from = previous.current;
|
|
620
|
+
previous.current = path;
|
|
621
|
+
if (!from || from === path) return;
|
|
622
|
+
if (isOrderingPath(from, menuPath) && !isOrderingPath(path, menuPath)) {
|
|
623
|
+
const cart = useCartStore.getState();
|
|
624
|
+
trackStorefront("delivery_exit", { from, to: path, cart_count: selectCount(cart), cart_subtotal: selectSubtotal(cart) });
|
|
625
|
+
}
|
|
626
|
+
}, [posthog, path, menuPath]);
|
|
627
|
+
return null;
|
|
628
|
+
}
|
|
629
|
+
var useSessionStore = create()(
|
|
630
|
+
persist(
|
|
631
|
+
(set) => ({
|
|
632
|
+
customerId: null,
|
|
633
|
+
email: null,
|
|
634
|
+
name: null,
|
|
635
|
+
setSession: ({ customerId, email, name }) => set({ customerId, email, name: name ?? null }),
|
|
636
|
+
signOut: () => set({ customerId: null, email: null, name: null })
|
|
637
|
+
}),
|
|
638
|
+
{ name: "fayz.storefront.session.v1" }
|
|
639
|
+
)
|
|
640
|
+
);
|
|
641
|
+
var EmailConfirmationRequiredError = class extends Error {
|
|
642
|
+
constructor(email) {
|
|
643
|
+
super("Cadastro realizado. Confirme seu e-mail para continuar.");
|
|
644
|
+
this.name = "EmailConfirmationRequiredError";
|
|
645
|
+
this.email = email;
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
var _adapter = null;
|
|
649
|
+
function isAuthAdapter(value) {
|
|
650
|
+
return Boolean(
|
|
651
|
+
value && typeof value === "object" && "getSession" in value && "signIn" in value && "signOut" in value
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
function normalizeAuthConfig(configured) {
|
|
655
|
+
if (!configured) return {};
|
|
656
|
+
if (typeof configured === "string" || isAuthAdapter(configured)) return { adapter: configured };
|
|
657
|
+
return configured;
|
|
658
|
+
}
|
|
659
|
+
function resolveAuthAdapter(configured, fallback) {
|
|
660
|
+
const config = normalizeAuthConfig(configured);
|
|
661
|
+
return createAuthRuntime({
|
|
662
|
+
provider: config.provider ?? config.adapter ?? (fallback?.supabaseUrl ? "supabase" : "mock"),
|
|
663
|
+
adapter: config.adapter,
|
|
664
|
+
routes: config.routes,
|
|
665
|
+
requireAuth: false,
|
|
666
|
+
supabase: {
|
|
667
|
+
url: config.supabase?.url ?? fallback?.supabaseUrl,
|
|
668
|
+
anonKey: config.supabase?.anonKey ?? fallback?.supabaseAnonKey,
|
|
669
|
+
client: config.supabase?.client,
|
|
670
|
+
callbackUrl: config.supabase?.callbackUrl,
|
|
671
|
+
resetPasswordUrl: config.supabase?.resetPasswordUrl
|
|
672
|
+
}
|
|
673
|
+
}).adapter;
|
|
674
|
+
}
|
|
675
|
+
var _accessToken = null;
|
|
676
|
+
var _hadAuthUser = false;
|
|
677
|
+
async function syncAccessToken(adapter) {
|
|
678
|
+
try {
|
|
679
|
+
const existing = await adapter.getSession();
|
|
680
|
+
_accessToken = existing?.session.accessToken ?? null;
|
|
681
|
+
} catch {
|
|
682
|
+
_accessToken = null;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
function initCustomerAuth(adapter) {
|
|
686
|
+
_adapter = adapter;
|
|
687
|
+
setShopAccessTokenResolver(() => _accessToken);
|
|
688
|
+
adapter.getSession().then((existing) => {
|
|
689
|
+
_accessToken = existing?.session.accessToken ?? null;
|
|
690
|
+
if (!existing) return;
|
|
691
|
+
_hadAuthUser = true;
|
|
692
|
+
void linkCustomer(existing.user).catch(() => {
|
|
693
|
+
});
|
|
694
|
+
}).catch(() => {
|
|
695
|
+
});
|
|
696
|
+
adapter.onAuthStateChange((user) => {
|
|
697
|
+
if (!user) {
|
|
698
|
+
_accessToken = null;
|
|
699
|
+
if (_hadAuthUser) {
|
|
700
|
+
_hadAuthUser = false;
|
|
701
|
+
useSessionStore.getState().signOut();
|
|
702
|
+
}
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
_hadAuthUser = true;
|
|
706
|
+
const linked = useSessionStore.getState();
|
|
707
|
+
const needsLink = !linked.customerId || (linked.email ?? "").toLowerCase() !== (user.email ?? "").toLowerCase();
|
|
708
|
+
void syncAccessToken(adapter).then(() => {
|
|
709
|
+
if (needsLink && user.email) return linkCustomer(user).then(() => void 0);
|
|
710
|
+
}).catch(() => {
|
|
711
|
+
});
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
function hasCustomerAuth() {
|
|
715
|
+
return _hadAuthUser;
|
|
716
|
+
}
|
|
717
|
+
async function relinkCustomer() {
|
|
718
|
+
if (!_hadAuthUser) return null;
|
|
719
|
+
const existing = await getCustomerAuthAdapter().getSession().catch(() => null);
|
|
720
|
+
if (!existing?.user.email) return null;
|
|
721
|
+
const customer = await resolveShopCustomer(existing.user.email.trim().toLowerCase(), existing.user.fullName ?? "");
|
|
722
|
+
const store = useSessionStore.getState();
|
|
723
|
+
store.setSession({ customerId: customer.id, email: existing.user.email.trim().toLowerCase(), name: store.name });
|
|
724
|
+
return { customerId: customer.id, phone: customer.phone ?? null, document: customer.document ?? null };
|
|
725
|
+
}
|
|
726
|
+
function getCustomerAuthAdapter() {
|
|
727
|
+
if (!_adapter) _adapter = createMockAuthAdapter();
|
|
728
|
+
return _adapter;
|
|
729
|
+
}
|
|
730
|
+
async function resolveShopCustomer(email, name) {
|
|
731
|
+
const provider = getShopProvider();
|
|
732
|
+
if (provider.resolveCustomer) return provider.resolveCustomer({ email, name });
|
|
733
|
+
const matches = await provider.listCustomers({ search: email, limit: 10 });
|
|
734
|
+
const existing = matches.find((c) => (c.email ?? "").toLowerCase() === email);
|
|
735
|
+
if (existing) return existing;
|
|
736
|
+
const parts = name.trim().split(/\s+/).filter(Boolean);
|
|
737
|
+
return provider.createCustomer({
|
|
738
|
+
firstName: parts[0] ?? email.split("@")[0] ?? "Cliente",
|
|
739
|
+
lastName: parts.slice(1).join(" "),
|
|
740
|
+
email
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
async function linkCustomer(user, fullName) {
|
|
744
|
+
const email = (user.email ?? "").trim().toLowerCase();
|
|
745
|
+
const name = fullName ?? user.fullName ?? "";
|
|
746
|
+
const customer = await resolveShopCustomer(email, name);
|
|
747
|
+
useSessionStore.getState().setSession({
|
|
748
|
+
customerId: customer.id,
|
|
749
|
+
email,
|
|
750
|
+
name: name || `${customer.firstName} ${customer.lastName}`.trim()
|
|
751
|
+
});
|
|
752
|
+
return { customerId: customer.id };
|
|
753
|
+
}
|
|
754
|
+
async function establishCustomerSession(email, opts) {
|
|
755
|
+
const normalized = email.trim().toLowerCase();
|
|
756
|
+
if (opts?.password) {
|
|
757
|
+
const adapter = getCustomerAuthAdapter();
|
|
758
|
+
const session = await adapter.signIn(normalized, opts.password);
|
|
759
|
+
_accessToken = session.accessToken ?? null;
|
|
760
|
+
_hadAuthUser = true;
|
|
761
|
+
return linkCustomer(session.user.email ? session.user : { ...session.user, email: normalized }, opts.name);
|
|
762
|
+
}
|
|
763
|
+
return linkCustomer({ email: normalized }, opts?.name);
|
|
764
|
+
}
|
|
765
|
+
function signInByEmail(email, name) {
|
|
766
|
+
return establishCustomerSession(email, { name });
|
|
767
|
+
}
|
|
768
|
+
async function signUpCustomer(email, password, name) {
|
|
769
|
+
const adapter = getCustomerAuthAdapter();
|
|
770
|
+
const normalized = email.trim().toLowerCase();
|
|
771
|
+
const session = await adapter.signUp(normalized, password, name);
|
|
772
|
+
if (!session.accessToken) throw new EmailConfirmationRequiredError(normalized);
|
|
773
|
+
_accessToken = session.accessToken;
|
|
774
|
+
_hadAuthUser = true;
|
|
775
|
+
return linkCustomer(session.user.email ? session.user : { ...session.user, email: normalized }, name);
|
|
776
|
+
}
|
|
777
|
+
async function signOutCustomer() {
|
|
778
|
+
try {
|
|
779
|
+
await getCustomerAuthAdapter().signOut();
|
|
780
|
+
} finally {
|
|
781
|
+
_accessToken = null;
|
|
782
|
+
_hadAuthUser = false;
|
|
783
|
+
useSessionStore.getState().signOut();
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
610
787
|
// src/data/facets.ts
|
|
611
788
|
function matchesFacets(metadata, facets) {
|
|
612
789
|
for (const [key, wanted] of Object.entries(facets)) {
|
|
@@ -1626,7 +1803,7 @@ function Link({ to, children, onClick, target, ...rest }) {
|
|
|
1626
1803
|
event.preventDefault();
|
|
1627
1804
|
adapter.navigate(to);
|
|
1628
1805
|
};
|
|
1629
|
-
return
|
|
1806
|
+
return React39__default.createElement(
|
|
1630
1807
|
"a",
|
|
1631
1808
|
{ href: adapter.href(to), onClick: handleClick, target, ...rest },
|
|
1632
1809
|
children
|
|
@@ -1866,9 +2043,9 @@ function SmoothImage({
|
|
|
1866
2043
|
const easing = resolved.easing ?? "cubic-bezier(0.22, 1, 0.36, 1)";
|
|
1867
2044
|
const blur = resolved.blur ?? true;
|
|
1868
2045
|
const transform = resolved.transform ?? "none";
|
|
1869
|
-
const ref =
|
|
1870
|
-
const [loaded, setLoaded] =
|
|
1871
|
-
const delivered =
|
|
2046
|
+
const ref = React39__default.useRef(null);
|
|
2047
|
+
const [loaded, setLoaded] = React39__default.useState(() => mode === "none" || !clientMounted);
|
|
2048
|
+
const delivered = React39__default.useMemo(() => {
|
|
1872
2049
|
if (transform !== "supabase" || !src || srcSet || !isStorageImageUrl(src)) return { src, srcSet, sizes };
|
|
1873
2050
|
if (variant?.width) {
|
|
1874
2051
|
const w = variant.width;
|
|
@@ -1886,10 +2063,10 @@ function SmoothImage({
|
|
|
1886
2063
|
sizes: variant?.sizes ?? sizes ?? "100vw"
|
|
1887
2064
|
};
|
|
1888
2065
|
}, [transform, src, srcSet, sizes, variant?.width, variant?.sizes, variant?.widths, variant?.quality]);
|
|
1889
|
-
|
|
2066
|
+
React39__default.useEffect(() => {
|
|
1890
2067
|
clientMounted = true;
|
|
1891
2068
|
}, []);
|
|
1892
|
-
|
|
2069
|
+
React39__default.useEffect(() => {
|
|
1893
2070
|
if (mode === "none") {
|
|
1894
2071
|
setLoaded(true);
|
|
1895
2072
|
return;
|
|
@@ -2287,17 +2464,17 @@ function PageDataScope({ nodes, params, initial: initial2, children }) {
|
|
|
2287
2464
|
}));
|
|
2288
2465
|
const signature = own.map((need) => need.key).join("\n");
|
|
2289
2466
|
useEffect(() => {
|
|
2290
|
-
const
|
|
2291
|
-
if (
|
|
2467
|
+
const pending2 = own.filter((need) => initial2?.[need.key]?.status !== "ready");
|
|
2468
|
+
if (pending2.length === 0) return;
|
|
2292
2469
|
let cancelled = false;
|
|
2293
2470
|
setEntries((prev) => {
|
|
2294
2471
|
const next = { ...prev };
|
|
2295
|
-
for (const need of
|
|
2472
|
+
for (const need of pending2) {
|
|
2296
2473
|
if (next[need.key]?.status !== "ready") next[need.key] = { status: "loading" };
|
|
2297
2474
|
}
|
|
2298
2475
|
return next;
|
|
2299
2476
|
});
|
|
2300
|
-
for (const need of
|
|
2477
|
+
for (const need of pending2) {
|
|
2301
2478
|
void resolvePageDataNeed(need).then((entry) => {
|
|
2302
2479
|
if (!cancelled) setEntries((prev) => ({ ...prev, [need.key]: entry }));
|
|
2303
2480
|
});
|
|
@@ -3165,8 +3342,8 @@ var BADGE_TONE_CLASSES = {
|
|
|
3165
3342
|
warning: "bg-amber-500 text-white"
|
|
3166
3343
|
};
|
|
3167
3344
|
function useExtensionBadges(product) {
|
|
3168
|
-
const [badges, setBadges] =
|
|
3169
|
-
|
|
3345
|
+
const [badges, setBadges] = React39__default.useState([]);
|
|
3346
|
+
React39__default.useEffect(() => {
|
|
3170
3347
|
let cancelled = false;
|
|
3171
3348
|
getProductCardBadges(product).then((next) => {
|
|
3172
3349
|
if (!cancelled && next.length > 0) setBadges(next);
|
|
@@ -4363,7 +4540,7 @@ function scalarToString(value) {
|
|
|
4363
4540
|
}
|
|
4364
4541
|
function ProductSpecs({ product }) {
|
|
4365
4542
|
const config = useStorefrontConfig();
|
|
4366
|
-
const extraExcluded =
|
|
4543
|
+
const extraExcluded = React39__default.useMemo(
|
|
4367
4544
|
() => new Set(config.productSpecs?.exclude ?? []),
|
|
4368
4545
|
[config.productSpecs?.exclude]
|
|
4369
4546
|
);
|
|
@@ -4992,6 +5169,17 @@ function ProductDetailPage({ slug }) {
|
|
|
4992
5169
|
useStorefrontHead(
|
|
4993
5170
|
product ? productSeo(product, { config, path }) : { title: config.name }
|
|
4994
5171
|
);
|
|
5172
|
+
useEffect(() => {
|
|
5173
|
+
if (!product) return;
|
|
5174
|
+
trackStorefront("product_viewed", {
|
|
5175
|
+
product_id: product.id,
|
|
5176
|
+
product_name: product.name,
|
|
5177
|
+
slug: product.slug,
|
|
5178
|
+
price: product.price,
|
|
5179
|
+
in_stock: product.inventoryCount > 0,
|
|
5180
|
+
surface: "product_page"
|
|
5181
|
+
});
|
|
5182
|
+
}, [product?.id]);
|
|
4995
5183
|
useEffect(() => {
|
|
4996
5184
|
if (!product) return;
|
|
4997
5185
|
const defaults = Object.fromEntries(
|
|
@@ -6077,7 +6265,7 @@ function CollectionHero({
|
|
|
6077
6265
|
{
|
|
6078
6266
|
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"}`,
|
|
6079
6267
|
children: /* @__PURE__ */ jsxs(Reveal, { className: centered ? "max-w-3xl" : "max-w-2xl", children: [
|
|
6080
|
-
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(
|
|
6268
|
+
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(React39__default.Fragment, { children: [
|
|
6081
6269
|
i > 0 && /* @__PURE__ */ jsx("span", { className: "text-2xl font-light opacity-60", "aria-hidden": true, children: "\xD7" }),
|
|
6082
6270
|
/* @__PURE__ */ jsx("img", { src: logo.src, alt: logo.alt, className: "h-10 w-auto object-contain sm:h-14" })
|
|
6083
6271
|
] }, logo.src)) }),
|
|
@@ -6859,10 +7047,10 @@ function StorefrontConfigHost({
|
|
|
6859
7047
|
buyer,
|
|
6860
7048
|
children
|
|
6861
7049
|
}) {
|
|
6862
|
-
const [policy, setPolicy] =
|
|
6863
|
-
const [shipping, setShipping] =
|
|
6864
|
-
const [delivery, setDelivery] =
|
|
6865
|
-
|
|
7050
|
+
const [policy, setPolicy] = React39__default.useState(null);
|
|
7051
|
+
const [shipping, setShipping] = React39__default.useState(null);
|
|
7052
|
+
const [delivery, setDelivery] = React39__default.useState(null);
|
|
7053
|
+
React39__default.useEffect(() => {
|
|
6866
7054
|
let cancelled = false;
|
|
6867
7055
|
let provider;
|
|
6868
7056
|
try {
|
|
@@ -6899,7 +7087,7 @@ function StorefrontConfigHost({
|
|
|
6899
7087
|
cancelled = true;
|
|
6900
7088
|
};
|
|
6901
7089
|
}, [config]);
|
|
6902
|
-
const resolved =
|
|
7090
|
+
const resolved = React39__default.useMemo(
|
|
6903
7091
|
() => applyBuyer(applyDeliveryPolicy(applyShippingSettings(applyStoreSettings(config, policy), shipping), delivery), buyer),
|
|
6904
7092
|
[config, policy, shipping, delivery, buyer?.language, buyer?.country]
|
|
6905
7093
|
);
|
|
@@ -6911,7 +7099,7 @@ function MarketScope({ children }) {
|
|
|
6911
7099
|
const markets = useMarketStore((s2) => s2.markets);
|
|
6912
7100
|
const market = markets.length ? marketForCountry(markets, country) : null;
|
|
6913
7101
|
const prices = useMarketStore((s2) => market ? s2.prices[market.code] : void 0);
|
|
6914
|
-
|
|
7102
|
+
React39__default.useEffect(() => {
|
|
6915
7103
|
useMarketStore.getState().setActive(market);
|
|
6916
7104
|
if (!market || market.isDefault || prices) return;
|
|
6917
7105
|
let provider;
|
|
@@ -6923,11 +7111,11 @@ function MarketScope({ children }) {
|
|
|
6923
7111
|
void provider.getMarketPrices?.(market.code).then((list) => useMarketStore.getState().setPrices(market.code, list)).catch(() => {
|
|
6924
7112
|
});
|
|
6925
7113
|
}, [market?.code, prices]);
|
|
6926
|
-
|
|
7114
|
+
React39__default.useEffect(() => {
|
|
6927
7115
|
if (!market || !market.isDefault && !prices) return;
|
|
6928
7116
|
useCartStore.getState().repriceForMarket();
|
|
6929
7117
|
}, [market?.code, prices]);
|
|
6930
|
-
const value =
|
|
7118
|
+
const value = React39__default.useMemo(() => {
|
|
6931
7119
|
if (!market) return base;
|
|
6932
7120
|
return {
|
|
6933
7121
|
...base,
|
|
@@ -7057,7 +7245,7 @@ function StorefrontThemeStyle({
|
|
|
7057
7245
|
document.getElementById(linkId)?.remove();
|
|
7058
7246
|
};
|
|
7059
7247
|
}, [fontsHref, linkId, selector]);
|
|
7060
|
-
return
|
|
7248
|
+
return React39__default.createElement(
|
|
7061
7249
|
"style",
|
|
7062
7250
|
{ "data-sf-theme": theme.name },
|
|
7063
7251
|
themeToCss(theme, { selector })
|
|
@@ -7156,7 +7344,7 @@ function SearchOverlay({ onClose }) {
|
|
|
7156
7344
|
"\u201D."
|
|
7157
7345
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7158
7346
|
/* @__PURE__ */ jsx("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4", children: suggestions.map(
|
|
7159
|
-
(product) => searchConfig.renderSuggestion ? /* @__PURE__ */ jsx(
|
|
7347
|
+
(product) => searchConfig.renderSuggestion ? /* @__PURE__ */ jsx(React39__default.Fragment, { children: searchConfig.renderSuggestion(product) }, product.id) : /* @__PURE__ */ jsx(SuggestionCard, { product, onNavigate: onClose }, product.id)
|
|
7160
7348
|
) }),
|
|
7161
7349
|
/* @__PURE__ */ jsx(
|
|
7162
7350
|
"button",
|
|
@@ -7363,11 +7551,11 @@ function HeaderActions({ onMenuClick }) {
|
|
|
7363
7551
|
const openDrawer = useCartStore((s2) => s2.openDrawer);
|
|
7364
7552
|
const session = useSessionStore();
|
|
7365
7553
|
const [accountOpen, setAccountOpen] = useState(false);
|
|
7366
|
-
const accountRef =
|
|
7554
|
+
const accountRef = React39__default.useRef(null);
|
|
7367
7555
|
const pop = usePopOnChange(count);
|
|
7368
7556
|
const firstName = session.name?.split(/\s+/)[0];
|
|
7369
7557
|
const initial2 = (firstName ?? session.email ?? "C").slice(0, 1).toUpperCase();
|
|
7370
|
-
|
|
7558
|
+
React39__default.useEffect(() => {
|
|
7371
7559
|
if (!accountOpen) return;
|
|
7372
7560
|
const onPointerDown = (event) => {
|
|
7373
7561
|
if (!accountRef.current?.contains(event.target)) setAccountOpen(false);
|
|
@@ -7534,7 +7722,7 @@ function MobileMenuDrawer({ open, onClose }) {
|
|
|
7534
7722
|
navigateTo(config.catalogPath);
|
|
7535
7723
|
onClose();
|
|
7536
7724
|
};
|
|
7537
|
-
|
|
7725
|
+
React39__default.useEffect(() => {
|
|
7538
7726
|
if (!open) return;
|
|
7539
7727
|
const onKey = (e) => {
|
|
7540
7728
|
if (e.key === "Escape") onClose();
|
|
@@ -8567,8 +8755,8 @@ function AddressForm({ country, language, value, onChange, onPostalCode, lookup,
|
|
|
8567
8755
|
postalHint()
|
|
8568
8756
|
] }, "postalCode");
|
|
8569
8757
|
}
|
|
8570
|
-
if (row.length === 1) return /* @__PURE__ */ jsx(
|
|
8571
|
-
return /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3", children: cells.map((key) => /* @__PURE__ */ jsx(
|
|
8758
|
+
if (row.length === 1) return /* @__PURE__ */ jsx(React39__default.Fragment, { children: input(specs.get(cells[0])) }, cells[0]);
|
|
8759
|
+
return /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3", children: cells.map((key) => /* @__PURE__ */ jsx(React39__default.Fragment, { children: input(specs.get(key)) }, key)) }, cells.join("-"));
|
|
8572
8760
|
}) });
|
|
8573
8761
|
}
|
|
8574
8762
|
function flag(iso2) {
|
|
@@ -8924,13 +9112,13 @@ function CardBrick({ publicKey, amount, email, onSubmit, onError }) {
|
|
|
8924
9112
|
var POLL_MS = 3e3;
|
|
8925
9113
|
var RESUME_KEY = "fz.checkout.resume";
|
|
8926
9114
|
function useExpiry(expiresAt) {
|
|
8927
|
-
const target =
|
|
9115
|
+
const target = React39__default.useMemo(() => {
|
|
8928
9116
|
if (!expiresAt) return null;
|
|
8929
9117
|
const t = new Date(expiresAt).getTime();
|
|
8930
9118
|
return Number.isFinite(t) ? t : null;
|
|
8931
9119
|
}, [expiresAt]);
|
|
8932
|
-
const [now, setNow] =
|
|
8933
|
-
|
|
9120
|
+
const [now, setNow] = React39__default.useState(() => Date.now());
|
|
9121
|
+
React39__default.useEffect(() => {
|
|
8934
9122
|
if (target === null) return;
|
|
8935
9123
|
const id = setInterval(() => setNow(Date.now()), 1e3);
|
|
8936
9124
|
return () => clearInterval(id);
|
|
@@ -9568,6 +9756,7 @@ var DEV_BUILD = (() => {
|
|
|
9568
9756
|
return false;
|
|
9569
9757
|
}
|
|
9570
9758
|
})();
|
|
9759
|
+
var CHECKOUT_STEP_NAMES = { 1: "contact", 2: "delivery", 3: "payment", 4: "done" };
|
|
9571
9760
|
function CheckoutPage() {
|
|
9572
9761
|
const config = useStorefrontConfig();
|
|
9573
9762
|
const cart = useCartStore();
|
|
@@ -9625,7 +9814,7 @@ function CheckoutPage() {
|
|
|
9625
9814
|
district: "",
|
|
9626
9815
|
state: ""
|
|
9627
9816
|
});
|
|
9628
|
-
|
|
9817
|
+
React39__default.useEffect(() => {
|
|
9629
9818
|
if (!known.ready) return;
|
|
9630
9819
|
setForm((current) => ({
|
|
9631
9820
|
...current,
|
|
@@ -9641,9 +9830,22 @@ function CheckoutPage() {
|
|
|
9641
9830
|
}));
|
|
9642
9831
|
}, [known.ready, known.phone, known.document, known.address]);
|
|
9643
9832
|
const [step, setStep] = useState(resume ? 3 : 1);
|
|
9833
|
+
const reportedStart = React39__default.useRef(false);
|
|
9834
|
+
useEffect(() => {
|
|
9835
|
+
if (reportedStart.current) return;
|
|
9836
|
+
reportedStart.current = true;
|
|
9837
|
+
if (!resume) trackStorefront("checkout_started", { cart_count: cart.lines.reduce((n, l) => n + l.quantity, 0) });
|
|
9838
|
+
}, []);
|
|
9839
|
+
const reportedStep = React39__default.useRef(null);
|
|
9840
|
+
useEffect(() => {
|
|
9841
|
+
if (reportedStep.current === step) return;
|
|
9842
|
+
reportedStep.current = step;
|
|
9843
|
+
trackStorefront("checkout_step_viewed", { step, step_name: CHECKOUT_STEP_NAMES[step], resume: Boolean(resume) });
|
|
9844
|
+
if (step >= 2 && /.+@.+\..+/.test(form.email)) identifyStorefrontBuyer(form.email);
|
|
9845
|
+
}, [step]);
|
|
9644
9846
|
const [contactKnown, setContactKnown] = useState(false);
|
|
9645
9847
|
const [editingContact, setEditingContact] = useState(false);
|
|
9646
|
-
const skippedContact =
|
|
9848
|
+
const skippedContact = React39__default.useRef(false);
|
|
9647
9849
|
const fulfillmentType = useDeliveryStore((s2) => s2.fulfillmentType);
|
|
9648
9850
|
const scheduledFor = useDeliveryStore((s2) => s2.scheduledFor);
|
|
9649
9851
|
const deliveryReference = useDeliveryStore((s2) => {
|
|
@@ -9672,7 +9874,7 @@ function CheckoutPage() {
|
|
|
9672
9874
|
const [applyingDiscount, setApplyingDiscount] = useState(false);
|
|
9673
9875
|
const [showSignin, setShowSignin] = useState(false);
|
|
9674
9876
|
const [placing, setPlacing] = useState(false);
|
|
9675
|
-
const leaving =
|
|
9877
|
+
const leaving = React39__default.useRef(false);
|
|
9676
9878
|
const [zipLookup, setZipLookup] = useState("idle");
|
|
9677
9879
|
const subtotal = selectSubtotal(cart);
|
|
9678
9880
|
const discountTotal = selectDiscountTotal(cart);
|
|
@@ -9680,7 +9882,7 @@ function CheckoutPage() {
|
|
|
9680
9882
|
const shipping = isPickup ? 0 : shippingRaw;
|
|
9681
9883
|
const total = selectTotal(cart, config) - (isPickup ? shippingRaw : 0);
|
|
9682
9884
|
const checkoutSlotContext = { subtotal, total };
|
|
9683
|
-
const checkoutSessionInput =
|
|
9885
|
+
const checkoutSessionInput = React39__default.useMemo(() => ({
|
|
9684
9886
|
items: cart.lines.map((line) => ({
|
|
9685
9887
|
productId: line.productId,
|
|
9686
9888
|
variantId: line.variantId ?? null,
|
|
@@ -9857,7 +10059,7 @@ function CheckoutPage() {
|
|
|
9857
10059
|
cancelled = true;
|
|
9858
10060
|
};
|
|
9859
10061
|
}, [session.customerId]);
|
|
9860
|
-
const shownCountry =
|
|
10062
|
+
const shownCountry = React39__default.useRef(country);
|
|
9861
10063
|
useEffect(() => {
|
|
9862
10064
|
if (shownCountry.current === country) return;
|
|
9863
10065
|
shownCountry.current = country;
|
|
@@ -9924,6 +10126,7 @@ function CheckoutPage() {
|
|
|
9924
10126
|
}
|
|
9925
10127
|
function fail(message, testId) {
|
|
9926
10128
|
setError(message);
|
|
10129
|
+
trackStorefront("checkout_error", { step, field: testId ?? null, reason: message });
|
|
9927
10130
|
if (testId) {
|
|
9928
10131
|
const field2 = document.querySelector(`[data-testid="${testId}"]`);
|
|
9929
10132
|
field2?.scrollIntoView({ block: "center", behavior: prefersReducedMotion() ? "auto" : "smooth" });
|
|
@@ -10091,10 +10294,18 @@ function CheckoutPage() {
|
|
|
10091
10294
|
});
|
|
10092
10295
|
if (customerId) session.setSession({ customerId, email: form.email, name: form.name });
|
|
10093
10296
|
leaving.current = true;
|
|
10297
|
+
trackStorefront("checkout_completed", {
|
|
10298
|
+
order_id: order.id,
|
|
10299
|
+
payment_method: paymentMethod,
|
|
10300
|
+
fulfillment: fulfillmentType ?? "delivery",
|
|
10301
|
+
total,
|
|
10302
|
+
online_payment: false
|
|
10303
|
+
});
|
|
10094
10304
|
cart.clear();
|
|
10095
10305
|
navigateTo(`/order/${order.id}`);
|
|
10096
10306
|
} catch (err) {
|
|
10097
10307
|
setError(placeOrderMessage(err, t));
|
|
10308
|
+
trackStorefront("checkout_error", { step, field: "place_order", reason: placeOrderMessage(err, t) });
|
|
10098
10309
|
setPlacing(false);
|
|
10099
10310
|
}
|
|
10100
10311
|
}
|
|
@@ -10342,7 +10553,10 @@ function CheckoutPage() {
|
|
|
10342
10553
|
role: "radio",
|
|
10343
10554
|
"aria-checked": selected,
|
|
10344
10555
|
"data-testid": `checkout-payment-${method}`,
|
|
10345
|
-
onClick: () =>
|
|
10556
|
+
onClick: () => {
|
|
10557
|
+
setPaymentMethod(method);
|
|
10558
|
+
if (method !== paymentMethod) trackStorefront("checkout_payment_selected", { payment_method: method });
|
|
10559
|
+
},
|
|
10346
10560
|
className: `w-full rounded-lg border p-3 text-left text-sm transition hover:bg-muted/40 ${selected ? "border-primary bg-primary/5" : "border-border bg-background"}`,
|
|
10347
10561
|
children: [
|
|
10348
10562
|
/* @__PURE__ */ jsxs("span", { className: "flex items-center justify-between gap-3 font-semibold", children: [
|
|
@@ -10368,6 +10582,13 @@ function CheckoutPage() {
|
|
|
10368
10582
|
onPaid: (orderId) => {
|
|
10369
10583
|
leaving.current = true;
|
|
10370
10584
|
setPaidOrderId(orderId);
|
|
10585
|
+
trackStorefront("checkout_completed", {
|
|
10586
|
+
order_id: orderId,
|
|
10587
|
+
payment_method: method,
|
|
10588
|
+
fulfillment: fulfillmentType ?? "delivery",
|
|
10589
|
+
total,
|
|
10590
|
+
online_payment: true
|
|
10591
|
+
});
|
|
10371
10592
|
goToStep(4);
|
|
10372
10593
|
cart.clear();
|
|
10373
10594
|
}
|
|
@@ -10751,8 +10972,8 @@ function AddressStrip({
|
|
|
10751
10972
|
const money = (v) => formatMoney(v, config.currency, config.locale);
|
|
10752
10973
|
const subtotal = selectSubtotal(useCartStore());
|
|
10753
10974
|
const resolve = useDeliveryStore((s2) => s2.resolve);
|
|
10754
|
-
const quotedOnce =
|
|
10755
|
-
|
|
10975
|
+
const quotedOnce = React39__default.useRef(false);
|
|
10976
|
+
React39__default.useEffect(() => {
|
|
10756
10977
|
if (quotedOnce.current || isPickup) return;
|
|
10757
10978
|
if (delivery.status !== "idle" || delivery.options.length > 0 || !delivery.postalCode) return;
|
|
10758
10979
|
quotedOnce.current = true;
|
|
@@ -10814,17 +11035,17 @@ function MenuToolbar({
|
|
|
10814
11035
|
onQuery,
|
|
10815
11036
|
autoFocusSearch
|
|
10816
11037
|
}) {
|
|
10817
|
-
const inputRef =
|
|
10818
|
-
const [active2, setActive] =
|
|
10819
|
-
|
|
11038
|
+
const inputRef = React39__default.useRef(null);
|
|
11039
|
+
const [active2, setActive] = React39__default.useState(null);
|
|
11040
|
+
React39__default.useEffect(() => {
|
|
10820
11041
|
setActive(
|
|
10821
11042
|
(current) => current && sections.some((s2) => s2.slug === current) ? current : sections[0]?.slug ?? null
|
|
10822
11043
|
);
|
|
10823
11044
|
}, [sections]);
|
|
10824
|
-
|
|
11045
|
+
React39__default.useEffect(() => {
|
|
10825
11046
|
if (autoFocusSearch) inputRef.current?.focus();
|
|
10826
11047
|
}, [autoFocusSearch]);
|
|
10827
|
-
|
|
11048
|
+
React39__default.useEffect(() => {
|
|
10828
11049
|
if (typeof IntersectionObserver === "undefined") return;
|
|
10829
11050
|
const seen = /* @__PURE__ */ new Map();
|
|
10830
11051
|
const observer = new IntersectionObserver(
|
|
@@ -11011,10 +11232,10 @@ function ItemSheet({
|
|
|
11011
11232
|
}) {
|
|
11012
11233
|
const config = useStorefrontConfig();
|
|
11013
11234
|
const money = (v) => formatMoney(v, config.currency, config.locale);
|
|
11014
|
-
const groups =
|
|
11015
|
-
const [options, setOptions] =
|
|
11016
|
-
const [notes, setNotes] =
|
|
11017
|
-
const [quantity, setQuantity] =
|
|
11235
|
+
const groups = React39__default.useMemo(() => getProductOptionGroups(product), [product]);
|
|
11236
|
+
const [options, setOptions] = React39__default.useState({});
|
|
11237
|
+
const [notes, setNotes] = React39__default.useState("");
|
|
11238
|
+
const [quantity, setQuantity] = React39__default.useState(1);
|
|
11018
11239
|
const image = product.images?.find((i) => i.isPrimary) ?? product.images?.[0];
|
|
11019
11240
|
const stock = product.inventoryCount;
|
|
11020
11241
|
const missing = groups.filter((g) => !options[g.label]);
|
|
@@ -11208,8 +11429,8 @@ function ScheduleSheet({ onClose }) {
|
|
|
11208
11429
|
const scheduledFor = useDeliveryStore((s2) => s2.scheduledFor);
|
|
11209
11430
|
const setScheduledFor = useDeliveryStore((s2) => s2.setScheduledFor);
|
|
11210
11431
|
const timezone = useServiceStore((s2) => s2.service?.timezone) ?? "America/Sao_Paulo";
|
|
11211
|
-
const [slots, setSlots] =
|
|
11212
|
-
|
|
11432
|
+
const [slots, setSlots] = React39__default.useState(null);
|
|
11433
|
+
React39__default.useEffect(() => {
|
|
11213
11434
|
let alive = true;
|
|
11214
11435
|
void (async () => {
|
|
11215
11436
|
const rows = await getShopProvider()?.listScheduleSlots?.(fulfillmentType) ?? [];
|
|
@@ -11219,7 +11440,7 @@ function ScheduleSheet({ onClose }) {
|
|
|
11219
11440
|
alive = false;
|
|
11220
11441
|
};
|
|
11221
11442
|
}, [fulfillmentType]);
|
|
11222
|
-
const days =
|
|
11443
|
+
const days = React39__default.useMemo(() => {
|
|
11223
11444
|
const fmtDay = new Intl.DateTimeFormat("pt-BR", {
|
|
11224
11445
|
weekday: "long",
|
|
11225
11446
|
day: "2-digit",
|
|
@@ -11305,8 +11526,8 @@ function hhmm(time) {
|
|
|
11305
11526
|
}
|
|
11306
11527
|
function ServiceHoursModal({ onClose }) {
|
|
11307
11528
|
const fulfillmentType = useServiceStore((s2) => s2.fulfillmentType);
|
|
11308
|
-
const [hours, setHours] =
|
|
11309
|
-
|
|
11529
|
+
const [hours, setHours] = React39__default.useState(null);
|
|
11530
|
+
React39__default.useEffect(() => {
|
|
11310
11531
|
let alive = true;
|
|
11311
11532
|
void (async () => {
|
|
11312
11533
|
const rows = await getShopProvider()?.listServiceHours?.(fulfillmentType) ?? [];
|
|
@@ -11316,7 +11537,7 @@ function ServiceHoursModal({ onClose }) {
|
|
|
11316
11537
|
alive = false;
|
|
11317
11538
|
};
|
|
11318
11539
|
}, [fulfillmentType]);
|
|
11319
|
-
const byDay =
|
|
11540
|
+
const byDay = React39__default.useMemo(() => {
|
|
11320
11541
|
const map = /* @__PURE__ */ new Map();
|
|
11321
11542
|
for (const h of hours ?? []) {
|
|
11322
11543
|
const list = map.get(h.weekday) ?? [];
|
|
@@ -11401,7 +11622,7 @@ function AddressSheet({ onClose, onSignIn }) {
|
|
|
11401
11622
|
const unsavedCurrent = current && !saved.some((a) => a.id === selectedId) ? current : null;
|
|
11402
11623
|
const fromAccount = accountBook.filter((a) => !saved.some((b) => normalizePostalCode(b.postalCode) === normalizePostalCode(a.postalCode) && b.number.trim().toLowerCase() === (a.number ?? "").trim().toLowerCase()));
|
|
11403
11624
|
const nothingToList = saved.length === 0 && !unsavedCurrent && fromAccount.length === 0 && !customerId;
|
|
11404
|
-
const [editing, setEditing] =
|
|
11625
|
+
const [editing, setEditing] = React39__default.useState(
|
|
11405
11626
|
nothingToList && !onSignIn ? {} : null
|
|
11406
11627
|
);
|
|
11407
11628
|
function pickAccountAddress(a) {
|
|
@@ -11420,13 +11641,13 @@ function AddressSheet({ onClose, onSignIn }) {
|
|
|
11420
11641
|
void selectAddress(id, subtotal);
|
|
11421
11642
|
onClose();
|
|
11422
11643
|
}
|
|
11423
|
-
const closeRef =
|
|
11644
|
+
const closeRef = React39__default.useRef(() => {
|
|
11424
11645
|
});
|
|
11425
11646
|
closeRef.current = () => {
|
|
11426
11647
|
if (editing && !nothingToList) setEditing(null);
|
|
11427
11648
|
else onClose();
|
|
11428
11649
|
};
|
|
11429
|
-
|
|
11650
|
+
React39__default.useEffect(() => {
|
|
11430
11651
|
const onKey = (e) => {
|
|
11431
11652
|
if (e.key === "Escape") closeRef.current();
|
|
11432
11653
|
};
|
|
@@ -11607,8 +11828,8 @@ function AddressLines({ address }) {
|
|
|
11607
11828
|
] });
|
|
11608
11829
|
}
|
|
11609
11830
|
function useAccountAddresses(customerId) {
|
|
11610
|
-
const [rows, setRows] =
|
|
11611
|
-
|
|
11831
|
+
const [rows, setRows] = React39__default.useState([]);
|
|
11832
|
+
React39__default.useEffect(() => {
|
|
11612
11833
|
if (!customerId) {
|
|
11613
11834
|
setRows([]);
|
|
11614
11835
|
return;
|
|
@@ -11636,24 +11857,24 @@ function AddressForm2({ onDone, initial: initial2, replaces }) {
|
|
|
11636
11857
|
const storeError = useDeliveryStore((s2) => s2.error);
|
|
11637
11858
|
const refusedZone = useDeliveryStore((s2) => s2.refusedZone);
|
|
11638
11859
|
const subtotal = selectSubtotal(useCartStore());
|
|
11639
|
-
const [cep, setCep] =
|
|
11640
|
-
const [number, setNumber] =
|
|
11641
|
-
const [complement, setComplement] =
|
|
11642
|
-
const [reference, setReference] =
|
|
11643
|
-
const [label, setLabel] =
|
|
11644
|
-
const [touched, setTouched] =
|
|
11645
|
-
const numberRef =
|
|
11860
|
+
const [cep, setCep] = React39__default.useState(initial2?.postalCode ? formatPostalCode(initial2.postalCode) : "");
|
|
11861
|
+
const [number, setNumber] = React39__default.useState(initial2?.number ?? "");
|
|
11862
|
+
const [complement, setComplement] = React39__default.useState(initial2?.complement ?? "");
|
|
11863
|
+
const [reference, setReference] = React39__default.useState(initial2?.reference ?? "");
|
|
11864
|
+
const [label, setLabel] = React39__default.useState(initial2?.label ?? "");
|
|
11865
|
+
const [touched, setTouched] = React39__default.useState(false);
|
|
11866
|
+
const numberRef = React39__default.useRef(null);
|
|
11646
11867
|
const digits = normalizePostalCode(cep);
|
|
11647
11868
|
const found = Boolean(looked) && normalizePostalCode(looked.postalCode) === digits;
|
|
11648
|
-
|
|
11869
|
+
React39__default.useEffect(() => {
|
|
11649
11870
|
if (found) numberRef.current?.focus();
|
|
11650
11871
|
}, [found]);
|
|
11651
11872
|
async function lookUp() {
|
|
11652
11873
|
if (digits.length !== 8) return;
|
|
11653
11874
|
await resolve(digits, subtotal);
|
|
11654
11875
|
}
|
|
11655
|
-
const prefilled =
|
|
11656
|
-
|
|
11876
|
+
const prefilled = React39__default.useRef(false);
|
|
11877
|
+
React39__default.useEffect(() => {
|
|
11657
11878
|
if (prefilled.current || !initial2?.postalCode) return;
|
|
11658
11879
|
prefilled.current = true;
|
|
11659
11880
|
if (!found) void lookUp();
|
|
@@ -11869,7 +12090,7 @@ function AccountDrawer({ onClose, onSignIn, onAddresses, onShowHours }) {
|
|
|
11869
12090
|
const session = useSessionStore();
|
|
11870
12091
|
const signedIn = Boolean(session.email);
|
|
11871
12092
|
const name = session.name || session.email?.split("@")[0] || "";
|
|
11872
|
-
|
|
12093
|
+
React39__default.useEffect(() => {
|
|
11873
12094
|
const onKey = (event) => {
|
|
11874
12095
|
if (event.key === "Escape") onClose();
|
|
11875
12096
|
};
|
|
@@ -11953,19 +12174,30 @@ function AccountDrawer({ onClose, onSignIn, onAddresses, onShowHours }) {
|
|
|
11953
12174
|
function MenuPage() {
|
|
11954
12175
|
const config = useStorefrontConfig();
|
|
11955
12176
|
const addItem = useCartStore((s2) => s2.addItem);
|
|
11956
|
-
const [openProduct, setOpenProduct] =
|
|
11957
|
-
|
|
11958
|
-
|
|
11959
|
-
|
|
11960
|
-
|
|
11961
|
-
|
|
11962
|
-
|
|
11963
|
-
|
|
12177
|
+
const [openProduct, setOpenProduct] = React39__default.useState(null);
|
|
12178
|
+
React39__default.useEffect(() => {
|
|
12179
|
+
if (!openProduct) return;
|
|
12180
|
+
trackStorefront("product_viewed", {
|
|
12181
|
+
product_id: openProduct.id,
|
|
12182
|
+
product_name: openProduct.name,
|
|
12183
|
+
slug: openProduct.slug,
|
|
12184
|
+
price: openProduct.price,
|
|
12185
|
+
in_stock: openProduct.inventoryCount > 0,
|
|
12186
|
+
surface: "menu_sheet"
|
|
12187
|
+
});
|
|
12188
|
+
}, [openProduct?.id]);
|
|
12189
|
+
const [showHours, setShowHours] = React39__default.useState(false);
|
|
12190
|
+
const [showClosed, setShowClosed] = React39__default.useState(false);
|
|
12191
|
+
const [showAddress, setShowAddress] = React39__default.useState(false);
|
|
12192
|
+
const [showAccount, setShowAccount] = React39__default.useState(false);
|
|
12193
|
+
const [showSignIn, setShowSignIn] = React39__default.useState(false);
|
|
12194
|
+
const [showSchedule, setShowSchedule] = React39__default.useState(false);
|
|
12195
|
+
const [query, setQuery] = React39__default.useState("");
|
|
11964
12196
|
const serviceState = useServiceStore();
|
|
11965
12197
|
const refreshService = useServiceStore((s2) => s2.refresh);
|
|
11966
12198
|
const paused = Boolean(config.delivery?.paused);
|
|
11967
12199
|
const isOpen = selectIsOpen(serviceState) && !paused;
|
|
11968
|
-
|
|
12200
|
+
React39__default.useEffect(() => {
|
|
11969
12201
|
void refreshService();
|
|
11970
12202
|
}, [refreshService]);
|
|
11971
12203
|
const cart = useCartStore();
|
|
@@ -11987,7 +12219,7 @@ function MenuPage() {
|
|
|
11987
12219
|
const loading = products.status === "loading" || products.status === "idle";
|
|
11988
12220
|
const items = products.data ?? [];
|
|
11989
12221
|
const cats = categories.data ?? [];
|
|
11990
|
-
const allSections =
|
|
12222
|
+
const allSections = React39__default.useMemo(() => {
|
|
11991
12223
|
const byCategory = /* @__PURE__ */ new Map();
|
|
11992
12224
|
const loose = [];
|
|
11993
12225
|
for (const p of items) {
|
|
@@ -12015,7 +12247,7 @@ function MenuPage() {
|
|
|
12015
12247
|
}
|
|
12016
12248
|
return ordered;
|
|
12017
12249
|
}, [items, cats]);
|
|
12018
|
-
const highlights =
|
|
12250
|
+
const highlights = React39__default.useMemo(
|
|
12019
12251
|
() => pickHighlights(items, {
|
|
12020
12252
|
listingFeaturedIds: featured.data?.listing,
|
|
12021
12253
|
menuFeaturedIds: featured.data?.menu,
|
|
@@ -12024,7 +12256,7 @@ function MenuPage() {
|
|
|
12024
12256
|
[items, featured.data, config.delivery?.highlightSlugs]
|
|
12025
12257
|
);
|
|
12026
12258
|
const normalized = query.trim().toLowerCase();
|
|
12027
|
-
const sections =
|
|
12259
|
+
const sections = React39__default.useMemo(() => {
|
|
12028
12260
|
if (!normalized) return allSections;
|
|
12029
12261
|
return allSections.map((section) => ({
|
|
12030
12262
|
...section,
|
|
@@ -12197,7 +12429,7 @@ function MenuPage() {
|
|
|
12197
12429
|
);
|
|
12198
12430
|
}
|
|
12199
12431
|
function BottomBarSpace() {
|
|
12200
|
-
|
|
12432
|
+
React39__default.useEffect(() => {
|
|
12201
12433
|
const root = document.documentElement;
|
|
12202
12434
|
root.style.setProperty("--fayz-bottom-bar", "4.5rem");
|
|
12203
12435
|
return () => {
|
|
@@ -12488,7 +12720,7 @@ function OrderConfirmationPage({ orderId }) {
|
|
|
12488
12720
|
const [loading, setLoading] = useState(true);
|
|
12489
12721
|
const money = (v) => formatMoney(v, config.currency, config.locale);
|
|
12490
12722
|
useStorefrontHead({ title: order ? `Pedido #${order.orderNumber} \u2014 ${config.name}` : config.name });
|
|
12491
|
-
const reload =
|
|
12723
|
+
const reload = React39__default.useCallback(() => {
|
|
12492
12724
|
let cancelled = false;
|
|
12493
12725
|
getShopProvider().getOrder(orderId).then((o) => {
|
|
12494
12726
|
if (!cancelled) setOrder(o);
|
|
@@ -12517,7 +12749,7 @@ function OrderConfirmationPage({ orderId }) {
|
|
|
12517
12749
|
] }, column)) }),
|
|
12518
12750
|
/* @__PURE__ */ jsxs("div", { className: "mt-6", children: [
|
|
12519
12751
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-32" }),
|
|
12520
|
-
/* @__PURE__ */ jsx("div", { className: "mt-3 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(
|
|
12752
|
+
/* @__PURE__ */ jsx("div", { className: "mt-3 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(React39__default.Fragment, { children: [
|
|
12521
12753
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-7 shrink-0 rounded-full" }),
|
|
12522
12754
|
node < 3 && /* @__PURE__ */ jsx(Skeleton, { className: "h-px flex-1" })
|
|
12523
12755
|
] }, node)) })
|
|
@@ -12804,7 +13036,7 @@ function OrdersPanel() {
|
|
|
12804
13036
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-24 rounded-full" })
|
|
12805
13037
|
] }),
|
|
12806
13038
|
/* @__PURE__ */ jsx(Skeleton, { className: "mt-2 h-3 w-20" }),
|
|
12807
|
-
/* @__PURE__ */ jsx("div", { className: "mt-4 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(
|
|
13039
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(React39__default.Fragment, { children: [
|
|
12808
13040
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-6 shrink-0 rounded-full" }),
|
|
12809
13041
|
node < 3 && /* @__PURE__ */ jsx(Skeleton, { className: "h-px flex-1" })
|
|
12810
13042
|
] }, node)) }),
|
|
@@ -12883,7 +13115,7 @@ function ProfilePanel() {
|
|
|
12883
13115
|
const [saving, setSaving] = useState(false);
|
|
12884
13116
|
const [saved, setSaved] = useState(false);
|
|
12885
13117
|
const [error, setError] = useState(null);
|
|
12886
|
-
|
|
13118
|
+
React39__default.useEffect(() => {
|
|
12887
13119
|
if (!supported) return;
|
|
12888
13120
|
let cancelled = false;
|
|
12889
13121
|
provider.getMyProfile().then((p) => {
|
|
@@ -13176,7 +13408,7 @@ function PolicyPage({ kind }) {
|
|
|
13176
13408
|
] }) })
|
|
13177
13409
|
] });
|
|
13178
13410
|
}
|
|
13179
|
-
var StorefrontErrorBoundary = class extends
|
|
13411
|
+
var StorefrontErrorBoundary = class extends React39__default.Component {
|
|
13180
13412
|
constructor() {
|
|
13181
13413
|
super(...arguments);
|
|
13182
13414
|
this.state = { error: null };
|
|
@@ -13432,7 +13664,8 @@ function StorefrontShellBody({ pathOverride }) {
|
|
|
13432
13664
|
/* @__PURE__ */ jsx(StorefrontErrorBoundary, { children: /* @__PURE__ */ jsx(RouteSwitch, { path }) }, path),
|
|
13433
13665
|
!focused && config.features.cart && /* @__PURE__ */ jsx(CartDrawer, {}),
|
|
13434
13666
|
!focused && /* @__PURE__ */ jsx(footer.Component, { ...chromeProps, ...footer.props }),
|
|
13435
|
-
/* @__PURE__ */ jsx(Toaster, {})
|
|
13667
|
+
/* @__PURE__ */ jsx(Toaster, {}),
|
|
13668
|
+
/* @__PURE__ */ jsx(StorefrontAnalytics, { config, path })
|
|
13436
13669
|
] });
|
|
13437
13670
|
if (Shell) {
|
|
13438
13671
|
return /* @__PURE__ */ jsx(Shell, { ...chromeProps, ...shellProps, children: body });
|
|
@@ -14792,6 +15025,6 @@ ${formatErrors(report.errors)}`;
|
|
|
14792
15025
|
return config;
|
|
14793
15026
|
}
|
|
14794
15027
|
|
|
14795
|
-
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 };
|
|
14796
|
-
//# sourceMappingURL=chunk-
|
|
14797
|
-
//# sourceMappingURL=chunk-
|
|
15028
|
+
export { AddressForm, AddressSheet, AddressStrip, BEFORE_PLACE_ORDER_VALVE, BLOCK_STRUCTURAL_KEYS, BUYER_COUNTRY_COOKIE, BenefitsRow, BlockDataError, CART_LINE_ANNOTATION_POINT, CATALOG_BODY_BLOCK, CHECKOUT_FIELD_POINT, CartDrawer, CatalogPage, CategoryShowcase, CheckoutPage, ClosedStoreDialog, CollectionCta, CollectionHero, ContentPage, CountdownBand, CountrySelect, DeliverToPicker, EmailConfirmationRequiredError, EntityListBlock, FaqSection, FiltersPanel, FormBlock, HeroSection, ImageTiles, ItemSheet, Link, MESSAGES, ManifestoBlock, MediaCarousel, MenuItemRow, MenuPage, MenuToolbar, MotifStrip, MyPurchasesPage, NewsletterBand, ORDER_METADATA_POINT, OrderConfirmationPage, OrderTrackingTimeline, PAGE_DATA_SCRIPT_ID, PLACEHOLDER_ASPECTS, PRODUCT_BODY_BLOCK, PRODUCT_CARD_BADGE_POINT, PageDataScope, PaymentTerms, Price, ProductCard, ProductDetailPage, ProductEnquiryForm, ProductGallery, ProductGrid, ProductOptionSelector, ProductRail, ProductReviews, ProductSlider, ProductSpecs, ProductSpotlight, PromoBanner, QuantityInput, Reveal, STOREFRONT_COMPONENT_KEYS, STOREFRONT_PAGE_KINDS, STOREFRONT_SLOTS, STORE_BACKEND_PROVIDERS, STORE_COMMERCE_MODES, STORE_DOCUMENT_KIND, STORE_PAYMENT_METHOD_KINDS, STORE_PAYMENT_MODES, STORE_ROUTE_CHROMES, STORE_ROUTE_KINDS, STORE_SECTIONS, STORE_SECTION_NAMES, ScheduleSheet, SealsBand, SearchOverlay, ServiceHoursModal, Slot, SmoothImage, StepsSection, StoreCover, StorefrontAnalytics, StorefrontConfigHost, StorefrontConfigProvider, StorefrontFooter, StorefrontHeader, StorefrontPage, StorefrontRouterProvider, StorefrontShell, StorefrontThemeStyle, StoryQuote, THEME_SCALE_FIELDS, THEME_SCALE_VAR_PREFIX, TID, Testimonials, TierCards, applyDeliveryPolicy, applyStoreSettings, bannerPlaceholder, blockInstanceId, buildEnquiryFromForm, checkPageBlocks, collectDataNeeds, collectOrderMetadata, contentPagePath, createStorefront, createStorefrontApp, currentStaticRenderPass, defaultPageBlocks, entityListBlockMeta, establishCustomerSession, exportStore, formatMoney, formatProductOptionSelection, getCartLineAnnotations, getCheckoutFieldContributions, getCustomerAuthAdapter, getProductCardBadges, getProductOptionGroups, hydrateStoreDocument, hydratedEntriesFor, identifyStorefrontBuyer, initStorefrontRuntime, isJsonValue, isKnownPath, isNestedBlockRef, isPublicPath, isRecord, listSlots, marketForCountry, marketUnitPrice, matchContentPage, matchPath, matchesFacets, mergeCollectionFacet, mergePageTheme, navigateTo, nextMilestone, normalizeLanguage, normalizeProductOptionSelection, onStorefrontEvent, orderGalleryImages, overrideComponent, overrideProps, pageSeo, pageThemeSelector, pickProductCardImage, placeStorefrontOrder, prefersReducedMotion, primaryImageUrl, productCardComponentContract, productJsonLd, productOptionSelectionKey, productPlaceholder, productSeo, readHydratedPageData, registerStorefrontBlocks, registerStorefrontEntities, registerStorefrontExtensionPoints, registerStorefrontLoaders, resetPageDiagnostics, resetProductOptionsDeprecationWarnings, resetStorefrontExtensionPoints, resolveAuthAdapter, resolveConfig, resolveDataParams, resolveOverride, resolvePageData, resolvePageDataNeed, resolvePaymentTerms, resolveStorefrontProvider, resolveStorefrontRoute, resolveVariantForSelection, roundCents, routePathParams, runBeforePlaceOrderValve, sectionToJsonSchema, sectionsToBlocks, selectCount, selectDiscountTotal, selectIsOpen, selectRequiresShipping, selectShipping, selectShowsHours, selectSubtotal, selectTotal, selectionPrice, serializePageData, shellRouterAdapter, signInByEmail, signOutCustomer, signUpCustomer, slugifyStoreName, startStorefrontPostHog, storeBuyerId, storefrontComponentContracts, storefrontPaths, themeToCss, toBlockNodes, toFacetMap, trackStorefront, translate, useBlockData, useBuyerCountry, useBuyerStore, useCartStore, useCatalogStore, useCategories, useDeliveryStore, useDiscountValidator, useEnquiry, useHashPath, useInView, useLoader, useMarketProduct, useMarketStore, useMyOrders, useNavigate, usePopOnChange, useProduct, useProducts, useRoutePath, useRouterAdapter, useScrollToTopOnNavigate, useScrolled, useServiceStore, useSessionStore, useSlotContext, useStorefrontActions, useStorefrontConfig, useStorefrontConfigOptional, useStorefrontHead, useStorefrontPage, useStorefrontPageOptional, useT, usedSlots, validateStore, withFacet, withMarketPrice, withStaticRenderPass };
|
|
15029
|
+
//# sourceMappingURL=chunk-3XECLBVJ.js.map
|
|
15030
|
+
//# sourceMappingURL=chunk-3XECLBVJ.js.map
|