@fayz-ai/storefront 0.7.0 → 0.8.2
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/README.md +3 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/components/CartDrawer.d.ts.map +1 -1
- package/dist/components/DeliveryEstimator.d.ts +17 -0
- package/dist/components/DeliveryEstimator.d.ts.map +1 -0
- package/dist/components/ProductGallery.d.ts +22 -0
- package/dist/components/ProductGallery.d.ts.map +1 -0
- package/dist/components/StorefrontHeader.d.ts.map +1 -1
- package/dist/config.d.ts +8 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/createStorefrontApp.d.ts.map +1 -1
- package/dist/index.cjs +886 -370
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +790 -275
- package/dist/index.js.map +1 -1
- package/dist/pages/CheckoutPage.d.ts.map +1 -1
- package/dist/pages/ProductDetailPage.d.ts.map +1 -1
- package/dist/presets.d.ts +5 -0
- package/dist/presets.d.ts.map +1 -1
- package/dist/stores/cart.store.d.ts +21 -0
- package/dist/stores/cart.store.d.ts.map +1 -1
- package/dist/stores/delivery.store.d.ts +64 -0
- package/dist/stores/delivery.store.d.ts.map +1 -0
- package/dist/testids.d.ts +12 -0
- package/dist/testids.d.ts.map +1 -1
- package/dist/theme.d.ts +18 -2
- package/dist/theme.d.ts.map +1 -1
- package/dist/workflows/checkout.d.ts +5 -2
- package/dist/workflows/checkout.d.ts.map +1 -1
- package/package.json +13 -7
- package/src/auth.ts +57 -1
- package/src/components/CartDrawer.tsx +23 -1
- package/src/components/DeliveryEstimator.tsx +157 -0
- package/src/components/ProductGallery.tsx +174 -0
- package/src/components/StorefrontHeader.tsx +35 -8
- package/src/config.ts +15 -3
- package/src/createStorefrontApp.tsx +18 -1
- package/src/index.ts +1 -0
- package/src/pages/CheckoutPage.tsx +240 -134
- package/src/pages/ProductDetailPage.tsx +17 -13
- package/src/presets.ts +66 -0
- package/src/stores/cart.store.ts +37 -1
- package/src/stores/delivery.store.ts +152 -0
- package/src/testids.ts +13 -0
- package/src/theme.ts +33 -3
- package/src/workflows/checkout.ts +34 -6
package/dist/index.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getShopProvider, setShopProvider } from '@fayz-ai/shop/runtime';
|
|
2
2
|
import { createMockShopProvider } from '@fayz-ai/shop/mock';
|
|
3
3
|
import { createAuthRuntime, createMockAuthAdapter } from '@fayz-ai/plugin-auth';
|
|
4
|
+
import { setShopAccessTokenResolver } from '@fayz-ai/sdk/shop';
|
|
4
5
|
import { create } from 'zustand';
|
|
5
6
|
import { persist } from 'zustand/middleware';
|
|
6
|
-
import
|
|
7
|
-
import { hashRouterAdapter, registerScaffold, registerBlock, renderBlocks, defineApp } from '@fayz-ai/core';
|
|
7
|
+
import React7, { createContext, useState, useRef, useEffect, useMemo, useContext, useCallback } from 'react';
|
|
8
|
+
import { hashRouterAdapter, normalizePostalCode, lookupPostalCode, registerScaffold, registerBlock, formatPostalCode, renderBlocks, defineApp } from '@fayz-ai/core';
|
|
8
9
|
export { getSupabaseClientOptional, renderApp } from '@fayz-ai/core';
|
|
9
10
|
import * as LucideIcons from 'lucide-react';
|
|
10
|
-
import { ChevronLeft, ChevronRight, ShoppingBag, X, Trash2, Phone, Mail, Search, User, UserCircle, Package, CreditCard, LogOut, Truck, RefreshCcw, ShieldCheck, Lock, Minus, Plus, Info, AlertCircle, Check, Send, MessageCircle,
|
|
11
|
+
import { ChevronLeft, ChevronRight, ShoppingBag, X, Trash2, Phone, Mail, Search, User, UserCircle, Package, CreditCard, LogOut, Truck, RefreshCcw, ShieldCheck, Lock, Minus, Plus, MapPin, Info, AlertCircle, Check, Send, MessageCircle, PackageCheck, QrCode, XCircle, RotateCcw, Clock } from 'lucide-react';
|
|
11
12
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
12
13
|
import { validateDiscount } from '@fayz-ai/shop';
|
|
13
14
|
|
|
@@ -53,10 +54,23 @@ function resolveAuthAdapter(configured, fallback) {
|
|
|
53
54
|
}
|
|
54
55
|
}).adapter;
|
|
55
56
|
}
|
|
57
|
+
var _accessToken = null;
|
|
58
|
+
var _hadAuthUser = false;
|
|
59
|
+
async function syncAccessToken(adapter2) {
|
|
60
|
+
try {
|
|
61
|
+
const existing = await adapter2.getSession();
|
|
62
|
+
_accessToken = existing?.session.accessToken ?? null;
|
|
63
|
+
} catch {
|
|
64
|
+
_accessToken = null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
56
67
|
function initCustomerAuth(adapter2) {
|
|
57
68
|
_adapter = adapter2;
|
|
69
|
+
setShopAccessTokenResolver(() => _accessToken);
|
|
58
70
|
adapter2.getSession().then((existing) => {
|
|
71
|
+
_accessToken = existing?.session.accessToken ?? null;
|
|
59
72
|
if (!existing) return;
|
|
73
|
+
_hadAuthUser = true;
|
|
60
74
|
const store = useSessionStore.getState();
|
|
61
75
|
if (store.email !== existing.user.email) {
|
|
62
76
|
void linkCustomer(existing.user);
|
|
@@ -64,7 +78,16 @@ function initCustomerAuth(adapter2) {
|
|
|
64
78
|
}).catch(() => {
|
|
65
79
|
});
|
|
66
80
|
adapter2.onAuthStateChange((user) => {
|
|
67
|
-
if (!user)
|
|
81
|
+
if (!user) {
|
|
82
|
+
_accessToken = null;
|
|
83
|
+
if (_hadAuthUser) {
|
|
84
|
+
_hadAuthUser = false;
|
|
85
|
+
useSessionStore.getState().signOut();
|
|
86
|
+
}
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
_hadAuthUser = true;
|
|
90
|
+
void syncAccessToken(adapter2);
|
|
68
91
|
});
|
|
69
92
|
}
|
|
70
93
|
function getCustomerAuthAdapter() {
|
|
@@ -100,6 +123,8 @@ async function establishCustomerSession(email, opts) {
|
|
|
100
123
|
if (opts?.password) {
|
|
101
124
|
const adapter2 = getCustomerAuthAdapter();
|
|
102
125
|
const session = await adapter2.signIn(normalized, opts.password);
|
|
126
|
+
_accessToken = session.accessToken ?? null;
|
|
127
|
+
_hadAuthUser = true;
|
|
103
128
|
return linkCustomer(session.user.email ? session.user : { ...session.user, email: normalized }, opts.name);
|
|
104
129
|
}
|
|
105
130
|
return linkCustomer({ email: normalized }, opts?.name);
|
|
@@ -111,12 +136,16 @@ async function signUpCustomer(email, password, name) {
|
|
|
111
136
|
const adapter2 = getCustomerAuthAdapter();
|
|
112
137
|
const normalized = email.trim().toLowerCase();
|
|
113
138
|
const session = await adapter2.signUp(normalized, password, name);
|
|
139
|
+
_accessToken = session.accessToken ?? null;
|
|
140
|
+
_hadAuthUser = true;
|
|
114
141
|
return linkCustomer(session.user.email ? session.user : { ...session.user, email: normalized }, name);
|
|
115
142
|
}
|
|
116
143
|
async function signOutCustomer() {
|
|
117
144
|
try {
|
|
118
145
|
await getCustomerAuthAdapter().signOut();
|
|
119
146
|
} finally {
|
|
147
|
+
_accessToken = null;
|
|
148
|
+
_hadAuthUser = false;
|
|
120
149
|
useSessionStore.getState().signOut();
|
|
121
150
|
}
|
|
122
151
|
}
|
|
@@ -129,7 +158,10 @@ function resolveConfig(config) {
|
|
|
129
158
|
currency: config.currency ?? "BRL",
|
|
130
159
|
locale: config.locale ?? "pt-BR",
|
|
131
160
|
shipping: { flatRate: config.shipping?.flatRate ?? 0, freeAbove: config.shipping?.freeAbove },
|
|
132
|
-
payments: {
|
|
161
|
+
payments: {
|
|
162
|
+
mode: config.payments?.mode ?? "mock",
|
|
163
|
+
methods: config.payments?.methods?.length ? config.payments.methods : ["pix", "credit_card", "cash"]
|
|
164
|
+
},
|
|
133
165
|
commerceMode,
|
|
134
166
|
enquiry: {
|
|
135
167
|
label: config.enquiry?.label ?? "Contact me",
|
|
@@ -204,93 +236,7 @@ function matchPath(pattern, path) {
|
|
|
204
236
|
return params;
|
|
205
237
|
}
|
|
206
238
|
function Link({ to, children, ...rest }) {
|
|
207
|
-
return
|
|
208
|
-
}
|
|
209
|
-
var RADIUS_MAP = {
|
|
210
|
-
none: { button: "0px", card: "0px", input: "0px" },
|
|
211
|
-
soft: { button: "6px", card: "10px", input: "6px" },
|
|
212
|
-
round: { button: "10px", card: "16px", input: "10px" },
|
|
213
|
-
pill: { button: "999px", card: "20px", input: "999px" }
|
|
214
|
-
};
|
|
215
|
-
var COLOR_VAR_MAP = {
|
|
216
|
-
background: "--background",
|
|
217
|
-
foreground: "--foreground",
|
|
218
|
-
primary: "--primary",
|
|
219
|
-
primaryForeground: "--primary-foreground",
|
|
220
|
-
card: "--card",
|
|
221
|
-
cardForeground: "--card-foreground",
|
|
222
|
-
muted: "--muted",
|
|
223
|
-
mutedForeground: "--muted-foreground",
|
|
224
|
-
border: "--border",
|
|
225
|
-
headerBackground: "--sf-header-bg",
|
|
226
|
-
headerForeground: "--sf-header-fg",
|
|
227
|
-
announcementBackground: "--sf-announcement-bg",
|
|
228
|
-
announcementForeground: "--sf-announcement-fg"
|
|
229
|
-
};
|
|
230
|
-
function themeToCss(theme) {
|
|
231
|
-
const lines = [];
|
|
232
|
-
for (const [key, cssVar] of Object.entries(COLOR_VAR_MAP)) {
|
|
233
|
-
const value = theme.colors?.[key];
|
|
234
|
-
if (value) lines.push(`${cssVar}: ${value};`);
|
|
235
|
-
}
|
|
236
|
-
if (!theme.colors?.headerBackground && theme.colors?.background) {
|
|
237
|
-
lines.push(`--sf-header-bg: ${theme.colors.background};`);
|
|
238
|
-
}
|
|
239
|
-
if (!theme.colors?.headerForeground && theme.colors?.foreground) {
|
|
240
|
-
lines.push(`--sf-header-fg: ${theme.colors.foreground};`);
|
|
241
|
-
}
|
|
242
|
-
if (theme.font) {
|
|
243
|
-
const fallback = theme.font.fallback ?? "sans-serif";
|
|
244
|
-
lines.push(`--font-family: '${theme.font.body}', ${fallback};`);
|
|
245
|
-
lines.push(`--sf-font-heading: '${theme.font.heading}', ${fallback};`);
|
|
246
|
-
}
|
|
247
|
-
const radius = RADIUS_MAP[theme.radius ?? "soft"];
|
|
248
|
-
lines.push(`--button-radius: ${radius.button};`);
|
|
249
|
-
lines.push(`--card-radius: ${radius.card};`);
|
|
250
|
-
lines.push(`--input-radius: ${radius.input};`);
|
|
251
|
-
lines.push(`--sf-radius-button: ${radius.button};`);
|
|
252
|
-
lines.push(`--sf-radius-card: ${radius.card};`);
|
|
253
|
-
lines.push(`--sf-radius-input: ${radius.input};`);
|
|
254
|
-
let css = `:root {
|
|
255
|
-
${lines.join("\n ")}
|
|
256
|
-
}
|
|
257
|
-
`;
|
|
258
|
-
css += `body { font-family: var(--font-family); }
|
|
259
|
-
`;
|
|
260
|
-
css += `h1, h2, h3, h4, .sf-heading { font-family: var(--sf-font-heading, var(--font-family)); }
|
|
261
|
-
`;
|
|
262
|
-
if (theme.uppercaseButtons) {
|
|
263
|
-
css += `.sf-cta { text-transform: uppercase; letter-spacing: 0.08em; }
|
|
264
|
-
`;
|
|
265
|
-
}
|
|
266
|
-
if (theme.header?.uppercaseNav) {
|
|
267
|
-
css += `.sf-nav-link { text-transform: uppercase; letter-spacing: 0.06em; font-size: 0.8rem; }
|
|
268
|
-
`;
|
|
269
|
-
}
|
|
270
|
-
return css;
|
|
271
|
-
}
|
|
272
|
-
function googleFontsHref(theme) {
|
|
273
|
-
if (!theme.font) return null;
|
|
274
|
-
const families = theme.font.googleFonts ?? [theme.font.heading, theme.font.body];
|
|
275
|
-
const unique = [...new Set(families)];
|
|
276
|
-
const params = unique.map((f) => `family=${encodeURIComponent(f).replace(/%20/g, "+")}:wght@300;400;500;600;700`).join("&");
|
|
277
|
-
return `https://fonts.googleapis.com/css2?${params}&display=swap`;
|
|
278
|
-
}
|
|
279
|
-
function StorefrontThemeStyle({ theme }) {
|
|
280
|
-
const fontsHref = googleFontsHref(theme);
|
|
281
|
-
useEffect(() => {
|
|
282
|
-
if (!fontsHref) return;
|
|
283
|
-
const id = "sf-theme-fonts";
|
|
284
|
-
let link = document.getElementById(id);
|
|
285
|
-
if (!link) {
|
|
286
|
-
link = document.createElement("link");
|
|
287
|
-
link.id = id;
|
|
288
|
-
link.rel = "stylesheet";
|
|
289
|
-
document.head.appendChild(link);
|
|
290
|
-
}
|
|
291
|
-
link.href = fontsHref;
|
|
292
|
-
}, [fontsHref]);
|
|
293
|
-
return React6.createElement("style", { "data-sf-theme": theme.name }, themeToCss(theme));
|
|
239
|
+
return React7.createElement("a", { href: `#${to}`, ...rest }, children);
|
|
294
240
|
}
|
|
295
241
|
|
|
296
242
|
// src/format.ts
|
|
@@ -300,6 +246,87 @@ function formatMoney(value, currency = "BRL", locale = "pt-BR") {
|
|
|
300
246
|
function roundCents(value) {
|
|
301
247
|
return Math.round(value * 100) / 100;
|
|
302
248
|
}
|
|
249
|
+
var EMPTY = {
|
|
250
|
+
postalCode: "",
|
|
251
|
+
address: null,
|
|
252
|
+
options: [],
|
|
253
|
+
selectedZoneId: null,
|
|
254
|
+
status: "idle",
|
|
255
|
+
error: null
|
|
256
|
+
};
|
|
257
|
+
var useDeliveryStore = create()(
|
|
258
|
+
persist(
|
|
259
|
+
(set, get) => ({
|
|
260
|
+
...EMPTY,
|
|
261
|
+
async resolve(postalCode, subtotal) {
|
|
262
|
+
const code = normalizePostalCode(postalCode);
|
|
263
|
+
if (code.length !== 8) {
|
|
264
|
+
set({ ...EMPTY, postalCode, status: "error", error: "Digite os 8 d\xEDgitos do CEP." });
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
set({ postalCode: code, status: "loading", error: null });
|
|
268
|
+
let options = [];
|
|
269
|
+
try {
|
|
270
|
+
options = await getShopProvider().quoteShipping?.(code, subtotal) ?? [];
|
|
271
|
+
} catch {
|
|
272
|
+
set({
|
|
273
|
+
...EMPTY,
|
|
274
|
+
postalCode: code,
|
|
275
|
+
status: "error",
|
|
276
|
+
error: "N\xE3o foi poss\xEDvel calcular o frete agora. Tente de novo."
|
|
277
|
+
});
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
let address = null;
|
|
281
|
+
let notFound = false;
|
|
282
|
+
try {
|
|
283
|
+
address = await lookupPostalCode(code);
|
|
284
|
+
notFound = address === null;
|
|
285
|
+
} catch {
|
|
286
|
+
address = null;
|
|
287
|
+
}
|
|
288
|
+
set({
|
|
289
|
+
postalCode: code,
|
|
290
|
+
address,
|
|
291
|
+
options,
|
|
292
|
+
selectedZoneId: options[0]?.zoneId ?? null,
|
|
293
|
+
// A store with no zones configured quotes nothing, and that must NOT
|
|
294
|
+
// read as "we don't deliver here" — it falls back to the store-wide
|
|
295
|
+
// flat rate, which the cart already knows how to show.
|
|
296
|
+
status: options.length > 0 ? "served" : "unserved",
|
|
297
|
+
// Reported alongside the price, not instead of it: the CEP may be
|
|
298
|
+
// mistyped even though its range is covered.
|
|
299
|
+
error: notFound ? "CEP n\xE3o encontrado. Confira os n\xFAmeros." : null
|
|
300
|
+
});
|
|
301
|
+
},
|
|
302
|
+
selectZone(zoneId) {
|
|
303
|
+
if (get().options.some((option) => option.zoneId === zoneId)) set({ selectedZoneId: zoneId });
|
|
304
|
+
},
|
|
305
|
+
clear() {
|
|
306
|
+
set({ ...EMPTY });
|
|
307
|
+
}
|
|
308
|
+
}),
|
|
309
|
+
{
|
|
310
|
+
name: "fayz.storefront.delivery.v1",
|
|
311
|
+
// Deliberately NOT persisting `options`: a rehydrated
|
|
312
|
+
// price would be shown as current without anything having quoted it. The
|
|
313
|
+
// address survives, the money is asked for again.
|
|
314
|
+
partialize: (state) => ({ postalCode: state.postalCode, address: state.address }),
|
|
315
|
+
onRehydrateStorage: () => (state) => {
|
|
316
|
+
if (state?.address) state.status = "idle";
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
)
|
|
320
|
+
);
|
|
321
|
+
function resolveOptionRate(option, subtotal) {
|
|
322
|
+
if (option.freeAbove != null && subtotal >= option.freeAbove) return 0;
|
|
323
|
+
return option.baseRate;
|
|
324
|
+
}
|
|
325
|
+
var selectQuotedShipping = (state, subtotal) => {
|
|
326
|
+
if (state.status !== "served") return null;
|
|
327
|
+
const option = state.options.find((o) => o.zoneId === state.selectedZoneId) ?? state.options[0];
|
|
328
|
+
return option ? resolveOptionRate(option, subtotal) : null;
|
|
329
|
+
};
|
|
303
330
|
|
|
304
331
|
// src/product-options.ts
|
|
305
332
|
function cleanValues(value) {
|
|
@@ -344,7 +371,7 @@ function productOptionSelectionKey(selection) {
|
|
|
344
371
|
// src/stores/cart.store.ts
|
|
345
372
|
var useCartStore = create()(
|
|
346
373
|
persist(
|
|
347
|
-
(set) => ({
|
|
374
|
+
(set, get) => ({
|
|
348
375
|
lines: [],
|
|
349
376
|
discountCode: null,
|
|
350
377
|
discountPercent: 0,
|
|
@@ -396,7 +423,16 @@ var useCartStore = create()(
|
|
|
396
423
|
clearDiscount: () => set({ discountCode: null, discountPercent: 0 }),
|
|
397
424
|
clear: () => set({ lines: [], discountCode: null, discountPercent: 0 }),
|
|
398
425
|
openDrawer: () => set({ isOpen: true }),
|
|
399
|
-
closeDrawer: () => set({ isOpen: false, justAddedLineId: null })
|
|
426
|
+
closeDrawer: () => set({ isOpen: false, justAddedLineId: null }),
|
|
427
|
+
reconcile: async (resolve) => {
|
|
428
|
+
const lines = get().lines;
|
|
429
|
+
if (lines.length === 0) return;
|
|
430
|
+
const keep = await Promise.all(
|
|
431
|
+
lines.map((line) => resolve(line).catch(() => true))
|
|
432
|
+
);
|
|
433
|
+
const kept = lines.filter((_, i) => keep[i]);
|
|
434
|
+
if (kept.length !== lines.length) set({ lines: kept });
|
|
435
|
+
}
|
|
400
436
|
}),
|
|
401
437
|
{
|
|
402
438
|
name: "fayz.storefront.cart.v1",
|
|
@@ -414,10 +450,108 @@ var selectDiscountTotal = (s) => roundCents(selectSubtotal(s) * (s.discountPerce
|
|
|
414
450
|
var selectShipping = (s, cfg) => {
|
|
415
451
|
if (s.lines.length === 0) return 0;
|
|
416
452
|
const subtotal = selectSubtotal(s);
|
|
453
|
+
const quoted = selectQuotedShipping(useDeliveryStore.getState(), subtotal);
|
|
454
|
+
if (quoted != null) return quoted;
|
|
417
455
|
if (cfg.shipping.freeAbove != null && subtotal >= cfg.shipping.freeAbove) return 0;
|
|
418
456
|
return cfg.shipping.flatRate;
|
|
419
457
|
};
|
|
420
458
|
var selectTotal = (s, cfg) => roundCents(selectSubtotal(s) - selectDiscountTotal(s) + selectShipping(s, cfg));
|
|
459
|
+
var RADIUS_MAP = {
|
|
460
|
+
none: { button: "0px", card: "0px", input: "0px" },
|
|
461
|
+
soft: { button: "6px", card: "10px", input: "6px" },
|
|
462
|
+
round: { button: "10px", card: "16px", input: "10px" },
|
|
463
|
+
pill: { button: "999px", card: "20px", input: "999px" }
|
|
464
|
+
};
|
|
465
|
+
var COLOR_VAR_MAP = {
|
|
466
|
+
background: "--background",
|
|
467
|
+
foreground: "--foreground",
|
|
468
|
+
primary: "--primary",
|
|
469
|
+
primaryForeground: "--primary-foreground",
|
|
470
|
+
card: "--card",
|
|
471
|
+
cardForeground: "--card-foreground",
|
|
472
|
+
muted: "--muted",
|
|
473
|
+
mutedForeground: "--muted-foreground",
|
|
474
|
+
border: "--border",
|
|
475
|
+
headerBackground: "--sf-header-bg",
|
|
476
|
+
headerForeground: "--sf-header-fg",
|
|
477
|
+
announcementBackground: "--sf-announcement-bg",
|
|
478
|
+
announcementForeground: "--sf-announcement-fg",
|
|
479
|
+
accent: "--sf-accent",
|
|
480
|
+
accentForeground: "--sf-accent-foreground"
|
|
481
|
+
};
|
|
482
|
+
function themeToCss(theme) {
|
|
483
|
+
const lines = [];
|
|
484
|
+
for (const [key, cssVar] of Object.entries(COLOR_VAR_MAP)) {
|
|
485
|
+
const value = theme.colors?.[key];
|
|
486
|
+
if (value) lines.push(`${cssVar}: ${value};`);
|
|
487
|
+
}
|
|
488
|
+
if (!theme.colors?.headerBackground && theme.colors?.background) {
|
|
489
|
+
lines.push(`--sf-header-bg: ${theme.colors.background};`);
|
|
490
|
+
}
|
|
491
|
+
if (!theme.colors?.headerForeground && theme.colors?.foreground) {
|
|
492
|
+
lines.push(`--sf-header-fg: ${theme.colors.foreground};`);
|
|
493
|
+
}
|
|
494
|
+
if (theme.font) {
|
|
495
|
+
const fallback = theme.font.fallback ?? "sans-serif";
|
|
496
|
+
lines.push(`--font-family: '${theme.font.body}', ${fallback};`);
|
|
497
|
+
lines.push(`--sf-font-heading: '${theme.font.heading}', ${fallback};`);
|
|
498
|
+
if (theme.font.display) lines.push(`--sf-font-display: '${theme.font.display}', ${fallback};`);
|
|
499
|
+
if (theme.font.serif) lines.push(`--sf-font-serif: '${theme.font.serif}', serif;`);
|
|
500
|
+
}
|
|
501
|
+
for (const [key, value] of Object.entries(theme.tokens ?? {})) {
|
|
502
|
+
const name = key.startsWith("--") ? key : `--${key}`;
|
|
503
|
+
lines.push(`${name}: ${value};`);
|
|
504
|
+
}
|
|
505
|
+
const radius = RADIUS_MAP[theme.radius ?? "soft"];
|
|
506
|
+
lines.push(`--button-radius: ${radius.button};`);
|
|
507
|
+
lines.push(`--card-radius: ${radius.card};`);
|
|
508
|
+
lines.push(`--input-radius: ${radius.input};`);
|
|
509
|
+
lines.push(`--sf-radius-button: ${radius.button};`);
|
|
510
|
+
lines.push(`--sf-radius-card: ${radius.card};`);
|
|
511
|
+
lines.push(`--sf-radius-input: ${radius.input};`);
|
|
512
|
+
let css = `:root {
|
|
513
|
+
${lines.join("\n ")}
|
|
514
|
+
}
|
|
515
|
+
`;
|
|
516
|
+
css += `body { font-family: var(--font-family); }
|
|
517
|
+
`;
|
|
518
|
+
css += `h1, h2, h3, h4, .sf-heading { font-family: var(--sf-font-heading, var(--font-family)); }
|
|
519
|
+
`;
|
|
520
|
+
if (theme.uppercaseButtons) {
|
|
521
|
+
css += `.sf-cta { text-transform: uppercase; letter-spacing: 0.08em; }
|
|
522
|
+
`;
|
|
523
|
+
}
|
|
524
|
+
if (theme.header?.uppercaseNav) {
|
|
525
|
+
css += `.sf-nav-link { text-transform: uppercase; letter-spacing: 0.06em; font-size: 0.8rem; }
|
|
526
|
+
`;
|
|
527
|
+
}
|
|
528
|
+
return css;
|
|
529
|
+
}
|
|
530
|
+
function googleFontsHref(theme) {
|
|
531
|
+
if (!theme.font) return null;
|
|
532
|
+
const families = theme.font.googleFonts ?? [theme.font.heading, theme.font.body, theme.font.display, theme.font.serif].filter(
|
|
533
|
+
(f) => Boolean(f)
|
|
534
|
+
);
|
|
535
|
+
const unique = [...new Set(families)];
|
|
536
|
+
const params = unique.map((f) => `family=${encodeURIComponent(f).replace(/%20/g, "+")}:wght@300;400;500;600;700`).join("&");
|
|
537
|
+
return `https://fonts.googleapis.com/css2?${params}&display=swap`;
|
|
538
|
+
}
|
|
539
|
+
function StorefrontThemeStyle({ theme }) {
|
|
540
|
+
const fontsHref = googleFontsHref(theme);
|
|
541
|
+
useEffect(() => {
|
|
542
|
+
if (!fontsHref) return;
|
|
543
|
+
const id = "sf-theme-fonts";
|
|
544
|
+
let link = document.getElementById(id);
|
|
545
|
+
if (!link) {
|
|
546
|
+
link = document.createElement("link");
|
|
547
|
+
link.id = id;
|
|
548
|
+
link.rel = "stylesheet";
|
|
549
|
+
document.head.appendChild(link);
|
|
550
|
+
}
|
|
551
|
+
link.href = fontsHref;
|
|
552
|
+
}, [fontsHref]);
|
|
553
|
+
return React7.createElement("style", { "data-sf-theme": theme.name }, themeToCss(theme));
|
|
554
|
+
}
|
|
421
555
|
var initial = {
|
|
422
556
|
search: "",
|
|
423
557
|
categoryId: null,
|
|
@@ -526,6 +660,7 @@ function usePopOnChange(value) {
|
|
|
526
660
|
var TID = {
|
|
527
661
|
// header
|
|
528
662
|
headerSearch: "header-search",
|
|
663
|
+
headerSearchToggle: "header-search-toggle",
|
|
529
664
|
cartButton: "cart-button",
|
|
530
665
|
cartCount: "cart-count",
|
|
531
666
|
accountLink: "account-link",
|
|
@@ -581,6 +716,9 @@ var TID = {
|
|
|
581
716
|
pdpAddToCart: "pdp-add-to-cart",
|
|
582
717
|
pdpRoot: "pdp-root",
|
|
583
718
|
pdpGallery: "pdp-gallery",
|
|
719
|
+
pdpGalleryImage: "pdp-gallery-image",
|
|
720
|
+
pdpGalleryThumbs: "pdp-gallery-thumbs",
|
|
721
|
+
pdpGalleryThumb: "pdp-gallery-thumb",
|
|
584
722
|
pdpActions: "pdp-actions",
|
|
585
723
|
pdpEnquiryButton: "pdp-enquiry-button",
|
|
586
724
|
enquiryForm: "enquiry-form",
|
|
@@ -609,6 +747,15 @@ var TID = {
|
|
|
609
747
|
cartTotal: "cart-total",
|
|
610
748
|
goCheckout: "go-checkout",
|
|
611
749
|
cartEmpty: "cart-empty",
|
|
750
|
+
// delivery estimate (product page + cart)
|
|
751
|
+
deliveryEstimator: "delivery-estimator",
|
|
752
|
+
deliveryCepInput: "delivery-cep-input",
|
|
753
|
+
deliveryCepSubmit: "delivery-cep-submit",
|
|
754
|
+
deliveryOption: "delivery-option",
|
|
755
|
+
deliveryUnserved: "delivery-unserved",
|
|
756
|
+
deliveryError: "delivery-error",
|
|
757
|
+
deliveryAddress: "delivery-address",
|
|
758
|
+
deliveryClear: "delivery-clear",
|
|
612
759
|
// checkout
|
|
613
760
|
checkoutEmail: "checkout-email",
|
|
614
761
|
checkoutName: "checkout-name",
|
|
@@ -714,12 +861,26 @@ function UtilityBar() {
|
|
|
714
861
|
/* @__PURE__ */ jsx("span", { className: "ml-auto flex items-center gap-4", children: social?.map((s) => /* @__PURE__ */ jsx("a", { href: s.href, target: "_blank", rel: "noreferrer", className: "hover:underline", children: s.label }, s.href)) })
|
|
715
862
|
] }) });
|
|
716
863
|
}
|
|
717
|
-
function SearchInput({ className }) {
|
|
864
|
+
function SearchInput({ className, iconOnly = false }) {
|
|
718
865
|
const config = useStorefrontConfig();
|
|
719
866
|
const search = useCatalogStore((s) => s.search);
|
|
720
867
|
const setSearch = useCatalogStore((s) => s.setSearch);
|
|
721
868
|
const path = useHashPath();
|
|
722
|
-
|
|
869
|
+
const [open, setOpen] = useState(false);
|
|
870
|
+
if (iconOnly && !open) {
|
|
871
|
+
return /* @__PURE__ */ jsx(
|
|
872
|
+
"button",
|
|
873
|
+
{
|
|
874
|
+
type: "button",
|
|
875
|
+
"aria-label": "Buscar produtos",
|
|
876
|
+
"data-testid": TID.headerSearchToggle,
|
|
877
|
+
onClick: () => setOpen(true),
|
|
878
|
+
className: "rounded-full p-2.5 transition-opacity hover:opacity-70",
|
|
879
|
+
children: /* @__PURE__ */ jsx(Search, { className: "h-5 w-5" })
|
|
880
|
+
}
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
return /* @__PURE__ */ jsxs("div", { className: `relative ${iconOnly ? "w-full max-w-xs" : className ?? ""}`, children: [
|
|
723
884
|
/* @__PURE__ */ jsx(Search, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 opacity-60" }),
|
|
724
885
|
/* @__PURE__ */ jsx(
|
|
725
886
|
"input",
|
|
@@ -728,10 +889,17 @@ function SearchInput({ className }) {
|
|
|
728
889
|
type: "search",
|
|
729
890
|
placeholder: "Buscar produtos...",
|
|
730
891
|
value: search,
|
|
892
|
+
autoFocus: iconOnly,
|
|
731
893
|
onChange: (e) => {
|
|
732
894
|
setSearch(e.target.value);
|
|
733
895
|
if (path !== config.catalogPath) navigateTo(config.catalogPath);
|
|
734
896
|
},
|
|
897
|
+
onKeyDown: (e) => {
|
|
898
|
+
if (e.key === "Escape" && iconOnly) setOpen(false);
|
|
899
|
+
},
|
|
900
|
+
onBlur: () => {
|
|
901
|
+
if (iconOnly && !search) setOpen(false);
|
|
902
|
+
},
|
|
735
903
|
className: "w-full border bg-white/10 py-2 pl-9 pr-4 text-sm outline-none transition-colors placeholder:opacity-60 focus:border-primary focus:bg-white focus:text-gray-900",
|
|
736
904
|
style: {
|
|
737
905
|
borderRadius: "var(--sf-radius-input)",
|
|
@@ -884,6 +1052,7 @@ function StorefrontHeader() {
|
|
|
884
1052
|
const variant = config.theme?.header?.variant ?? "classic";
|
|
885
1053
|
const scrolled = useScrolled();
|
|
886
1054
|
const showSearch = config.theme?.header?.showSearch !== false;
|
|
1055
|
+
const iconSearch = config.theme?.header?.searchStyle === "icon";
|
|
887
1056
|
const logo = /* @__PURE__ */ jsx(Link, { to: "/", className: "sf-heading shrink-0 text-xl font-bold tracking-tight", children: config.logo ?? config.name });
|
|
888
1057
|
return /* @__PURE__ */ jsxs(
|
|
889
1058
|
"header",
|
|
@@ -897,7 +1066,7 @@ function StorefrontHeader() {
|
|
|
897
1066
|
// Rio/Flex pattern: centered logo row, nav row below
|
|
898
1067
|
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
899
1068
|
/* @__PURE__ */ jsxs("div", { className: "mx-auto grid h-16 max-w-7xl grid-cols-[1fr_auto_1fr] items-center px-4 sm:px-6", children: [
|
|
900
|
-
showSearch ? /* @__PURE__ */ jsx(SearchInput, { className: "hidden w-full max-w-xs sm:block" }) : /* @__PURE__ */ jsx("div", {}),
|
|
1069
|
+
showSearch ? /* @__PURE__ */ jsx(SearchInput, { iconOnly: iconSearch, className: "hidden w-full max-w-xs sm:block" }) : /* @__PURE__ */ jsx("div", {}),
|
|
901
1070
|
/* @__PURE__ */ jsx("div", { className: "text-center", children: logo }),
|
|
902
1071
|
/* @__PURE__ */ jsx("div", { className: "justify-self-end", children: /* @__PURE__ */ jsx(HeaderActions, {}) })
|
|
903
1072
|
] }),
|
|
@@ -907,7 +1076,7 @@ function StorefrontHeader() {
|
|
|
907
1076
|
// Brasília pattern: prominent search left, logo center, actions right; nav row below
|
|
908
1077
|
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
909
1078
|
/* @__PURE__ */ jsxs("div", { className: "mx-auto grid h-16 max-w-7xl grid-cols-[1fr_auto_1fr] items-center gap-6 px-4 sm:px-6", children: [
|
|
910
|
-
showSearch ? /* @__PURE__ */ jsx(SearchInput, { className: "hidden w-full max-w-sm sm:block" }) : /* @__PURE__ */ jsx("div", {}),
|
|
1079
|
+
showSearch ? /* @__PURE__ */ jsx(SearchInput, { iconOnly: iconSearch, className: "hidden w-full max-w-sm sm:block" }) : /* @__PURE__ */ jsx("div", {}),
|
|
911
1080
|
/* @__PURE__ */ jsx("div", { className: "text-center", children: logo }),
|
|
912
1081
|
/* @__PURE__ */ jsx("div", { className: "justify-self-end", children: /* @__PURE__ */ jsx(HeaderActions, {}) })
|
|
913
1082
|
] }),
|
|
@@ -919,17 +1088,19 @@ function StorefrontHeader() {
|
|
|
919
1088
|
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-5", children: /* @__PURE__ */ jsx(NavLinks, { className: "hidden sm:flex" }) }),
|
|
920
1089
|
/* @__PURE__ */ jsx("div", { className: "text-center", children: logo }),
|
|
921
1090
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-3", children: [
|
|
922
|
-
showSearch && /* @__PURE__ */ jsx(SearchInput, { className: "hidden w-44 lg:block" }),
|
|
1091
|
+
showSearch && /* @__PURE__ */ jsx(SearchInput, { iconOnly: iconSearch, className: "hidden w-44 lg:block" }),
|
|
923
1092
|
/* @__PURE__ */ jsx(HeaderActions, {})
|
|
924
1093
|
] })
|
|
925
1094
|
] })
|
|
926
1095
|
) : (
|
|
927
|
-
// classic: logo left,
|
|
1096
|
+
// classic: logo left, nav, then a right-aligned search + actions cluster
|
|
928
1097
|
/* @__PURE__ */ jsxs("div", { className: "mx-auto flex h-16 max-w-7xl items-center gap-6 px-4 sm:px-6", children: [
|
|
929
1098
|
logo,
|
|
930
1099
|
/* @__PURE__ */ jsx(NavLinks, { className: "hidden md:flex" }),
|
|
931
|
-
|
|
932
|
-
|
|
1100
|
+
/* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-2 sm:gap-3", children: [
|
|
1101
|
+
showSearch && /* @__PURE__ */ jsx(SearchInput, { iconOnly: iconSearch, className: iconSearch ? "" : "hidden w-full max-w-sm sm:block" }),
|
|
1102
|
+
/* @__PURE__ */ jsx(HeaderActions, {})
|
|
1103
|
+
] })
|
|
933
1104
|
] })
|
|
934
1105
|
)
|
|
935
1106
|
]
|
|
@@ -1103,6 +1274,113 @@ function QuantityInput({ value, onChange, min = 1, max, testId, incTestId, decTe
|
|
|
1103
1274
|
)
|
|
1104
1275
|
] });
|
|
1105
1276
|
}
|
|
1277
|
+
function DeliveryEstimator({ compact = false }) {
|
|
1278
|
+
const config = useStorefrontConfig();
|
|
1279
|
+
const cart = useCartStore();
|
|
1280
|
+
const delivery = useDeliveryStore();
|
|
1281
|
+
const [draft, setDraft] = useState(() => formatPostalCode(delivery.postalCode));
|
|
1282
|
+
const subtotal = selectSubtotal(cart);
|
|
1283
|
+
const money = (value) => formatMoney(value, config.currency, config.locale);
|
|
1284
|
+
const loading = delivery.status === "loading";
|
|
1285
|
+
async function submit(event) {
|
|
1286
|
+
event.preventDefault();
|
|
1287
|
+
await delivery.resolve(draft, subtotal);
|
|
1288
|
+
}
|
|
1289
|
+
function eta(option) {
|
|
1290
|
+
const { etaMinDays: min, etaMaxDays: max } = option;
|
|
1291
|
+
if (min == null && max == null) return null;
|
|
1292
|
+
if (min === 0 && (max === 0 || max === 1)) return "hoje ou amanh\xE3";
|
|
1293
|
+
if (min != null && max != null && min !== max) return `${min} a ${max} dias \xFAteis`;
|
|
1294
|
+
return `${max ?? min} dia(s) \xFAtil(eis)`;
|
|
1295
|
+
}
|
|
1296
|
+
return /* @__PURE__ */ jsxs(
|
|
1297
|
+
"section",
|
|
1298
|
+
{
|
|
1299
|
+
"data-testid": TID.deliveryEstimator,
|
|
1300
|
+
className: compact ? "rounded-lg border p-3" : "mt-6 rounded-lg border p-4",
|
|
1301
|
+
children: [
|
|
1302
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm font-semibold", children: [
|
|
1303
|
+
/* @__PURE__ */ jsx(Truck, { className: "h-4 w-4 text-primary" }),
|
|
1304
|
+
"Calcular entrega"
|
|
1305
|
+
] }),
|
|
1306
|
+
/* @__PURE__ */ jsxs("form", { onSubmit: submit, className: "mt-3 flex gap-2", children: [
|
|
1307
|
+
/* @__PURE__ */ jsx(
|
|
1308
|
+
"input",
|
|
1309
|
+
{
|
|
1310
|
+
"data-testid": TID.deliveryCepInput,
|
|
1311
|
+
"aria-label": "CEP",
|
|
1312
|
+
inputMode: "numeric",
|
|
1313
|
+
autoComplete: "postal-code",
|
|
1314
|
+
placeholder: "00000-000",
|
|
1315
|
+
value: draft,
|
|
1316
|
+
onChange: (event) => setDraft(formatPostalCode(event.target.value)),
|
|
1317
|
+
className: "min-w-0 flex-1 rounded-lg border bg-background px-3 py-2 text-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/10"
|
|
1318
|
+
}
|
|
1319
|
+
),
|
|
1320
|
+
/* @__PURE__ */ jsx(
|
|
1321
|
+
"button",
|
|
1322
|
+
{
|
|
1323
|
+
type: "submit",
|
|
1324
|
+
"data-testid": TID.deliveryCepSubmit,
|
|
1325
|
+
disabled: loading,
|
|
1326
|
+
className: "shrink-0 rounded-lg bg-primary px-4 py-2 text-sm font-semibold text-primary-foreground transition hover:opacity-90 disabled:opacity-50",
|
|
1327
|
+
children: loading ? "..." : "Calcular"
|
|
1328
|
+
}
|
|
1329
|
+
)
|
|
1330
|
+
] }),
|
|
1331
|
+
delivery.error && /* @__PURE__ */ jsx("p", { "data-testid": TID.deliveryError, className: "mt-3 text-sm text-destructive", children: delivery.error }),
|
|
1332
|
+
delivery.address && /* @__PURE__ */ jsxs("p", { "data-testid": TID.deliveryAddress, className: "mt-3 flex items-start gap-1.5 text-xs text-muted-foreground", children: [
|
|
1333
|
+
/* @__PURE__ */ jsx(MapPin, { className: "mt-0.5 h-3.5 w-3.5 shrink-0" }),
|
|
1334
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
1335
|
+
[delivery.address.street, delivery.address.district].filter(Boolean).join(", "),
|
|
1336
|
+
delivery.address.street || delivery.address.district ? " \u2014 " : "",
|
|
1337
|
+
delivery.address.city,
|
|
1338
|
+
"/",
|
|
1339
|
+
delivery.address.state
|
|
1340
|
+
] })
|
|
1341
|
+
] }),
|
|
1342
|
+
delivery.status === "served" && /* @__PURE__ */ jsx("ul", { className: "mt-3 space-y-2", children: delivery.options.map((option) => {
|
|
1343
|
+
const selected = delivery.selectedZoneId === option.zoneId;
|
|
1344
|
+
const label = eta(option);
|
|
1345
|
+
const rate = resolveOptionRate(option, subtotal);
|
|
1346
|
+
return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
|
|
1347
|
+
"button",
|
|
1348
|
+
{
|
|
1349
|
+
type: "button",
|
|
1350
|
+
"data-testid": TID.deliveryOption,
|
|
1351
|
+
"data-zone": option.zoneId,
|
|
1352
|
+
"data-rate": rate.toFixed(2),
|
|
1353
|
+
"aria-pressed": selected,
|
|
1354
|
+
onClick: () => delivery.selectZone(option.zoneId),
|
|
1355
|
+
className: `flex w-full items-center justify-between gap-3 rounded-lg border px-3 py-2 text-left text-sm transition ${selected ? "border-primary bg-primary/5" : "border-border hover:bg-muted/40"}`,
|
|
1356
|
+
children: [
|
|
1357
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0", children: [
|
|
1358
|
+
/* @__PURE__ */ jsx("span", { className: "block truncate font-medium", children: option.carrier ? `${option.carrier} \xB7 ${option.name}` : option.name }),
|
|
1359
|
+
label && /* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: label })
|
|
1360
|
+
] }),
|
|
1361
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 font-semibold", children: rate === 0 ? "Gr\xE1tis" : money(rate) })
|
|
1362
|
+
]
|
|
1363
|
+
}
|
|
1364
|
+
) }, option.zoneId);
|
|
1365
|
+
}) }),
|
|
1366
|
+
delivery.status === "unserved" && /* @__PURE__ */ jsx("p", { "data-testid": TID.deliveryUnserved, className: "mt-3 text-sm text-destructive", children: "Ainda n\xE3o entregamos nesse CEP." }),
|
|
1367
|
+
delivery.postalCode && /* @__PURE__ */ jsx(
|
|
1368
|
+
"button",
|
|
1369
|
+
{
|
|
1370
|
+
type: "button",
|
|
1371
|
+
"data-testid": TID.deliveryClear,
|
|
1372
|
+
onClick: () => {
|
|
1373
|
+
delivery.clear();
|
|
1374
|
+
setDraft("");
|
|
1375
|
+
},
|
|
1376
|
+
className: "mt-3 text-xs text-muted-foreground underline-offset-2 hover:underline",
|
|
1377
|
+
children: "Trocar CEP"
|
|
1378
|
+
}
|
|
1379
|
+
)
|
|
1380
|
+
]
|
|
1381
|
+
}
|
|
1382
|
+
);
|
|
1383
|
+
}
|
|
1106
1384
|
function SmoothImage({
|
|
1107
1385
|
imageLoading,
|
|
1108
1386
|
loading = "lazy",
|
|
@@ -1120,9 +1398,9 @@ function SmoothImage({
|
|
|
1120
1398
|
const durationMs = resolved.durationMs ?? 420;
|
|
1121
1399
|
const easing = resolved.easing ?? "cubic-bezier(0.22, 1, 0.36, 1)";
|
|
1122
1400
|
const blur = resolved.blur ?? true;
|
|
1123
|
-
const ref =
|
|
1124
|
-
const [loaded, setLoaded] =
|
|
1125
|
-
|
|
1401
|
+
const ref = React7.useRef(null);
|
|
1402
|
+
const [loaded, setLoaded] = React7.useState(mode === "none");
|
|
1403
|
+
React7.useEffect(() => {
|
|
1126
1404
|
if (mode === "none") {
|
|
1127
1405
|
setLoaded(true);
|
|
1128
1406
|
return;
|
|
@@ -1165,6 +1443,7 @@ function CartDrawer() {
|
|
|
1165
1443
|
document.addEventListener("keydown", onKey);
|
|
1166
1444
|
return () => document.removeEventListener("keydown", onKey);
|
|
1167
1445
|
}, [cart.isOpen, cart.closeDrawer]);
|
|
1446
|
+
const delivery = useDeliveryStore();
|
|
1168
1447
|
const subtotal = selectSubtotal(cart);
|
|
1169
1448
|
const discountTotal = selectDiscountTotal(cart);
|
|
1170
1449
|
const shipping = selectShipping(cart, config);
|
|
@@ -1321,6 +1600,7 @@ function CartDrawer() {
|
|
|
1321
1600
|
] }),
|
|
1322
1601
|
discountError && /* @__PURE__ */ jsx("p", { "data-testid": TID.discountError, className: "text-xs text-destructive", children: discountError })
|
|
1323
1602
|
] }),
|
|
1603
|
+
/* @__PURE__ */ jsx("div", { className: "mb-3", children: /* @__PURE__ */ jsx(DeliveryEstimator, { compact: true }) }),
|
|
1324
1604
|
/* @__PURE__ */ jsxs("dl", { className: "space-y-1.5 text-sm", children: [
|
|
1325
1605
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
|
|
1326
1606
|
/* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: "Subtotal" }),
|
|
@@ -1350,7 +1630,13 @@ function CartDrawer() {
|
|
|
1350
1630
|
] })
|
|
1351
1631
|
] }),
|
|
1352
1632
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
|
|
1353
|
-
/* @__PURE__ */
|
|
1633
|
+
/* @__PURE__ */ jsxs("dt", { className: "text-muted-foreground", children: [
|
|
1634
|
+
"Frete",
|
|
1635
|
+
delivery.status === "served" && delivery.postalCode && /* @__PURE__ */ jsxs("span", { className: "ml-1 text-xs", children: [
|
|
1636
|
+
"\xB7 ",
|
|
1637
|
+
formatPostalCode(delivery.postalCode)
|
|
1638
|
+
] })
|
|
1639
|
+
] }),
|
|
1354
1640
|
/* @__PURE__ */ jsx("dd", { "data-testid": TID.cartShipping, "data-price": shipping.toFixed(2), children: shipping === 0 ? "Gr\xE1tis" : money(shipping) })
|
|
1355
1641
|
] }),
|
|
1356
1642
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between border-t pt-2 text-base font-semibold", children: [
|
|
@@ -2693,6 +2979,128 @@ function ProductEnquiryForm({ product, onSuccess }) {
|
|
|
2693
2979
|
}
|
|
2694
2980
|
);
|
|
2695
2981
|
}
|
|
2982
|
+
function ProductGallery({ product, images, primaryImage }) {
|
|
2983
|
+
const ordered = orderImages(images, primaryImage);
|
|
2984
|
+
const [index, setIndex] = useState(0);
|
|
2985
|
+
const [zoom, setZoom] = useState(null);
|
|
2986
|
+
const frameRef = useRef(null);
|
|
2987
|
+
const canHover = useCanHover();
|
|
2988
|
+
useEffect(() => {
|
|
2989
|
+
setIndex(0);
|
|
2990
|
+
setZoom(null);
|
|
2991
|
+
}, [product.id]);
|
|
2992
|
+
const current = ordered[Math.min(index, ordered.length - 1)];
|
|
2993
|
+
function trackPointer(event) {
|
|
2994
|
+
if (!canHover) return;
|
|
2995
|
+
const frame = frameRef.current;
|
|
2996
|
+
if (!frame) return;
|
|
2997
|
+
const rect = frame.getBoundingClientRect();
|
|
2998
|
+
setZoom({
|
|
2999
|
+
x: (event.clientX - rect.left) / rect.width * 100,
|
|
3000
|
+
y: (event.clientY - rect.top) / rect.height * 100
|
|
3001
|
+
});
|
|
3002
|
+
}
|
|
3003
|
+
function step(delta) {
|
|
3004
|
+
if (ordered.length < 2) return;
|
|
3005
|
+
setIndex((current2) => (current2 + delta + ordered.length) % ordered.length);
|
|
3006
|
+
setZoom(null);
|
|
3007
|
+
}
|
|
3008
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 self-start", children: [
|
|
3009
|
+
/* @__PURE__ */ jsxs(
|
|
3010
|
+
"div",
|
|
3011
|
+
{
|
|
3012
|
+
...storefrontComponentContracts.productDetail.gallery,
|
|
3013
|
+
ref: frameRef,
|
|
3014
|
+
className: "group relative aspect-square w-full overflow-hidden border bg-muted",
|
|
3015
|
+
style: { borderRadius: "var(--sf-radius-card)" },
|
|
3016
|
+
onMouseMove: trackPointer,
|
|
3017
|
+
onMouseLeave: () => setZoom(null),
|
|
3018
|
+
onKeyDown: (event) => {
|
|
3019
|
+
if (event.key === "ArrowRight") step(1);
|
|
3020
|
+
if (event.key === "ArrowLeft") step(-1);
|
|
3021
|
+
},
|
|
3022
|
+
tabIndex: ordered.length > 1 ? 0 : -1,
|
|
3023
|
+
role: ordered.length > 1 ? "group" : void 0,
|
|
3024
|
+
"aria-label": ordered.length > 1 ? `Imagens de ${product.name}` : void 0,
|
|
3025
|
+
children: [
|
|
3026
|
+
current && /* @__PURE__ */ jsx(
|
|
3027
|
+
"div",
|
|
3028
|
+
{
|
|
3029
|
+
className: "h-full w-full transition-transform duration-150 ease-out",
|
|
3030
|
+
style: zoom ? { transform: "scale(2)", transformOrigin: `${zoom.x}% ${zoom.y}%` } : { transform: "scale(1)" },
|
|
3031
|
+
children: /* @__PURE__ */ jsx(
|
|
3032
|
+
SmoothImage,
|
|
3033
|
+
{
|
|
3034
|
+
src: current.url,
|
|
3035
|
+
alt: current.altText ?? product.name,
|
|
3036
|
+
"data-testid": TID.pdpGalleryImage,
|
|
3037
|
+
className: "h-full w-full object-cover"
|
|
3038
|
+
},
|
|
3039
|
+
current.id
|
|
3040
|
+
)
|
|
3041
|
+
}
|
|
3042
|
+
),
|
|
3043
|
+
ordered.length > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3044
|
+
/* @__PURE__ */ jsx(GalleryArrow, { side: "left", onClick: () => step(-1) }),
|
|
3045
|
+
/* @__PURE__ */ jsx(GalleryArrow, { side: "right", onClick: () => step(1) }),
|
|
3046
|
+
/* @__PURE__ */ jsxs("span", { className: "pointer-events-none absolute bottom-3 right-3 rounded-full bg-black/60 px-2 py-0.5 text-[11px] font-medium text-white", children: [
|
|
3047
|
+
index + 1,
|
|
3048
|
+
"/",
|
|
3049
|
+
ordered.length
|
|
3050
|
+
] })
|
|
3051
|
+
] })
|
|
3052
|
+
]
|
|
3053
|
+
}
|
|
3054
|
+
),
|
|
3055
|
+
ordered.length > 1 && /* @__PURE__ */ jsx("ul", { "data-testid": TID.pdpGalleryThumbs, className: "flex gap-2 overflow-x-auto pb-1", children: ordered.map((image, position) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
|
|
3056
|
+
"button",
|
|
3057
|
+
{
|
|
3058
|
+
type: "button",
|
|
3059
|
+
"data-testid": TID.pdpGalleryThumb,
|
|
3060
|
+
"data-index": position,
|
|
3061
|
+
"aria-label": `Imagem ${position + 1} de ${ordered.length}`,
|
|
3062
|
+
"aria-current": position === index,
|
|
3063
|
+
onClick: () => {
|
|
3064
|
+
setIndex(position);
|
|
3065
|
+
setZoom(null);
|
|
3066
|
+
},
|
|
3067
|
+
className: `h-16 w-16 shrink-0 overflow-hidden rounded-lg border transition ${position === index ? "border-primary ring-2 ring-primary/20" : "border-border opacity-70 hover:opacity-100"}`,
|
|
3068
|
+
children: /* @__PURE__ */ jsx("img", { src: image.url, alt: "", className: "h-full w-full object-cover", loading: "lazy" })
|
|
3069
|
+
}
|
|
3070
|
+
) }, image.id)) })
|
|
3071
|
+
] });
|
|
3072
|
+
}
|
|
3073
|
+
function orderImages(images, primary) {
|
|
3074
|
+
const all = images.length > 0 ? images : primary ? [primary] : [];
|
|
3075
|
+
return [...all].sort((a, b) => {
|
|
3076
|
+
if (a.isPrimary !== b.isPrimary) return a.isPrimary ? -1 : 1;
|
|
3077
|
+
return (a.sortOrder ?? 0) - (b.sortOrder ?? 0);
|
|
3078
|
+
});
|
|
3079
|
+
}
|
|
3080
|
+
function useCanHover() {
|
|
3081
|
+
const [canHover, setCanHover] = useState(false);
|
|
3082
|
+
useEffect(() => {
|
|
3083
|
+
const query = window.matchMedia?.("(hover: hover) and (pointer: fine)");
|
|
3084
|
+
if (!query) return;
|
|
3085
|
+
setCanHover(query.matches);
|
|
3086
|
+
const onChange = (event) => setCanHover(event.matches);
|
|
3087
|
+
query.addEventListener?.("change", onChange);
|
|
3088
|
+
return () => query.removeEventListener?.("change", onChange);
|
|
3089
|
+
}, []);
|
|
3090
|
+
return canHover;
|
|
3091
|
+
}
|
|
3092
|
+
function GalleryArrow({ side, onClick }) {
|
|
3093
|
+
return /* @__PURE__ */ jsx(
|
|
3094
|
+
"button",
|
|
3095
|
+
{
|
|
3096
|
+
type: "button",
|
|
3097
|
+
onClick,
|
|
3098
|
+
"aria-label": side === "left" ? "Imagem anterior" : "Pr\xF3xima imagem",
|
|
3099
|
+
className: `absolute top-1/2 z-10 flex h-9 w-9 -translate-y-1/2 items-center justify-center rounded-full bg-background/80 opacity-0 shadow-md backdrop-blur transition hover:bg-background focus:opacity-100 group-hover:opacity-100 ${side === "left" ? "left-3" : "right-3"}`,
|
|
3100
|
+
children: /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "text-lg leading-none", children: side === "left" ? "\u2039" : "\u203A" })
|
|
3101
|
+
}
|
|
3102
|
+
);
|
|
3103
|
+
}
|
|
2696
3104
|
function ProductDetailPage({ slug: slug2 }) {
|
|
2697
3105
|
const config = useStorefrontConfig();
|
|
2698
3106
|
const actions = useStorefrontActions();
|
|
@@ -2733,6 +3141,7 @@ function ProductDetailPage({ slug: slug2 }) {
|
|
|
2733
3141
|
const image = product.images.find((i) => i.isPrimary) ?? product.images[0];
|
|
2734
3142
|
const components = getStorefrontComponents(config);
|
|
2735
3143
|
const ProductDetailComponent = components.ProductDetail;
|
|
3144
|
+
const GalleryComponent = components.ProductGallery ?? ProductGallery;
|
|
2736
3145
|
const addToCart = () => addItem(product, qty, selectedOptions);
|
|
2737
3146
|
const openEnquiry = () => {
|
|
2738
3147
|
document.getElementById("storefront-product-enquiry")?.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
@@ -2766,19 +3175,13 @@ function ProductDetailPage({ slug: slug2 }) {
|
|
|
2766
3175
|
] }),
|
|
2767
3176
|
/* @__PURE__ */ jsxs("div", { className: "grid animate-fade-up gap-10 md:grid-cols-2", children: [
|
|
2768
3177
|
/* @__PURE__ */ jsx(
|
|
2769
|
-
|
|
3178
|
+
GalleryComponent,
|
|
2770
3179
|
{
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
{
|
|
2777
|
-
src: image.url,
|
|
2778
|
-
alt: image.altText ?? product.name,
|
|
2779
|
-
className: "aspect-square w-full object-cover transition-transform duration-700 ease-out group-hover:scale-105"
|
|
2780
|
-
}
|
|
2781
|
-
)
|
|
3180
|
+
product,
|
|
3181
|
+
images: product.images,
|
|
3182
|
+
primaryImage: image,
|
|
3183
|
+
config,
|
|
3184
|
+
commerceMode: config.commerceMode
|
|
2782
3185
|
}
|
|
2783
3186
|
),
|
|
2784
3187
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col py-2 lg:sticky lg:top-24 lg:self-start", children: [
|
|
@@ -2876,6 +3279,7 @@ function ProductDetailPage({ slug: slug2 }) {
|
|
|
2876
3279
|
children: "Voltar ao cat\xE1logo"
|
|
2877
3280
|
}
|
|
2878
3281
|
) }),
|
|
3282
|
+
config.commerceMode === "checkout" && /* @__PURE__ */ jsx(DeliveryEstimator, {}),
|
|
2879
3283
|
config.commerceMode === "checkout" && /* @__PURE__ */ jsxs("div", { className: "mt-6 grid grid-cols-3 gap-3 border-t pt-6 text-center", children: [
|
|
2880
3284
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1.5 text-[11px] font-medium text-muted-foreground", children: [
|
|
2881
3285
|
/* @__PURE__ */ jsx(Truck, { className: "h-5 w-5 text-primary" }),
|
|
@@ -2901,9 +3305,10 @@ function ProductDetailPage({ slug: slug2 }) {
|
|
|
2901
3305
|
/* @__PURE__ */ jsx(RelatedProducts, { product })
|
|
2902
3306
|
] });
|
|
2903
3307
|
}
|
|
2904
|
-
function formatDeliveryNotes(address) {
|
|
3308
|
+
function formatDeliveryNotes(address, shippingAddress) {
|
|
3309
|
+
if (address?.notes?.trim()) return address.notes.trim();
|
|
3310
|
+
if (shippingAddress) return void 0;
|
|
2905
3311
|
if (!address) return void 0;
|
|
2906
|
-
if (address.notes?.trim()) return address.notes.trim();
|
|
2907
3312
|
const parts = [address.street, address.city, address.zip].map((part) => part?.trim()).filter(Boolean);
|
|
2908
3313
|
return parts.length > 0 ? `Entrega: ${parts.join(", ")}` : void 0;
|
|
2909
3314
|
}
|
|
@@ -2913,6 +3318,8 @@ async function placeStorefrontOrder({
|
|
|
2913
3318
|
session,
|
|
2914
3319
|
customer,
|
|
2915
3320
|
address,
|
|
3321
|
+
shippingAddress,
|
|
3322
|
+
paymentMethod,
|
|
2916
3323
|
markPaid = false
|
|
2917
3324
|
}) {
|
|
2918
3325
|
const email = customer.email.trim().toLowerCase();
|
|
@@ -2927,9 +3334,14 @@ async function placeStorefrontOrder({
|
|
|
2927
3334
|
customerId: customerId ?? void 0,
|
|
2928
3335
|
customer: { name, email },
|
|
2929
3336
|
currency: config.currency,
|
|
2930
|
-
notes: formatDeliveryNotes(address),
|
|
3337
|
+
notes: formatDeliveryNotes(address, shippingAddress),
|
|
2931
3338
|
discountCode: cart.discountCode ?? void 0,
|
|
2932
3339
|
shippingTotal: selectShipping(cart, config),
|
|
3340
|
+
// Structured address + method are what populate public.addresses and the
|
|
3341
|
+
// transactions ledger. `notes` stays for backwards compatibility with
|
|
3342
|
+
// checkouts that have not been updated yet.
|
|
3343
|
+
shippingAddress,
|
|
3344
|
+
paymentMethod,
|
|
2933
3345
|
items: cart.lines.map((line) => ({
|
|
2934
3346
|
productId: line.productId,
|
|
2935
3347
|
quantity: line.quantity,
|
|
@@ -2937,7 +3349,8 @@ async function placeStorefrontOrder({
|
|
|
2937
3349
|
}))
|
|
2938
3350
|
});
|
|
2939
3351
|
if (markPaid) {
|
|
2940
|
-
await provider.
|
|
3352
|
+
if (provider.confirmPayment) await provider.confirmPayment(order.id);
|
|
3353
|
+
else await provider.updateOrder(order.id, { financialStatus: "paid" });
|
|
2941
3354
|
}
|
|
2942
3355
|
return { order, customerId: customerId ?? order.customerId ?? "" };
|
|
2943
3356
|
}
|
|
@@ -3051,19 +3464,18 @@ function SignInModal({ defaultEmail = "", onClose, onSignedIn }) {
|
|
|
3051
3464
|
}
|
|
3052
3465
|
);
|
|
3053
3466
|
}
|
|
3054
|
-
var
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3467
|
+
var PAYMENT_LABELS = {
|
|
3468
|
+
pix: { label: "Pix", hint: "Voc\xEA recebe a chave para pagar ap\xF3s confirmar o pedido" },
|
|
3469
|
+
credit_card: { label: "Cart\xE3o de cr\xE9dito", hint: "Maquininha na entrega" },
|
|
3470
|
+
debit_card: { label: "Cart\xE3o de d\xE9bito", hint: "Maquininha na entrega" },
|
|
3471
|
+
boleto: { label: "Boleto", hint: "Enviado por e-mail ap\xF3s a confirma\xE7\xE3o" },
|
|
3472
|
+
cash: { label: "Dinheiro", hint: "Pagamento na entrega" },
|
|
3473
|
+
other: { label: "Combinar com a loja", hint: "A loja entra em contato para acertar o pagamento" }
|
|
3474
|
+
};
|
|
3060
3475
|
var PROCESSING_STEPS = [
|
|
3061
3476
|
{ icon: Lock, label: "Validando seus dados..." },
|
|
3062
|
-
{ icon:
|
|
3063
|
-
{ icon: PackageCheck, label: "Confirmando seu pedido..." }
|
|
3477
|
+
{ icon: PackageCheck, label: "Registrando seu pedido..." }
|
|
3064
3478
|
];
|
|
3065
|
-
var DEFAULT_ADDRESS = SAVED_ADDRESSES[0];
|
|
3066
|
-
var DEFAULT_PAYMENT = SAVED_PAYMENT_METHODS[0];
|
|
3067
3479
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
3068
3480
|
function ProcessingOverlay({ step }) {
|
|
3069
3481
|
const current = PROCESSING_STEPS[Math.min(step, PROCESSING_STEPS.length - 1)];
|
|
@@ -3106,23 +3518,24 @@ function CheckoutPage() {
|
|
|
3106
3518
|
const config = useStorefrontConfig();
|
|
3107
3519
|
const cart = useCartStore();
|
|
3108
3520
|
const session = useSessionStore();
|
|
3521
|
+
const delivery = useDeliveryStore();
|
|
3109
3522
|
const validateDiscount2 = useDiscountValidator();
|
|
3110
3523
|
useStorefrontHead({ title: `Checkout \u2014 ${config.name}` });
|
|
3111
|
-
const
|
|
3112
|
-
const [
|
|
3113
|
-
const [savedAddresses, setSavedAddresses] = useState(
|
|
3114
|
-
const [
|
|
3115
|
-
const [
|
|
3116
|
-
const [paymentMode, setPaymentMode] = useState("saved");
|
|
3524
|
+
const paymentMethods = config.payments.methods;
|
|
3525
|
+
const [selectedAddressId, setSelectedAddressId] = useState("new");
|
|
3526
|
+
const [savedAddresses, setSavedAddresses] = useState([]);
|
|
3527
|
+
const [addressMode, setAddressMode] = useState("new");
|
|
3528
|
+
const [paymentMethod, setPaymentMethod] = useState(paymentMethods[0] ?? "pix");
|
|
3117
3529
|
const [form, setForm] = useState({
|
|
3118
3530
|
email: session.email ?? "",
|
|
3119
3531
|
name: session.name ?? "",
|
|
3120
|
-
street:
|
|
3121
|
-
city:
|
|
3122
|
-
zip:
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3532
|
+
street: "",
|
|
3533
|
+
city: "",
|
|
3534
|
+
zip: "",
|
|
3535
|
+
number: "",
|
|
3536
|
+
complement: "",
|
|
3537
|
+
district: "",
|
|
3538
|
+
state: ""
|
|
3126
3539
|
});
|
|
3127
3540
|
const [error, setError] = useState(null);
|
|
3128
3541
|
const [discountCode, setDiscountCode] = useState("");
|
|
@@ -3132,6 +3545,7 @@ function CheckoutPage() {
|
|
|
3132
3545
|
const [placing, setPlacing] = useState(false);
|
|
3133
3546
|
const [processingStep, setProcessingStep] = useState(0);
|
|
3134
3547
|
const [showSignin, setShowSignin] = useState(false);
|
|
3548
|
+
const [zipLookup, setZipLookup] = useState("idle");
|
|
3135
3549
|
const subtotal = selectSubtotal(cart);
|
|
3136
3550
|
const discountTotal = selectDiscountTotal(cart);
|
|
3137
3551
|
const shipping = selectShipping(cart, config);
|
|
@@ -3141,6 +3555,32 @@ function CheckoutPage() {
|
|
|
3141
3555
|
if (cart.lines.length === 0 && !placing) navigateTo(config.catalogPath);
|
|
3142
3556
|
}, [cart.lines.length, config.catalogPath, placing]);
|
|
3143
3557
|
const set = (key) => (value) => setForm((current) => ({ ...current, [key]: value }));
|
|
3558
|
+
async function setZip(value) {
|
|
3559
|
+
const masked = formatPostalCode(value);
|
|
3560
|
+
setForm((current) => ({ ...current, zip: masked }));
|
|
3561
|
+
if (normalizePostalCode(masked).length !== 8) {
|
|
3562
|
+
setZipLookup("idle");
|
|
3563
|
+
return;
|
|
3564
|
+
}
|
|
3565
|
+
setZipLookup("loading");
|
|
3566
|
+
try {
|
|
3567
|
+
const found = await lookupPostalCode(masked);
|
|
3568
|
+
if (!found) {
|
|
3569
|
+
setZipLookup("not-found");
|
|
3570
|
+
return;
|
|
3571
|
+
}
|
|
3572
|
+
setZipLookup("found");
|
|
3573
|
+
setForm((current) => ({
|
|
3574
|
+
...current,
|
|
3575
|
+
street: found.street || current.street,
|
|
3576
|
+
district: found.district || current.district,
|
|
3577
|
+
city: found.city,
|
|
3578
|
+
state: found.state
|
|
3579
|
+
}));
|
|
3580
|
+
} catch {
|
|
3581
|
+
setZipLookup("idle");
|
|
3582
|
+
}
|
|
3583
|
+
}
|
|
3144
3584
|
async function applyDiscountCode() {
|
|
3145
3585
|
setApplyingDiscount(true);
|
|
3146
3586
|
setDiscountError(null);
|
|
@@ -3167,10 +3607,54 @@ function CheckoutPage() {
|
|
|
3167
3607
|
setDiscountSuccess(null);
|
|
3168
3608
|
setDiscountError(null);
|
|
3169
3609
|
}
|
|
3610
|
+
useEffect(() => {
|
|
3611
|
+
const customerId = session.customerId;
|
|
3612
|
+
if (!customerId) {
|
|
3613
|
+
setSavedAddresses([]);
|
|
3614
|
+
setAddressMode("new");
|
|
3615
|
+
return;
|
|
3616
|
+
}
|
|
3617
|
+
let cancelled = false;
|
|
3618
|
+
const provider = getShopProvider();
|
|
3619
|
+
void provider.listCustomerAddresses?.(customerId).then((addresses) => {
|
|
3620
|
+
if (cancelled || addresses.length === 0) return;
|
|
3621
|
+
setSavedAddresses(addresses);
|
|
3622
|
+
applySavedAddress(addresses[0]);
|
|
3623
|
+
}).catch(() => {
|
|
3624
|
+
});
|
|
3625
|
+
return () => {
|
|
3626
|
+
cancelled = true;
|
|
3627
|
+
};
|
|
3628
|
+
}, [session.customerId]);
|
|
3629
|
+
useEffect(() => {
|
|
3630
|
+
if (addressMode !== "new") return;
|
|
3631
|
+
const looked = delivery.address;
|
|
3632
|
+
if (!looked) return;
|
|
3633
|
+
setForm((current) => {
|
|
3634
|
+
if (current.zip.trim() || current.street.trim()) return current;
|
|
3635
|
+
return {
|
|
3636
|
+
...current,
|
|
3637
|
+
zip: formatPostalCode(looked.postalCode),
|
|
3638
|
+
street: looked.street,
|
|
3639
|
+
district: looked.district,
|
|
3640
|
+
city: looked.city,
|
|
3641
|
+
state: looked.state
|
|
3642
|
+
};
|
|
3643
|
+
});
|
|
3644
|
+
}, [delivery.address, addressMode]);
|
|
3170
3645
|
function applySavedAddress(address) {
|
|
3171
3646
|
setAddressMode("saved");
|
|
3172
3647
|
setSelectedAddressId(address.id);
|
|
3173
|
-
setForm((current) => ({
|
|
3648
|
+
setForm((current) => ({
|
|
3649
|
+
...current,
|
|
3650
|
+
street: address.street,
|
|
3651
|
+
city: address.city,
|
|
3652
|
+
zip: address.postalCode,
|
|
3653
|
+
number: address.number ?? "",
|
|
3654
|
+
complement: address.complement ?? "",
|
|
3655
|
+
district: address.district ?? "",
|
|
3656
|
+
state: address.state
|
|
3657
|
+
}));
|
|
3174
3658
|
}
|
|
3175
3659
|
function selectAddress(addressId) {
|
|
3176
3660
|
const address = savedAddresses.find((item) => item.id === addressId);
|
|
@@ -3179,37 +3663,7 @@ function CheckoutPage() {
|
|
|
3179
3663
|
function addNewAddress() {
|
|
3180
3664
|
setAddressMode("new");
|
|
3181
3665
|
setSelectedAddressId("new");
|
|
3182
|
-
setForm((current) => ({ ...current, street: "", city: "", zip: "" }));
|
|
3183
|
-
}
|
|
3184
|
-
function removeAddress(addressId) {
|
|
3185
|
-
const nextAddresses = savedAddresses.filter((item) => item.id !== addressId);
|
|
3186
|
-
setSavedAddresses(nextAddresses);
|
|
3187
|
-
if (selectedAddressId !== addressId) return;
|
|
3188
|
-
const fallback = nextAddresses[0];
|
|
3189
|
-
if (fallback) applySavedAddress(fallback);
|
|
3190
|
-
else addNewAddress();
|
|
3191
|
-
}
|
|
3192
|
-
function applySavedPayment(method) {
|
|
3193
|
-
setPaymentMode("saved");
|
|
3194
|
-
setSelectedPaymentId(method.id);
|
|
3195
|
-
setForm((current) => ({ ...current, card: method.card, expiry: method.expiry, cvc: method.cvc }));
|
|
3196
|
-
}
|
|
3197
|
-
function selectPayment(paymentId) {
|
|
3198
|
-
const method = savedPaymentMethods.find((item) => item.id === paymentId);
|
|
3199
|
-
if (method) applySavedPayment(method);
|
|
3200
|
-
}
|
|
3201
|
-
function addNewPayment() {
|
|
3202
|
-
setPaymentMode("new");
|
|
3203
|
-
setSelectedPaymentId("new");
|
|
3204
|
-
setForm((current) => ({ ...current, card: "", expiry: "", cvc: "" }));
|
|
3205
|
-
}
|
|
3206
|
-
function removePayment(paymentId) {
|
|
3207
|
-
const nextMethods = savedPaymentMethods.filter((item) => item.id !== paymentId);
|
|
3208
|
-
setSavedPaymentMethods(nextMethods);
|
|
3209
|
-
if (selectedPaymentId !== paymentId) return;
|
|
3210
|
-
const fallback = nextMethods[0];
|
|
3211
|
-
if (fallback) applySavedPayment(fallback);
|
|
3212
|
-
else addNewPayment();
|
|
3666
|
+
setForm((current) => ({ ...current, street: "", city: "", zip: "", number: "", complement: "", district: "", state: "" }));
|
|
3213
3667
|
}
|
|
3214
3668
|
function validate() {
|
|
3215
3669
|
setError(null);
|
|
@@ -3221,12 +3675,20 @@ function CheckoutPage() {
|
|
|
3221
3675
|
setError("Informe seu nome completo.");
|
|
3222
3676
|
return false;
|
|
3223
3677
|
}
|
|
3224
|
-
if (!form.street.trim() || !form.city.trim() || !form.zip.trim()) {
|
|
3678
|
+
if (!form.street.trim() || !form.city.trim() || !form.zip.trim() || !form.district.trim()) {
|
|
3225
3679
|
setError("Preencha ou selecione o endere\xE7o de entrega.");
|
|
3226
3680
|
return false;
|
|
3227
3681
|
}
|
|
3228
|
-
if (
|
|
3229
|
-
setError("
|
|
3682
|
+
if (!form.number.trim()) {
|
|
3683
|
+
setError("Falta o n\xFAmero do endere\xE7o.");
|
|
3684
|
+
return false;
|
|
3685
|
+
}
|
|
3686
|
+
if (form.state.trim().length !== 2) {
|
|
3687
|
+
setError("Informe a UF com duas letras (ex.: RJ).");
|
|
3688
|
+
return false;
|
|
3689
|
+
}
|
|
3690
|
+
if (delivery.status === "unserved" && delivery.postalCode === normalizePostalCode(form.zip)) {
|
|
3691
|
+
setError("Ainda n\xE3o entregamos nesse CEP. Tente outro endere\xE7o.");
|
|
3230
3692
|
return false;
|
|
3231
3693
|
}
|
|
3232
3694
|
return true;
|
|
@@ -3248,9 +3710,22 @@ function CheckoutPage() {
|
|
|
3248
3710
|
session,
|
|
3249
3711
|
customer: { email: form.email, name: form.name },
|
|
3250
3712
|
address: { street: form.street, city: form.city, zip: form.zip },
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3713
|
+
shippingAddress: {
|
|
3714
|
+
postalCode: form.zip.trim(),
|
|
3715
|
+
street: form.street.trim(),
|
|
3716
|
+
number: form.number.trim() || void 0,
|
|
3717
|
+
complement: form.complement.trim() || void 0,
|
|
3718
|
+
district: form.district.trim() || void 0,
|
|
3719
|
+
city: form.city.trim(),
|
|
3720
|
+
state: form.state.trim().toUpperCase()
|
|
3721
|
+
},
|
|
3722
|
+
// The method the buyer actually chose, which opens the ledger row in
|
|
3723
|
+
// public.transactions with the right kind.
|
|
3724
|
+
paymentMethod
|
|
3725
|
+
// Never marked paid from the browser. It used to be, through an RPC that
|
|
3726
|
+
// was granted to anon — so any buyer holding their own order id could
|
|
3727
|
+
// declare it settled. The order is now born `pending` and only the
|
|
3728
|
+
// merchant (or a PSP webhook) can confirm the money arrived.
|
|
3254
3729
|
});
|
|
3255
3730
|
await minDuration;
|
|
3256
3731
|
cart.clear();
|
|
@@ -3323,35 +3798,25 @@ function CheckoutPage() {
|
|
|
3323
3798
|
/* @__PURE__ */ jsxs("section", { children: [
|
|
3324
3799
|
/* @__PURE__ */ jsx("h2", { className: "mb-3 text-xl font-semibold tracking-tight", children: "Endere\xE7o de entrega" }),
|
|
3325
3800
|
/* @__PURE__ */ jsxs("div", { className: "mb-3 grid gap-3", children: [
|
|
3326
|
-
savedAddresses.map((address) => /* @__PURE__ */
|
|
3801
|
+
savedAddresses.map((address) => /* @__PURE__ */ jsx(
|
|
3327
3802
|
"div",
|
|
3328
3803
|
{
|
|
3329
3804
|
className: `group relative rounded-lg border p-3 pr-11 text-left text-sm transition hover:bg-muted/40 ${selectedAddressId === address.id ? "border-primary bg-primary/5" : "border-border bg-background"}`,
|
|
3330
|
-
children: [
|
|
3331
|
-
/* @__PURE__ */ jsxs("
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
addressMode === "saved" && selectedAddressId === address.id && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-primary/10 px-2 py-0.5 text-[11px] font-bold text-primary", children: "Selecionado" })
|
|
3335
|
-
] }),
|
|
3336
|
-
/* @__PURE__ */ jsx("span", { className: "mt-1 block text-muted-foreground", children: address.street }),
|
|
3337
|
-
/* @__PURE__ */ jsxs("span", { className: "block text-muted-foreground", children: [
|
|
3338
|
-
address.city,
|
|
3339
|
-
" - ",
|
|
3340
|
-
address.zip
|
|
3341
|
-
] })
|
|
3805
|
+
children: /* @__PURE__ */ jsxs("button", { type: "button", onClick: () => selectAddress(address.id), className: "block w-full text-left", children: [
|
|
3806
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center justify-between gap-3 font-semibold", children: [
|
|
3807
|
+
address.label,
|
|
3808
|
+
addressMode === "saved" && selectedAddressId === address.id && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-primary/10 px-2 py-0.5 text-[11px] font-bold text-primary", children: "Selecionado" })
|
|
3342
3809
|
] }),
|
|
3343
|
-
/* @__PURE__ */
|
|
3344
|
-
"
|
|
3345
|
-
{
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
)
|
|
3354
|
-
]
|
|
3810
|
+
/* @__PURE__ */ jsxs("span", { className: "mt-1 block text-muted-foreground", children: [
|
|
3811
|
+
[address.street, address.number].filter(Boolean).join(", "),
|
|
3812
|
+
address.complement ? ` \u2014 ${address.complement}` : ""
|
|
3813
|
+
] }),
|
|
3814
|
+
/* @__PURE__ */ jsxs("span", { className: "block text-muted-foreground", children: [
|
|
3815
|
+
[address.district, address.city, address.state].filter(Boolean).join(" \xB7 "),
|
|
3816
|
+
" \u2014 ",
|
|
3817
|
+
address.postalCode
|
|
3818
|
+
] })
|
|
3819
|
+
] })
|
|
3355
3820
|
},
|
|
3356
3821
|
address.id
|
|
3357
3822
|
)),
|
|
@@ -3362,83 +3827,62 @@ function CheckoutPage() {
|
|
|
3362
3827
|
onClick: addNewAddress,
|
|
3363
3828
|
className: `rounded-lg border border-dashed p-3 text-left text-sm transition hover:bg-muted/40 ${addressMode === "new" ? "border-primary bg-primary/5" : "border-border bg-muted/20"}`,
|
|
3364
3829
|
children: [
|
|
3365
|
-
/* @__PURE__ */ jsx("span", { className: "block font-semibold text-primary", children: "+ Adicionar novo endere\xE7o" }),
|
|
3830
|
+
/* @__PURE__ */ jsx("span", { className: "block font-semibold text-primary", children: savedAddresses.length > 0 ? "+ Adicionar novo endere\xE7o" : "Informe o endere\xE7o de entrega" }),
|
|
3366
3831
|
/* @__PURE__ */ jsx("span", { className: "mt-1 block text-muted-foreground", children: "Preencher outro endere\xE7o para esta compra" })
|
|
3367
3832
|
]
|
|
3368
3833
|
}
|
|
3369
3834
|
)
|
|
3370
3835
|
] }),
|
|
3371
3836
|
addressMode === "new" && /* @__PURE__ */ jsxs("div", { className: "grid gap-3", children: [
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3837
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-1 sm:grid-cols-[200px_1fr] sm:items-center", children: [
|
|
3838
|
+
field("CEP", TID.checkoutZip, form.zip, setZip, {
|
|
3839
|
+
placeholder: "CEP",
|
|
3840
|
+
inputMode: "numeric",
|
|
3841
|
+
autoComplete: "postal-code"
|
|
3842
|
+
}),
|
|
3843
|
+
/* @__PURE__ */ jsx("p", { className: "px-1 text-xs text-muted-foreground", children: zipLookup === "loading" ? "Buscando endere\xE7o\u2026" : zipLookup === "not-found" ? "CEP n\xE3o encontrado \u2014 preencha o endere\xE7o \xE0 m\xE3o." : "Preenchemos o endere\xE7o para voc\xEA." })
|
|
3844
|
+
] }),
|
|
3845
|
+
field("Endere\xE7o", TID.checkoutStreet, form.street, set("street"), { placeholder: "Rua, avenida\u2026" }),
|
|
3846
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
|
|
3847
|
+
field("N\xFAmero", "checkout-number", form.number, set("number"), { placeholder: "N\xFAmero" }),
|
|
3848
|
+
field("Complemento", "checkout-complement", form.complement, set("complement"), { placeholder: "Apto, bloco (opcional)" })
|
|
3849
|
+
] }),
|
|
3850
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
|
|
3851
|
+
field("Bairro", "checkout-district", form.district, set("district"), { placeholder: "Bairro" }),
|
|
3852
|
+
field("UF", "checkout-state", form.state, set("state"), { placeholder: "UF" })
|
|
3853
|
+
] }),
|
|
3854
|
+
field("Cidade", TID.checkoutCity, form.city, set("city"), { placeholder: "Cidade" })
|
|
3377
3855
|
] })
|
|
3378
3856
|
] }),
|
|
3379
3857
|
/* @__PURE__ */ jsxs("section", { children: [
|
|
3380
3858
|
/* @__PURE__ */ jsx("h2", { className: "mb-3 text-xl font-semibold tracking-tight", children: "Pagamento" }),
|
|
3381
|
-
/* @__PURE__ */
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
className: `group relative rounded-lg border p-3 pr-11 text-left text-sm transition hover:bg-muted/40 ${selectedPaymentId === method.id ? "border-primary bg-primary/5" : "border-border bg-background"}`,
|
|
3386
|
-
children: [
|
|
3387
|
-
/* @__PURE__ */ jsxs("button", { type: "button", onClick: () => selectPayment(method.id), className: "block w-full text-left", children: [
|
|
3388
|
-
/* @__PURE__ */ jsxs("span", { className: "flex items-center justify-between gap-3 font-semibold", children: [
|
|
3389
|
-
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
|
|
3390
|
-
/* @__PURE__ */ jsx(CreditCard, { className: "h-4 w-4" }),
|
|
3391
|
-
method.label
|
|
3392
|
-
] }),
|
|
3393
|
-
paymentMode === "saved" && selectedPaymentId === method.id && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-primary/10 px-2 py-0.5 text-[11px] font-bold text-primary", children: "Selecionado" })
|
|
3394
|
-
] }),
|
|
3395
|
-
/* @__PURE__ */ jsxs("span", { className: "mt-1 block text-muted-foreground", children: [
|
|
3396
|
-
"Expira em ",
|
|
3397
|
-
method.expiry
|
|
3398
|
-
] })
|
|
3399
|
-
] }),
|
|
3400
|
-
/* @__PURE__ */ jsx(
|
|
3401
|
-
"button",
|
|
3402
|
-
{
|
|
3403
|
-
type: "button",
|
|
3404
|
-
onClick: () => removePayment(method.id),
|
|
3405
|
-
className: "absolute right-3 top-3 inline-flex h-8 w-8 items-center justify-center rounded-full text-muted-foreground opacity-0 transition hover:bg-destructive/10 hover:text-destructive focus:opacity-100 group-hover:opacity-100",
|
|
3406
|
-
"aria-label": `Remover cart\xE3o ${method.label}`,
|
|
3407
|
-
title: "Remover cart\xE3o",
|
|
3408
|
-
children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
|
|
3409
|
-
}
|
|
3410
|
-
)
|
|
3411
|
-
]
|
|
3412
|
-
},
|
|
3413
|
-
method.id
|
|
3414
|
-
)),
|
|
3415
|
-
/* @__PURE__ */ jsxs(
|
|
3859
|
+
/* @__PURE__ */ jsx("div", { className: "mb-3 grid gap-3", role: "radiogroup", "aria-label": "Forma de pagamento", children: paymentMethods.map((method) => {
|
|
3860
|
+
const copy = PAYMENT_LABELS[method];
|
|
3861
|
+
const selected = paymentMethod === method;
|
|
3862
|
+
return /* @__PURE__ */ jsxs(
|
|
3416
3863
|
"button",
|
|
3417
3864
|
{
|
|
3418
3865
|
type: "button",
|
|
3419
|
-
|
|
3420
|
-
|
|
3866
|
+
role: "radio",
|
|
3867
|
+
"aria-checked": selected,
|
|
3868
|
+
"data-testid": `checkout-payment-${method}`,
|
|
3869
|
+
onClick: () => setPaymentMethod(method),
|
|
3870
|
+
className: `rounded-lg border p-3 text-left text-sm transition hover:bg-muted/40 ${selected ? "border-primary bg-primary/5" : "border-border bg-background"}`,
|
|
3421
3871
|
children: [
|
|
3422
|
-
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-
|
|
3423
|
-
/* @__PURE__ */
|
|
3424
|
-
|
|
3872
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center justify-between gap-3 font-semibold", children: [
|
|
3873
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
|
|
3874
|
+
/* @__PURE__ */ jsx(CreditCard, { className: "h-4 w-4" }),
|
|
3875
|
+
copy.label
|
|
3876
|
+
] }),
|
|
3877
|
+
selected && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-primary/10 px-2 py-0.5 text-[11px] font-bold text-primary", children: "Selecionado" })
|
|
3425
3878
|
] }),
|
|
3426
|
-
/* @__PURE__ */ jsx("span", { className: "mt-1 block text-muted-foreground", children:
|
|
3879
|
+
/* @__PURE__ */ jsx("span", { className: "mt-1 block text-muted-foreground", children: copy.hint })
|
|
3427
3880
|
]
|
|
3428
|
-
}
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
placeholder: "N\xFAmero do cart\xE3o",
|
|
3434
|
-
inputMode: "numeric"
|
|
3435
|
-
}),
|
|
3436
|
-
/* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [
|
|
3437
|
-
field("Validade", TID.checkoutExpiry, form.expiry, set("expiry"), { placeholder: "MM/AA" }),
|
|
3438
|
-
field("CVC", TID.checkoutCvc, form.cvc, set("cvc"), { placeholder: "CVC", inputMode: "numeric" })
|
|
3439
|
-
] })
|
|
3440
|
-
] }),
|
|
3441
|
-
/* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: "Pagamento de demonstra\xE7\xE3o - nenhuma cobran\xE7a \xE9 feita." })
|
|
3881
|
+
},
|
|
3882
|
+
method
|
|
3883
|
+
);
|
|
3884
|
+
}) }),
|
|
3885
|
+
/* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: "Nenhuma cobran\xE7a \xE9 feita agora. Seu pedido \xE9 registrado e a loja confirma o pagamento." })
|
|
3442
3886
|
] }),
|
|
3443
3887
|
error && /* @__PURE__ */ jsx("p", { "data-testid": TID.checkoutError, className: "rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2 text-sm text-destructive", children: error })
|
|
3444
3888
|
] }),
|
|
@@ -4262,7 +4706,7 @@ function PolicyPage({ kind }) {
|
|
|
4262
4706
|
] }) })
|
|
4263
4707
|
] });
|
|
4264
4708
|
}
|
|
4265
|
-
var StorefrontErrorBoundary = class extends
|
|
4709
|
+
var StorefrontErrorBoundary = class extends React7.Component {
|
|
4266
4710
|
constructor() {
|
|
4267
4711
|
super(...arguments);
|
|
4268
4712
|
this.state = { error: null };
|
|
@@ -4417,6 +4861,15 @@ function initStorefrontRuntime(config) {
|
|
|
4417
4861
|
} else {
|
|
4418
4862
|
setShopProvider(createMockShopProvider(buildMockSeed(config)));
|
|
4419
4863
|
}
|
|
4864
|
+
const reconcileCart = () => {
|
|
4865
|
+
const provider = getShopProvider();
|
|
4866
|
+
void useCartStore.getState().reconcile(async (line) => {
|
|
4867
|
+
const product = await provider.getProduct(line.productId);
|
|
4868
|
+
return product != null;
|
|
4869
|
+
});
|
|
4870
|
+
};
|
|
4871
|
+
if (useCartStore.persist.hasHydrated()) reconcileCart();
|
|
4872
|
+
else useCartStore.persist.onFinishHydration(reconcileCart);
|
|
4420
4873
|
if (config.supabaseUrl || config.supabaseAnonKey) {
|
|
4421
4874
|
console.warn(
|
|
4422
4875
|
"@fayz-ai/shop: supabaseUrl/supabaseAnonKey are legacy fields. Pass an explicit provider/adapter or use the Fayz SDK broker path."
|
|
@@ -4548,9 +5001,9 @@ function manifestToStorefrontConfig(manifest, surfaceName) {
|
|
|
4548
5001
|
};
|
|
4549
5002
|
}
|
|
4550
5003
|
function StorefrontScaffold({ manifest, surface }) {
|
|
4551
|
-
const config =
|
|
4552
|
-
const resolved =
|
|
4553
|
-
const inited =
|
|
5004
|
+
const config = React7.useMemo(() => manifestToStorefrontConfig(manifest, surface), [manifest, surface]);
|
|
5005
|
+
const resolved = React7.useMemo(() => resolveConfig(config), [config]);
|
|
5006
|
+
const inited = React7.useRef(false);
|
|
4554
5007
|
if (!inited.current) {
|
|
4555
5008
|
initStorefrontRuntime(config);
|
|
4556
5009
|
inited.current = true;
|
|
@@ -4776,13 +5229,75 @@ var atelierTemplate = {
|
|
|
4776
5229
|
]
|
|
4777
5230
|
})
|
|
4778
5231
|
};
|
|
5232
|
+
var foodTemplate = {
|
|
5233
|
+
id: "food",
|
|
5234
|
+
inspiration: "Delivery / restaurant storefront",
|
|
5235
|
+
announcement: "ENTREGA GR\xC1TIS ACIMA DE R$ 150 \xB7 PE\xC7A J\xC1",
|
|
5236
|
+
theme: {
|
|
5237
|
+
name: "food",
|
|
5238
|
+
colors: {
|
|
5239
|
+
background: "30 33% 97%",
|
|
5240
|
+
foreground: "20 14% 15%",
|
|
5241
|
+
primary: "14 84% 50%",
|
|
5242
|
+
primaryForeground: "0 0% 100%",
|
|
5243
|
+
card: "30 33% 99%",
|
|
5244
|
+
cardForeground: "20 14% 15%",
|
|
5245
|
+
muted: "28 20% 92%",
|
|
5246
|
+
mutedForeground: "22 10% 42%",
|
|
5247
|
+
border: "28 18% 85%",
|
|
5248
|
+
headerBackground: "20 14% 11%",
|
|
5249
|
+
headerForeground: "30 24% 96%",
|
|
5250
|
+
announcementBackground: "14 84% 50%",
|
|
5251
|
+
announcementForeground: "0 0% 100%"
|
|
5252
|
+
},
|
|
5253
|
+
font: { heading: "Poppins", body: "Inter" },
|
|
5254
|
+
radius: "round",
|
|
5255
|
+
header: { variant: "classic" },
|
|
5256
|
+
productCard: { style: "card", imageAspect: "square" }
|
|
5257
|
+
},
|
|
5258
|
+
home: (storeName, images) => ({
|
|
5259
|
+
sections: [
|
|
5260
|
+
{
|
|
5261
|
+
type: "hero",
|
|
5262
|
+
variant: "banner",
|
|
5263
|
+
height: "tall",
|
|
5264
|
+
slides: [
|
|
5265
|
+
{ title: "Sabor de verdade, na sua porta", subtitle: `${storeName} \u2014 feito na hora, do jeito que voc\xEA ama.`, cta: "Ver card\xE1pio", href: "/catalog", hue: 20, image: images?.hero?.[0] }
|
|
5266
|
+
]
|
|
5267
|
+
},
|
|
5268
|
+
{
|
|
5269
|
+
type: "benefits",
|
|
5270
|
+
items: [
|
|
5271
|
+
{ icon: "Flame", title: "Feito na hora", text: "Preparado com capricho" },
|
|
5272
|
+
{ icon: "Truck", title: "Entrega r\xE1pida", text: "Frete gr\xE1tis acima de R$ 150" },
|
|
5273
|
+
{ icon: "CreditCard", title: "Pagamento f\xE1cil", text: "Pix, cart\xE3o e mais" }
|
|
5274
|
+
]
|
|
5275
|
+
},
|
|
5276
|
+
{ type: "categories", style: "tiles", title: "Nosso card\xE1pio" },
|
|
5277
|
+
{ type: "products", title: "Mais pedidos", eyebrow: "favoritos da casa", filter: "all", limit: 8 },
|
|
5278
|
+
{ type: "banner", title: "Combo do dia", eyebrow: "oferta", subtitle: "Sele\xE7\xE3o especial com desconto", cta: "Aproveitar", hue: 14, image: images?.banners?.[0] },
|
|
5279
|
+
{ type: "products", title: "Novidades no card\xE1pio", filter: "new", limit: 4 },
|
|
5280
|
+
{
|
|
5281
|
+
type: "testimonials",
|
|
5282
|
+
title: "O que dizem por a\xED",
|
|
5283
|
+
items: [
|
|
5284
|
+
{ quote: "Chegou quentinho e absurdo de bom. Virei cliente!", author: "Rafael M." },
|
|
5285
|
+
{ quote: "Sabor de restaurante em casa, sem complica\xE7\xE3o.", author: "Beatriz L." },
|
|
5286
|
+
{ quote: "Entrega r\xE1pida e por\xE7\xE3o generosa. Recomendo demais.", author: "Diego S." }
|
|
5287
|
+
]
|
|
5288
|
+
},
|
|
5289
|
+
{ type: "newsletter", title: "Receba nossas ofertas", subtitle: "Promo\xE7\xF5es e novidades do card\xE1pio, direto no seu e-mail." }
|
|
5290
|
+
]
|
|
5291
|
+
})
|
|
5292
|
+
};
|
|
4779
5293
|
var storefrontTemplates = {
|
|
4780
5294
|
mare: mareTemplate,
|
|
4781
5295
|
sertao: sertaoTemplate,
|
|
4782
5296
|
volt: voltTemplate,
|
|
4783
|
-
atelier: atelierTemplate
|
|
5297
|
+
atelier: atelierTemplate,
|
|
5298
|
+
food: foodTemplate
|
|
4784
5299
|
};
|
|
4785
5300
|
|
|
4786
|
-
export { BenefitsRow, CartDrawer, CatalogPage, CategoryShowcase, CheckoutPage, FiltersPanel, HeroSection, HomePage, Link, ManifestoBlock, MediaCarousel, MyPurchasesPage, NewsletterBand, OrderConfirmationPage, OrderTrackingTimeline, Price, ProductCard, ProductDetailPage, ProductEnquiryForm, ProductGrid, ProductOptionSelector, ProductRail, ProductSlider, PromoBanner, QuantityInput, Reveal, SmoothImage, StorefrontFooter, StorefrontHeader, StorefrontScaffold, StorefrontSections, StorefrontShell, StorefrontThemeStyle, TID, Testimonials, atelierTemplate, bannerPlaceholder, createStorefront, createStorefrontApp, defineStorefront, defineStorefrontApp, defineStorefrontComponents, defineStorefrontConfig, defineStorefrontRoutes, defineStorefrontSections, establishCustomerSession, formatMoney, formatProductOptionSelection, getCustomerAuthAdapter, getProductOptionGroups, initStorefrontRuntime, mareTemplate, matchPath, navigateTo, normalizeProductOptionSelection, placeStorefrontOrder, prefersReducedMotion, productCardComponentContract, productOptionSelectionKey, registerStorefrontBlocks, resolveAuthAdapter, roundCents, sectionsToBlocks, selectCount, selectDiscountTotal, selectShipping, selectSubtotal, selectTotal, sertaoTemplate, signInByEmail, signOutCustomer, signUpCustomer, storefrontComponentContracts, storefrontTemplates, themeToCss, useCart, useCartStore, useCatalog, useCatalogStore, useCategories, useDiscountValidator, useEnquiry, useHashPath, useInView, useMyOrders, usePopOnChange, useProduct, useProducts, useScrolled, useSessionStore, useStorefront, useStorefrontActions, useStorefrontConfig, useStorefrontConfigOptional, voltTemplate };
|
|
5301
|
+
export { BenefitsRow, CartDrawer, CatalogPage, CategoryShowcase, CheckoutPage, FiltersPanel, HeroSection, HomePage, Link, ManifestoBlock, MediaCarousel, MyPurchasesPage, NewsletterBand, OrderConfirmationPage, OrderTrackingTimeline, Price, ProductCard, ProductDetailPage, ProductEnquiryForm, ProductGrid, ProductOptionSelector, ProductRail, ProductSlider, PromoBanner, QuantityInput, Reveal, SmoothImage, StorefrontFooter, StorefrontHeader, StorefrontScaffold, StorefrontSections, StorefrontShell, StorefrontThemeStyle, TID, Testimonials, atelierTemplate, bannerPlaceholder, createStorefront, createStorefrontApp, defineStorefront, defineStorefrontApp, defineStorefrontComponents, defineStorefrontConfig, defineStorefrontRoutes, defineStorefrontSections, establishCustomerSession, foodTemplate, formatMoney, formatProductOptionSelection, getCustomerAuthAdapter, getProductOptionGroups, initStorefrontRuntime, mareTemplate, matchPath, navigateTo, normalizeProductOptionSelection, placeStorefrontOrder, prefersReducedMotion, productCardComponentContract, productOptionSelectionKey, registerStorefrontBlocks, resolveAuthAdapter, roundCents, sectionsToBlocks, selectCount, selectDiscountTotal, selectShipping, selectSubtotal, selectTotal, sertaoTemplate, signInByEmail, signOutCustomer, signUpCustomer, storefrontComponentContracts, storefrontTemplates, themeToCss, useCart, useCartStore, useCatalog, useCatalogStore, useCategories, useDiscountValidator, useEnquiry, useHashPath, useInView, useMyOrders, usePopOnChange, useProduct, useProducts, useScrolled, useSessionStore, useStorefront, useStorefrontActions, useStorefrontConfig, useStorefrontConfigOptional, voltTemplate };
|
|
4787
5302
|
//# sourceMappingURL=index.js.map
|
|
4788
5303
|
//# sourceMappingURL=index.js.map
|