@fayz-ai/storefront 0.84.0 → 0.84.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/CheckoutPage-DDY4WLFJ.js +12 -0
  2. package/dist/CheckoutPage-DDY4WLFJ.js.map +1 -0
  3. package/dist/MyPurchasesPage-IHCB5QRR.js +11 -0
  4. package/dist/MyPurchasesPage-IHCB5QRR.js.map +1 -0
  5. package/dist/OrderConfirmationPage-SAKAGOCC.js +10 -0
  6. package/dist/OrderConfirmationPage-SAKAGOCC.js.map +1 -0
  7. package/dist/app/createStorefrontApp.d.ts.map +1 -1
  8. package/dist/chunk-45R7CIEA.js +234 -0
  9. package/dist/chunk-45R7CIEA.js.map +1 -0
  10. package/dist/chunk-BKO2AQ3Q.js +329 -0
  11. package/dist/chunk-BKO2AQ3Q.js.map +1 -0
  12. package/dist/chunk-CV6RYJIC.js +454 -0
  13. package/dist/chunk-CV6RYJIC.js.map +1 -0
  14. package/dist/chunk-D5C5U2SG.js +267 -0
  15. package/dist/chunk-D5C5U2SG.js.map +1 -0
  16. package/dist/chunk-DRMDBXMT.js +2123 -0
  17. package/dist/chunk-DRMDBXMT.js.map +1 -0
  18. package/dist/chunk-DVQHKNNX.js +29 -0
  19. package/dist/chunk-DVQHKNNX.js.map +1 -0
  20. package/dist/chunk-FCPOPWG3.js +31 -0
  21. package/dist/chunk-FCPOPWG3.js.map +1 -0
  22. package/dist/chunk-GQ3TCJVX.js +216 -0
  23. package/dist/chunk-GQ3TCJVX.js.map +1 -0
  24. package/dist/{chunk-7N5HKQBM.js → chunk-GVZ2SAOI.js} +5 -552
  25. package/dist/chunk-GVZ2SAOI.js.map +1 -0
  26. package/dist/{chunk-QU5O4CKY.js → chunk-H6IOPA3J.js} +5 -4
  27. package/dist/chunk-H6IOPA3J.js.map +1 -0
  28. package/dist/{chunk-7FR6KOW2.js → chunk-HRLF5NYO.js} +1237 -6583
  29. package/dist/chunk-HRLF5NYO.js.map +1 -0
  30. package/dist/chunk-K27LYMSF.js +435 -0
  31. package/dist/chunk-K27LYMSF.js.map +1 -0
  32. package/dist/chunk-MFAU3AWK.js +817 -0
  33. package/dist/chunk-MFAU3AWK.js.map +1 -0
  34. package/dist/chunk-OHWX6BEY.js +436 -0
  35. package/dist/chunk-OHWX6BEY.js.map +1 -0
  36. package/dist/chunk-PATS4DIF.js +484 -0
  37. package/dist/chunk-PATS4DIF.js.map +1 -0
  38. package/dist/chunk-WDQFNHYO.js +41 -0
  39. package/dist/chunk-WDQFNHYO.js.map +1 -0
  40. package/dist/chunk-WPWNYBNG.js +68 -0
  41. package/dist/chunk-WPWNYBNG.js.map +1 -0
  42. package/dist/chunk-WXXYJZE6.js +99 -0
  43. package/dist/chunk-WXXYJZE6.js.map +1 -0
  44. package/dist/host.js +4 -2
  45. package/dist/host.js.map +1 -1
  46. package/dist/index.js +26 -6
  47. package/dist/index.js.map +1 -1
  48. package/dist/render.js +11 -3
  49. package/dist/render.js.map +1 -1
  50. package/dist/tanstack.js +10 -2
  51. package/dist/tanstack.js.map +1 -1
  52. package/package.json +5 -5
  53. package/dist/chunk-7FR6KOW2.js.map +0 -1
  54. package/dist/chunk-7N5HKQBM.js.map +0 -1
  55. package/dist/chunk-QU5O4CKY.js.map +0 -1
@@ -0,0 +1,484 @@
1
+ import { useStorefrontConfigOptional, currentStaticRenderPass } from './chunk-GVZ2SAOI.js';
2
+ import { create } from 'zustand';
3
+ import { persist } from 'zustand/middleware';
4
+ import { createMockAuthAdapter } from '@fayz-ai/auth';
5
+ import { createAuthRuntime } from '@fayz-ai/auth/lib/runtime';
6
+ import { getShopProvider } from '@fayz-ai/shop/runtime';
7
+ import { setShopAccessTokenResolver } from '@fayz-ai/sdk/shop';
8
+ import React, { useEffect } from 'react';
9
+ import { isStorageImageUrl, imageVariantUrl, imageSrcSet, IMAGE_SRCSET_WIDTHS } from '@fayz-ai/shop';
10
+ import { jsx } from 'react/jsx-runtime';
11
+
12
+ // src/lib/format.ts
13
+ function formatMoney(value, currency = "BRL", locale = "pt-BR") {
14
+ return new Intl.NumberFormat(locale, { style: "currency", currency }).format(value);
15
+ }
16
+ function roundCents(value) {
17
+ return Math.round(value * 100) / 100;
18
+ }
19
+ var useSessionStore = create()(
20
+ persist(
21
+ (set) => ({
22
+ customerId: null,
23
+ email: null,
24
+ name: null,
25
+ setSession: ({ customerId, email, name }) => set({ customerId, email, name: name ?? null }),
26
+ signOut: () => set({ customerId: null, email: null, name: null })
27
+ }),
28
+ { name: "fayz.storefront.session.v1" }
29
+ )
30
+ );
31
+ var EmailConfirmationRequiredError = class extends Error {
32
+ constructor(email) {
33
+ super("Cadastro realizado. Confirme seu e-mail para continuar.");
34
+ this.name = "EmailConfirmationRequiredError";
35
+ this.email = email;
36
+ }
37
+ };
38
+ var _adapter = null;
39
+ function isAuthAdapter(value) {
40
+ return Boolean(
41
+ value && typeof value === "object" && "getSession" in value && "signIn" in value && "signOut" in value
42
+ );
43
+ }
44
+ function normalizeAuthConfig(configured) {
45
+ if (!configured) return {};
46
+ if (typeof configured === "string" || isAuthAdapter(configured)) return { adapter: configured };
47
+ return configured;
48
+ }
49
+ function resolveAuthAdapter(configured, fallback) {
50
+ const config = normalizeAuthConfig(configured);
51
+ return createAuthRuntime({
52
+ provider: config.provider ?? config.adapter ?? (fallback?.supabaseUrl ? "supabase" : "mock"),
53
+ adapter: config.adapter,
54
+ routes: config.routes,
55
+ requireAuth: false,
56
+ supabase: {
57
+ url: config.supabase?.url ?? fallback?.supabaseUrl,
58
+ anonKey: config.supabase?.anonKey ?? fallback?.supabaseAnonKey,
59
+ client: config.supabase?.client,
60
+ callbackUrl: config.supabase?.callbackUrl,
61
+ resetPasswordUrl: config.supabase?.resetPasswordUrl
62
+ }
63
+ }).adapter;
64
+ }
65
+ var _accessToken = null;
66
+ var _hadAuthUser = false;
67
+ async function syncAccessToken(adapter) {
68
+ try {
69
+ const existing = await adapter.getSession();
70
+ _accessToken = existing?.session.accessToken ?? null;
71
+ } catch {
72
+ _accessToken = null;
73
+ }
74
+ }
75
+ function initCustomerAuth(adapter) {
76
+ _adapter = adapter;
77
+ setShopAccessTokenResolver(() => _accessToken);
78
+ adapter.getSession().then((existing) => {
79
+ _accessToken = existing?.session.accessToken ?? null;
80
+ if (!existing) return;
81
+ _hadAuthUser = true;
82
+ void linkCustomer(existing.user).catch(() => {
83
+ });
84
+ }).catch(() => {
85
+ });
86
+ adapter.onAuthStateChange((user) => {
87
+ if (!user) {
88
+ _accessToken = null;
89
+ if (_hadAuthUser) {
90
+ _hadAuthUser = false;
91
+ useSessionStore.getState().signOut();
92
+ }
93
+ return;
94
+ }
95
+ _hadAuthUser = true;
96
+ const linked = useSessionStore.getState();
97
+ const needsLink = !linked.customerId || (linked.email ?? "").toLowerCase() !== (user.email ?? "").toLowerCase();
98
+ void syncAccessToken(adapter).then(() => {
99
+ if (needsLink && user.email) return linkCustomer(user).then(() => void 0);
100
+ }).catch(() => {
101
+ });
102
+ });
103
+ }
104
+ function hasCustomerAuth() {
105
+ return _hadAuthUser;
106
+ }
107
+ async function relinkCustomer() {
108
+ if (!_hadAuthUser) return null;
109
+ const existing = await getCustomerAuthAdapter().getSession().catch(() => null);
110
+ if (!existing?.user.email) return null;
111
+ const customer = await resolveShopCustomer(existing.user.email.trim().toLowerCase(), existing.user.fullName ?? "");
112
+ const store = useSessionStore.getState();
113
+ store.setSession({ customerId: customer.id, email: existing.user.email.trim().toLowerCase(), name: store.name });
114
+ return { customerId: customer.id, phone: customer.phone ?? null, document: customer.document ?? null };
115
+ }
116
+ function getCustomerAuthAdapter() {
117
+ if (!_adapter) _adapter = createMockAuthAdapter();
118
+ return _adapter;
119
+ }
120
+ async function resolveShopCustomer(email, name) {
121
+ const provider = getShopProvider();
122
+ if (provider.resolveCustomer) return provider.resolveCustomer({ email, name });
123
+ const matches = await provider.listCustomers({ search: email, limit: 10 });
124
+ const existing = matches.find((c) => (c.email ?? "").toLowerCase() === email);
125
+ if (existing) return existing;
126
+ const parts = name.trim().split(/\s+/).filter(Boolean);
127
+ return provider.createCustomer({
128
+ firstName: parts[0] ?? email.split("@")[0] ?? "Cliente",
129
+ lastName: parts.slice(1).join(" "),
130
+ email
131
+ });
132
+ }
133
+ async function linkCustomer(user, fullName) {
134
+ const email = (user.email ?? "").trim().toLowerCase();
135
+ const name = fullName ?? user.fullName ?? "";
136
+ const customer = await resolveShopCustomer(email, name);
137
+ useSessionStore.getState().setSession({
138
+ customerId: customer.id,
139
+ email,
140
+ name: name || `${customer.firstName} ${customer.lastName}`.trim()
141
+ });
142
+ return { customerId: customer.id };
143
+ }
144
+ async function establishCustomerSession(email, opts) {
145
+ const normalized = email.trim().toLowerCase();
146
+ if (opts?.password) {
147
+ const adapter = getCustomerAuthAdapter();
148
+ const session = await adapter.signIn(normalized, opts.password);
149
+ _accessToken = session.accessToken ?? null;
150
+ _hadAuthUser = true;
151
+ return linkCustomer(session.user.email ? session.user : { ...session.user, email: normalized }, opts.name);
152
+ }
153
+ return linkCustomer({ email: normalized }, opts?.name);
154
+ }
155
+ function signInByEmail(email, name) {
156
+ return establishCustomerSession(email, { name });
157
+ }
158
+ async function signUpCustomer(email, password, name) {
159
+ const adapter = getCustomerAuthAdapter();
160
+ const normalized = email.trim().toLowerCase();
161
+ const session = await adapter.signUp(normalized, password, name);
162
+ if (!session.accessToken) throw new EmailConfirmationRequiredError(normalized);
163
+ _accessToken = session.accessToken;
164
+ _hadAuthUser = true;
165
+ return linkCustomer(session.user.email ? session.user : { ...session.user, email: normalized }, name);
166
+ }
167
+ async function signOutCustomer() {
168
+ try {
169
+ await getCustomerAuthAdapter().signOut();
170
+ } finally {
171
+ _accessToken = null;
172
+ _hadAuthUser = false;
173
+ useSessionStore.getState().signOut();
174
+ }
175
+ }
176
+
177
+ // src/lib/testids.ts
178
+ var TID = {
179
+ // header
180
+ headerSearch: "header-search",
181
+ headerSearchToggle: "header-search-toggle",
182
+ searchOverlay: "search-overlay",
183
+ searchOverlayInput: "search-overlay-input",
184
+ searchOverlayClose: "search-overlay-close",
185
+ searchOverlayCta: "search-overlay-cta",
186
+ searchSuggestion: "search-suggestion",
187
+ cartButton: "cart-button",
188
+ cartCount: "cart-count",
189
+ accountLink: "account-link",
190
+ accountDropdown: "account-dropdown",
191
+ announcementBar: "announcement-bar",
192
+ navLink: (label) => `nav-${label.toLowerCase().replace(/\s+/g, "-")}`,
193
+ navCategory: (slug) => `nav-cat-${slug}`,
194
+ accountName: "account-name",
195
+ // home sections
196
+ hero: "home-hero",
197
+ heroPrev: "hero-prev",
198
+ heroNext: "hero-next",
199
+ mediaCarousel: "media-carousel",
200
+ mediaCarouselPrev: "media-carousel-prev",
201
+ mediaCarouselNext: "media-carousel-next",
202
+ productSlider: "product-slider",
203
+ productSliderViewport: "product-slider-viewport",
204
+ productSliderPrev: "product-slider-prev",
205
+ productSliderNext: "product-slider-next",
206
+ categoryShowcase: "category-showcase",
207
+ productRail: "product-rail",
208
+ entityList: "entity-list",
209
+ benefits: "benefits-row",
210
+ promoBanner: "promo-banner",
211
+ manifesto: "manifesto",
212
+ testimonials: "testimonials",
213
+ newsletter: "newsletter",
214
+ newsletterEmail: "newsletter-email",
215
+ newsletterSubmit: "newsletter-submit",
216
+ newsletterDone: "newsletter-done",
217
+ formBlock: "form-block",
218
+ formBlockField: (id) => `form-block-field-${id}`,
219
+ formBlockSubmit: "form-block-submit",
220
+ formBlockSuccess: "form-block-success",
221
+ formBlockError: "form-block-error",
222
+ // collection / campaign page blocks
223
+ collectionHero: "collection-hero",
224
+ collectionHeroCta: "collection-hero-cta",
225
+ productSpotlight: "product-spotlight",
226
+ productSpotlightCta: "product-spotlight-cta",
227
+ motifStrip: "motif-strip",
228
+ collectionCta: "collection-cta",
229
+ collectionCtaButton: "collection-cta-button",
230
+ // catalog
231
+ productGrid: "product-grid",
232
+ productCard: "product-card",
233
+ productCardName: "product-card-name",
234
+ productCardPrice: "product-card-price",
235
+ productCardAdd: "product-card-add",
236
+ badgeSale: "badge-sale",
237
+ badgeSoldout: "badge-soldout",
238
+ // filters
239
+ filterCategory: (slug) => `filter-category-${slug}`,
240
+ filterPriceMin: "filter-price-min",
241
+ filterPriceMax: "filter-price-max",
242
+ filterInstock: "filter-instock",
243
+ sortSelect: "sort-select",
244
+ filtersClear: "filters-clear",
245
+ // product detail
246
+ pdpName: "pdp-name",
247
+ pdpPrice: "pdp-price",
248
+ pdpComparePrice: "pdp-compare-price",
249
+ pdpDescription: "pdp-description",
250
+ productOptionGroup: (id) => `product-option-${id.toLowerCase().replace(/\s+/g, "-")}`,
251
+ productOptionValue: (id, value) => `product-option-${id.toLowerCase().replace(/\s+/g, "-")}-${value.toLowerCase().replace(/\s+/g, "-")}`,
252
+ pdpQtyInput: "pdp-qty-input",
253
+ pdpAddToCart: "pdp-add-to-cart",
254
+ pdpRoot: "pdp-root",
255
+ pdpGallery: "pdp-gallery",
256
+ pdpGalleryImage: "pdp-gallery-image",
257
+ pdpGalleryThumbs: "pdp-gallery-thumbs",
258
+ pdpGalleryThumb: "pdp-gallery-thumb",
259
+ pdpActions: "pdp-actions",
260
+ pdpEnquiryButton: "pdp-enquiry-button",
261
+ enquiryForm: "enquiry-form",
262
+ enquiryName: "enquiry-name",
263
+ enquiryEmail: "enquiry-email",
264
+ enquiryPhone: "enquiry-phone",
265
+ enquirySubject: "enquiry-subject",
266
+ enquiryMessage: "enquiry-message",
267
+ enquirySubmit: "enquiry-submit",
268
+ enquirySuccess: "enquiry-success",
269
+ enquiryError: "enquiry-error",
270
+ // cart
271
+ cartDrawer: "cart-drawer",
272
+ cartLinesList: "cart-lines-list",
273
+ cartFooter: "cart-footer",
274
+ cartLine: "cart-line",
275
+ lineQty: "line-qty",
276
+ lineInc: "line-inc",
277
+ lineDec: "line-dec",
278
+ lineRemove: "line-remove",
279
+ cartSubtotal: "cart-subtotal",
280
+ discountInput: "discount-input",
281
+ discountApply: "discount-apply",
282
+ discountRow: "discount-row",
283
+ discountError: "discount-error",
284
+ cartShipping: "cart-shipping",
285
+ shippingProgress: "shipping-progress",
286
+ cartTotal: "cart-total",
287
+ goCheckout: "go-checkout",
288
+ cartEmpty: "cart-empty",
289
+ // menu / delivery mode (0094)
290
+ menuPage: "menu-page",
291
+ menuSection: (slug) => `menu-section-${slug}`,
292
+ menuItem: (slug) => `menu-item-${slug}`,
293
+ menuQuickAdd: (slug) => `menu-quick-add-${slug}`,
294
+ devPlaceOrderWithoutCharge: "dev-place-order-without-charge",
295
+ menuCartBar: "menu-cart-bar",
296
+ menuItemSoldOut: "menu-sold-out",
297
+ itemSheet: "item-sheet",
298
+ itemSheetNotes: "item-sheet-notes",
299
+ itemSheetNotesCount: "item-sheet-notes-count",
300
+ itemSheetQty: "item-sheet-qty",
301
+ itemSheetAdd: "item-sheet-add",
302
+ serviceStatus: "service-status",
303
+ serviceHoursModal: "service-hours-modal",
304
+ serviceClosedGate: "service-closed-gate",
305
+ fulfillmentMode: (mode) => `fulfillment-mode-${mode}`,
306
+ scheduleSheet: "schedule-sheet",
307
+ scheduleSlot: (iso) => `schedule-slot-${iso}`,
308
+ storeCover: "store-cover",
309
+ menuSearch: "menu-search",
310
+ menuCategoryNav: "menu-category-nav",
311
+ menuCategoryLink: (slug) => `menu-category-link-${slug}`,
312
+ menuHighlights: "menu-highlights",
313
+ menuItemBadge: (slug) => `menu-item-badge-${slug}`,
314
+ deliveryTabBar: "delivery-tab-bar",
315
+ deliveryTab: (key) => `delivery-tab-${key}`,
316
+ addressStrip: "address-strip",
317
+ addressSheet: "address-sheet",
318
+ addressCep: "address-cep",
319
+ addressNumber: "address-number",
320
+ addressComplement: "address-complement",
321
+ addressReference: "address-reference",
322
+ addressSave: "address-save",
323
+ addressAddNew: "address-add-new",
324
+ savedAddress: (id) => `saved-address-${id}`,
325
+ itemSheetGroup: (label) => `item-sheet-group-${label}`,
326
+ // delivery estimate (product page + cart)
327
+ deliveryEstimator: "delivery-estimator",
328
+ deliveryCepInput: "delivery-cep-input",
329
+ deliveryCepSubmit: "delivery-cep-submit",
330
+ deliveryOption: "delivery-option",
331
+ deliveryUnserved: "delivery-unserved",
332
+ deliveryError: "delivery-error",
333
+ deliveryAddress: "delivery-address",
334
+ deliveryClear: "delivery-clear",
335
+ // checkout
336
+ checkoutEmail: "checkout-email",
337
+ checkoutName: "checkout-name",
338
+ checkoutDocument: "checkout-document",
339
+ checkoutStreet: "checkout-street",
340
+ checkoutCity: "checkout-city",
341
+ checkoutZip: "checkout-zip",
342
+ checkoutCard: "checkout-card",
343
+ checkoutExpiry: "checkout-expiry",
344
+ checkoutCvc: "checkout-cvc",
345
+ placeOrder: "place-order",
346
+ // checkout em passos
347
+ checkoutSteps: "checkout-steps",
348
+ checkoutStep: (n) => `checkout-step-${n}`,
349
+ checkoutPayment: "checkout-payment",
350
+ checkoutPaymentTotal: "checkout-payment-total",
351
+ checkoutContinue: "checkout-continue",
352
+ checkoutBack: "checkout-back",
353
+ checkoutDone: "checkout-done",
354
+ // payment step
355
+ pixPanel: "pix-panel",
356
+ pixCode: "pix-code",
357
+ pixCopy: "pix-copy",
358
+ pixConfirm: "pix-confirm",
359
+ checkoutError: "checkout-error",
360
+ checkoutProcessing: "checkout-processing",
361
+ // confirmation
362
+ orderNumber: "order-number",
363
+ orderStatus: "order-status",
364
+ orderTracking: "order-tracking",
365
+ orderTrackingStep: (step) => `order-tracking-step-${step}`,
366
+ orderTotal: "order-total",
367
+ viewPurchases: "view-purchases",
368
+ // account
369
+ customerAccountShell: "customer-account-shell",
370
+ customerAccountMenu: "customer-account-menu",
371
+ orderDetail: "order-detail",
372
+ authTabSignin: "auth-tab-signin",
373
+ authTabSignup: "auth-tab-signup",
374
+ signinEmail: "signin-email",
375
+ signinPassword: "signin-password",
376
+ signinPasswordConfirm: "signin-password-confirm",
377
+ signinName: "signin-name",
378
+ signinSubmit: "signin-submit",
379
+ authError: "auth-error",
380
+ authNotice: "auth-notice",
381
+ checkoutExpired: "checkout-expired",
382
+ purchasesList: "purchases-list",
383
+ purchaseItem: "purchase-item",
384
+ purchasesEmpty: "purchases-empty",
385
+ signout: "signout"
386
+ };
387
+ var clientMounted = false;
388
+ function SmoothImage({
389
+ imageLoading,
390
+ variant,
391
+ loading = "lazy",
392
+ decoding = "async",
393
+ onLoad,
394
+ style,
395
+ src,
396
+ srcSet,
397
+ sizes,
398
+ ...props
399
+ }) {
400
+ const config = useStorefrontConfigOptional();
401
+ const resolved = {
402
+ ...config?.imageLoading,
403
+ ...imageLoading
404
+ };
405
+ const mode = resolved.mode ?? "fade";
406
+ const durationMs = resolved.durationMs ?? 420;
407
+ const easing = resolved.easing ?? "cubic-bezier(0.22, 1, 0.36, 1)";
408
+ const blur = resolved.blur ?? true;
409
+ const transform = resolved.transform ?? "none";
410
+ const ref = React.useRef(null);
411
+ const [loaded, setLoaded] = React.useState(() => mode === "none" || !clientMounted);
412
+ const delivered = React.useMemo(() => {
413
+ if (transform !== "supabase" || !src || srcSet || !isStorageImageUrl(src)) return { src, srcSet, sizes };
414
+ if (variant?.width) {
415
+ const w = variant.width;
416
+ const q = variant.quality;
417
+ return {
418
+ src: imageVariantUrl(src, { width: w, quality: q }),
419
+ srcSet: `${imageVariantUrl(src, { width: w, quality: q })} 1x, ${imageVariantUrl(src, { width: w * 2, quality: q })} 2x`,
420
+ sizes
421
+ };
422
+ }
423
+ return {
424
+ // A middle rung as the fallback `src`, for a browser without srcset.
425
+ src: imageVariantUrl(src, { width: 960, quality: variant?.quality }),
426
+ srcSet: imageSrcSet(src, variant?.widths ?? IMAGE_SRCSET_WIDTHS, { quality: variant?.quality }),
427
+ sizes: variant?.sizes ?? sizes ?? "100vw"
428
+ };
429
+ }, [transform, src, srcSet, sizes, variant?.width, variant?.sizes, variant?.widths, variant?.quality]);
430
+ React.useEffect(() => {
431
+ clientMounted = true;
432
+ }, []);
433
+ React.useEffect(() => {
434
+ if (mode === "none") {
435
+ setLoaded(true);
436
+ return;
437
+ }
438
+ if (ref.current?.complete && ref.current.naturalWidth > 0) setLoaded(true);
439
+ }, [mode, delivered.src]);
440
+ const revealStyle = mode === "none" ? {} : {
441
+ opacity: loaded ? 1 : 0,
442
+ filter: blur && !loaded ? "blur(10px)" : "blur(0px)",
443
+ transition: `opacity ${durationMs}ms ${easing}, filter ${durationMs}ms ${easing}, transform ${durationMs}ms ${easing}`
444
+ };
445
+ return /* @__PURE__ */ jsx(
446
+ "img",
447
+ {
448
+ ...props,
449
+ src: delivered.src,
450
+ srcSet: delivered.srcSet,
451
+ sizes: delivered.sizes,
452
+ ref,
453
+ loading,
454
+ decoding,
455
+ "data-sf-image-loaded": loaded ? "true" : "false",
456
+ style: { ...style, ...revealStyle },
457
+ onLoad: (event) => {
458
+ setLoaded(true);
459
+ onLoad?.(event);
460
+ }
461
+ }
462
+ );
463
+ }
464
+ function useStorefrontHead(input) {
465
+ const { title, description } = input;
466
+ currentStaticRenderPass()?.head(input);
467
+ useEffect(() => {
468
+ if (title) document.title = title;
469
+ }, [title]);
470
+ useEffect(() => {
471
+ if (!description) return;
472
+ let tag = document.head.querySelector('meta[name="description"]');
473
+ if (!tag) {
474
+ tag = document.createElement("meta");
475
+ tag.setAttribute("name", "description");
476
+ document.head.appendChild(tag);
477
+ }
478
+ tag.setAttribute("content", description.slice(0, 160));
479
+ }, [description]);
480
+ }
481
+
482
+ export { EmailConfirmationRequiredError, SmoothImage, TID, establishCustomerSession, formatMoney, getCustomerAuthAdapter, hasCustomerAuth, initCustomerAuth, relinkCustomer, resolveAuthAdapter, roundCents, signInByEmail, signOutCustomer, signUpCustomer, useSessionStore, useStorefrontHead };
483
+ //# sourceMappingURL=chunk-PATS4DIF.js.map
484
+ //# sourceMappingURL=chunk-PATS4DIF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/format.ts","../src/stores/session.store.ts","../src/data/auth.ts","../src/lib/testids.ts","../src/components/SmoothImage.tsx","../src/hooks/use-storefront-head.ts"],"names":[],"mappings":"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","file":"chunk-PATS4DIF.js","sourcesContent":["export function formatMoney(value: number, currency = 'BRL', locale = 'pt-BR'): string {\n return new Intl.NumberFormat(locale, { style: 'currency', currency }).format(value)\n}\n\nexport function roundCents(value: number): number {\n return Math.round(value * 100) / 100\n}\n","import { create } from 'zustand'\nimport { persist } from 'zustand/middleware'\n\n// Customer session state. Identity is established through the shared\n// @fayz-ai/auth AuthAdapter (see ../auth.ts) — this store only mirrors the\n// linked ShopCustomer for synchronous UI access.\n\nexport interface SessionState {\n customerId: string | null\n email: string | null\n name: string | null\n setSession(session: { customerId: string; email: string; name?: string | null }): void\n signOut(): void\n}\n\nexport const useSessionStore = create<SessionState>()(\n persist(\n (set) => ({\n customerId: null,\n email: null,\n name: null,\n setSession: ({ customerId, email, name }) =>\n set({ customerId, email, name: name ?? null }),\n signOut: () => set({ customerId: null, email: null, name: null }),\n }),\n { name: 'fayz.storefront.session.v1' },\n ),\n)\n","import type { AuthAdapter, AuthUser } from '@fayz-ai/core'\nimport { createMockAuthAdapter } from '@fayz-ai/auth'\nimport { createAuthRuntime } from '@fayz-ai/auth/lib/runtime'\nimport type { AuthPluginOptions } from '@fayz-ai/auth/domain/auth-config'\nimport { getShopProvider } from '@fayz-ai/shop/runtime'\nimport { setShopAccessTokenResolver } from '@fayz-ai/sdk/shop'\nimport { useSessionStore } from '../stores/session.store'\n\n// ---------------------------------------------------------------------------\n// Customer auth — the SAME AuthAdapter contract createSaasApp uses, so the\n// mock and Supabase adapters from @fayz-ai/auth serve both the saas admin and\n// the storefront customer. The storefront adds one layer on top: linking the\n// auth identity to a ShopCustomer record (find-or-create by email) so orders\n// and purchase history attach to a customer.\n// ---------------------------------------------------------------------------\n\nexport type StorefrontAuthAdapter = AuthAdapter | 'mock' | 'supabase' | (string & {})\n\n/** Thrown by signUpCustomer when the adapter reports a user but no live\n * session (Supabase's signal for \"email confirmation required\" — see\n * createSupabaseAuthAdapter's signUp, which returns accessToken: '' instead\n * of null/an error). Signup succeeded; the customer just isn't authenticated\n * yet, so we must not link/persist a session for them. */\nexport class EmailConfirmationRequiredError extends Error {\n readonly email: string\n\n constructor(email: string) {\n super('Cadastro realizado. Confirme seu e-mail para continuar.')\n this.name = 'EmailConfirmationRequiredError'\n this.email = email\n }\n}\n\nexport interface StorefrontAuthConfig {\n adapter?: AuthPluginOptions['adapter']\n provider?: AuthPluginOptions['provider']\n routes?: AuthPluginOptions['routes']\n supabase?: AuthPluginOptions['supabase']\n}\n\nlet _adapter: AuthAdapter | null = null\n\nfunction isAuthAdapter(value: unknown): value is AuthAdapter {\n return Boolean(\n value &&\n typeof value === 'object' &&\n 'getSession' in value &&\n 'signIn' in value &&\n 'signOut' in value,\n )\n}\n\nfunction normalizeAuthConfig(\n configured: StorefrontAuthAdapter | StorefrontAuthConfig | undefined,\n): StorefrontAuthConfig {\n if (!configured) return {}\n if (typeof configured === 'string' || isAuthAdapter(configured)) return { adapter: configured }\n return configured\n}\n\nexport function resolveAuthAdapter(\n configured: StorefrontAuthAdapter | StorefrontAuthConfig | undefined,\n fallback?: { supabaseUrl?: string; supabaseAnonKey?: string },\n): AuthAdapter {\n const config = normalizeAuthConfig(configured)\n return createAuthRuntime({\n provider: config.provider ?? config.adapter ?? (fallback?.supabaseUrl ? 'supabase' : 'mock'),\n adapter: config.adapter,\n routes: config.routes,\n requireAuth: false,\n supabase: {\n url: config.supabase?.url ?? fallback?.supabaseUrl,\n anonKey: config.supabase?.anonKey ?? fallback?.supabaseAnonKey,\n client: config.supabase?.client,\n callbackUrl: config.supabase?.callbackUrl,\n resetPasswordUrl: config.supabase?.resetPasswordUrl,\n },\n }).adapter\n}\n\n// The shopper's current access token, handed to the shop REST client so its\n// requests reach PostgREST as the signed-in user instead of as `anon`. Held\n// here rather than in the session store because it is a credential: it must not\n// be persisted to localStorage alongside the customer id. The Supabase client\n// owns its own refresh; this is only a mirror of the live value.\nlet _accessToken: string | null = null\n\n/** Whether an authenticated identity was ever seen this session. Distinguishes\n * \"signed out\" from \"was never signed in\" — see the onAuthStateChange guard. */\nlet _hadAuthUser = false\n\n/** Refresh the mirrored token from the adapter. Safe to call on any event. */\nasync function syncAccessToken(adapter: AuthAdapter): Promise<void> {\n try {\n const existing = await adapter.getSession()\n _accessToken = existing?.session.accessToken ?? null\n } catch {\n _accessToken = null\n }\n}\n\n/** Called once by createStorefrontApp. Restores any persisted session. */\nexport function initCustomerAuth(adapter: AuthAdapter): void {\n _adapter = adapter\n\n // Registered before the first await so no request can slip out anonymously\n // while the session is still being restored.\n setShopAccessTokenResolver(() => _accessToken)\n\n adapter\n .getSession()\n .then((existing) => {\n _accessToken = existing?.session.accessToken ?? null\n if (!existing) return\n _hadAuthUser = true\n // Every boot, not only on an email change: the persisted id goes stale\n // with the same email, and this call is what writes auth_user_id, which\n // the phone/CPF prefill and save both filter on.\n void linkCustomer(existing.user).catch(() => {})\n })\n .catch(() => {})\n\n adapter.onAuthStateChange((user) => {\n if (!user) {\n _accessToken = null\n // Only tear down the shop session if there WAS an authenticated identity\n // to lose. The Supabase adapter fires this once on boot with a null user\n // (INITIAL_SESSION), and clearing unconditionally wiped the guest's local\n // session on every page load — a guest who checked out could no longer\n // find their order after a reload. The mock adapter never surfaced this\n // because it always restored a session.\n if (_hadAuthUser) {\n _hadAuthUser = false\n useSessionStore.getState().signOut()\n }\n return\n }\n _hadAuthUser = true\n // Covers token refresh too, not just sign-in: the callback carries the user\n // but not the token, and a stale token would 401 every read an hour in.\n // Magic link / OAuth sign-ins arrive only here; link once the token is live.\n const linked = useSessionStore.getState()\n const needsLink = !linked.customerId\n || (linked.email ?? '').toLowerCase() !== (user.email ?? '').toLowerCase()\n void syncAccessToken(adapter).then(() => {\n if (needsLink && user.email) return linkCustomer(user).then(() => undefined)\n }).catch(() => {})\n })\n}\n\n/** True once an authenticated shopper identity has been seen this session. */\nexport function hasCustomerAuth(): boolean {\n return _hadAuthUser\n}\n\n/** Re-resolve the signed-in shopper's row (phone and document included) and re-point the session at it. */\nexport async function relinkCustomer(): Promise<{ customerId: string; phone: string | null; document: string | null } | null> {\n if (!_hadAuthUser) return null\n const existing = await getCustomerAuthAdapter().getSession().catch(() => null)\n if (!existing?.user.email) return null\n const customer = await resolveShopCustomer(existing.user.email.trim().toLowerCase(), existing.user.fullName ?? '')\n const store = useSessionStore.getState()\n store.setSession({ customerId: customer.id, email: existing.user.email.trim().toLowerCase(), name: store.name })\n return { customerId: customer.id, phone: customer.phone ?? null, document: customer.document ?? null }\n}\n\nexport function getCustomerAuthAdapter(): AuthAdapter {\n if (!_adapter) _adapter = createMockAuthAdapter()\n return _adapter\n}\n\n/** Resolve (find-or-create + server-side auth link) the ShopCustomer for an email. */\nasync function resolveShopCustomer(email: string, name: string) {\n const provider = getShopProvider()\n // Preferred: provider.resolveCustomer find-or-creates AND links auth.uid\n // server-side (RLS-safe). Falls back to generic CRUD for legacy providers.\n if (provider.resolveCustomer) return provider.resolveCustomer({ email, name })\n const matches = await provider.listCustomers({ search: email, limit: 10 })\n const existing = matches.find((c) => (c.email ?? '').toLowerCase() === email)\n if (existing) return existing\n const parts = name.trim().split(/\\s+/).filter(Boolean)\n return provider.createCustomer({\n firstName: parts[0] ?? email.split('@')[0] ?? 'Cliente',\n lastName: parts.slice(1).join(' '),\n email,\n })\n}\n\n/** Find-or-create the ShopCustomer for an auth identity and persist the session. */\nasync function linkCustomer(user: AuthUser, fullName?: string): Promise<{ customerId: string }> {\n const email = (user.email ?? '').trim().toLowerCase()\n const name = fullName ?? user.fullName ?? ''\n const customer = await resolveShopCustomer(email, name)\n useSessionStore.getState().setSession({\n customerId: customer.id,\n email,\n name: name || `${customer.firstName} ${customer.lastName}`.trim(),\n })\n return { customerId: customer.id }\n}\n\nexport interface EstablishSessionOptions {\n /** Provided → adapter.signIn; omitted → passwordless customer identity via signUp (mock-friendly). */\n password?: string\n name?: string\n}\n\n/**\n * Sign a customer in through the auth adapter and link the ShopCustomer.\n * Used by the account page sign-in AND by checkout (so a buyer is signed in\n * for \"my purchases\" immediately after purchase) — one auth path, two doors.\n */\nexport async function establishCustomerSession(\n email: string,\n opts?: EstablishSessionOptions,\n): Promise<{ customerId: string }> {\n const normalized = email.trim().toLowerCase()\n if (opts?.password) {\n const adapter = getCustomerAuthAdapter()\n const session = await adapter.signIn(normalized, opts.password)\n // Before linkCustomer, not after: linkCustomer calls shop_resolve_customer,\n // which reads auth.uid() to fill auth_user_id. Sent with the old token that\n // link silently no-ops and the account stays unlinked forever.\n _accessToken = session.accessToken ?? null\n _hadAuthUser = true\n return linkCustomer(session.user.email ? session.user : { ...session.user, email: normalized }, opts.name)\n }\n // Guest / passwordless checkout: do NOT create an auth account (that made\n // returning guests fail with \"user already registered\" on Supabase). Just\n // resolve the ShopCustomer and persist the local session for order history.\n return linkCustomer({ id: '', email: normalized } as AuthUser, opts?.name)\n}\n\n/** Convenience wrapper — passwordless email sign-in (guest checkout path). */\nexport function signInByEmail(email: string, name?: string): Promise<{ customerId: string }> {\n return establishCustomerSession(email, { name })\n}\n\n/** Explicit account creation (account page \"Criar conta\" form). */\nexport async function signUpCustomer(\n email: string,\n password: string,\n name: string,\n): Promise<{ customerId: string }> {\n const adapter = getCustomerAuthAdapter()\n const normalized = email.trim().toLowerCase()\n const session = await adapter.signUp(normalized, password, name)\n // Empty accessToken == account created but not authenticated (email\n // confirmation pending). Do NOT link/persist a session for an unconfirmed\n // user — see EmailConfirmationRequiredError.\n if (!session.accessToken) throw new EmailConfirmationRequiredError(normalized)\n _accessToken = session.accessToken\n _hadAuthUser = true\n return linkCustomer(session.user.email ? session.user : { ...session.user, email: normalized }, name)\n}\n\nexport async function signOutCustomer(): Promise<void> {\n try {\n await getCustomerAuthAdapter().signOut()\n } finally {\n _accessToken = null\n _hadAuthUser = false\n useSessionStore.getState().signOut()\n }\n}\n","// Single source of truth for e2e selectors. Components import from here;\n// Playwright specs assert against the same constants — they cannot drift.\nexport const TID = {\n // header\n headerSearch: 'header-search',\n headerSearchToggle: 'header-search-toggle',\n searchOverlay: 'search-overlay',\n searchOverlayInput: 'search-overlay-input',\n searchOverlayClose: 'search-overlay-close',\n searchOverlayCta: 'search-overlay-cta',\n searchSuggestion: 'search-suggestion',\n cartButton: 'cart-button',\n cartCount: 'cart-count',\n accountLink: 'account-link',\n accountDropdown: 'account-dropdown',\n announcementBar: 'announcement-bar',\n navLink: (label: string) => `nav-${label.toLowerCase().replace(/\\s+/g, '-')}`,\n navCategory: (slug: string) => `nav-cat-${slug}`,\n accountName: 'account-name',\n // home sections\n hero: 'home-hero',\n heroPrev: 'hero-prev',\n heroNext: 'hero-next',\n mediaCarousel: 'media-carousel',\n mediaCarouselPrev: 'media-carousel-prev',\n mediaCarouselNext: 'media-carousel-next',\n productSlider: 'product-slider',\n productSliderViewport: 'product-slider-viewport',\n productSliderPrev: 'product-slider-prev',\n productSliderNext: 'product-slider-next',\n categoryShowcase: 'category-showcase',\n productRail: 'product-rail',\n entityList: 'entity-list',\n benefits: 'benefits-row',\n promoBanner: 'promo-banner',\n manifesto: 'manifesto',\n testimonials: 'testimonials',\n newsletter: 'newsletter',\n newsletterEmail: 'newsletter-email',\n newsletterSubmit: 'newsletter-submit',\n newsletterDone: 'newsletter-done',\n formBlock: 'form-block',\n formBlockField: (id: string) => `form-block-field-${id}`,\n formBlockSubmit: 'form-block-submit',\n formBlockSuccess: 'form-block-success',\n formBlockError: 'form-block-error',\n // collection / campaign page blocks\n collectionHero: 'collection-hero',\n collectionHeroCta: 'collection-hero-cta',\n productSpotlight: 'product-spotlight',\n productSpotlightCta: 'product-spotlight-cta',\n motifStrip: 'motif-strip',\n collectionCta: 'collection-cta',\n collectionCtaButton: 'collection-cta-button',\n // catalog\n productGrid: 'product-grid',\n productCard: 'product-card',\n productCardName: 'product-card-name',\n productCardPrice: 'product-card-price',\n productCardAdd: 'product-card-add',\n badgeSale: 'badge-sale',\n badgeSoldout: 'badge-soldout',\n // filters\n filterCategory: (slug: string) => `filter-category-${slug}`,\n filterPriceMin: 'filter-price-min',\n filterPriceMax: 'filter-price-max',\n filterInstock: 'filter-instock',\n sortSelect: 'sort-select',\n filtersClear: 'filters-clear',\n // product detail\n pdpName: 'pdp-name',\n pdpPrice: 'pdp-price',\n pdpComparePrice: 'pdp-compare-price',\n pdpDescription: 'pdp-description',\n productOptionGroup: (id: string) => `product-option-${id.toLowerCase().replace(/\\s+/g, '-')}`,\n productOptionValue: (id: string, value: string) => `product-option-${id.toLowerCase().replace(/\\s+/g, '-')}-${value.toLowerCase().replace(/\\s+/g, '-')}`,\n pdpQtyInput: 'pdp-qty-input',\n pdpAddToCart: 'pdp-add-to-cart',\n pdpRoot: 'pdp-root',\n pdpGallery: 'pdp-gallery',\n pdpGalleryImage: 'pdp-gallery-image',\n pdpGalleryThumbs: 'pdp-gallery-thumbs',\n pdpGalleryThumb: 'pdp-gallery-thumb',\n pdpActions: 'pdp-actions',\n pdpEnquiryButton: 'pdp-enquiry-button',\n enquiryForm: 'enquiry-form',\n enquiryName: 'enquiry-name',\n enquiryEmail: 'enquiry-email',\n enquiryPhone: 'enquiry-phone',\n enquirySubject: 'enquiry-subject',\n enquiryMessage: 'enquiry-message',\n enquirySubmit: 'enquiry-submit',\n enquirySuccess: 'enquiry-success',\n enquiryError: 'enquiry-error',\n // cart\n cartDrawer: 'cart-drawer',\n cartLinesList: 'cart-lines-list',\n cartFooter: 'cart-footer',\n cartLine: 'cart-line',\n lineQty: 'line-qty',\n lineInc: 'line-inc',\n lineDec: 'line-dec',\n lineRemove: 'line-remove',\n cartSubtotal: 'cart-subtotal',\n discountInput: 'discount-input',\n discountApply: 'discount-apply',\n discountRow: 'discount-row',\n discountError: 'discount-error',\n cartShipping: 'cart-shipping',\n shippingProgress: 'shipping-progress',\n cartTotal: 'cart-total',\n goCheckout: 'go-checkout',\n cartEmpty: 'cart-empty',\n // menu / delivery mode (0094)\n menuPage: 'menu-page',\n menuSection: (slug: string) => `menu-section-${slug}`,\n menuItem: (slug: string) => `menu-item-${slug}`,\n menuQuickAdd: (slug: string) => `menu-quick-add-${slug}`,\n devPlaceOrderWithoutCharge: 'dev-place-order-without-charge',\n menuCartBar: 'menu-cart-bar',\n menuItemSoldOut: 'menu-sold-out',\n itemSheet: 'item-sheet',\n itemSheetNotes: 'item-sheet-notes',\n itemSheetNotesCount: 'item-sheet-notes-count',\n itemSheetQty: 'item-sheet-qty',\n itemSheetAdd: 'item-sheet-add',\n serviceStatus: 'service-status',\n serviceHoursModal: 'service-hours-modal',\n serviceClosedGate: 'service-closed-gate',\n fulfillmentMode: (mode: string) => `fulfillment-mode-${mode}`,\n scheduleSheet: 'schedule-sheet',\n scheduleSlot: (iso: string) => `schedule-slot-${iso}`,\n storeCover: 'store-cover',\n menuSearch: 'menu-search',\n menuCategoryNav: 'menu-category-nav',\n menuCategoryLink: (slug: string) => `menu-category-link-${slug}`,\n menuHighlights: 'menu-highlights',\n menuItemBadge: (slug: string) => `menu-item-badge-${slug}`,\n deliveryTabBar: 'delivery-tab-bar',\n deliveryTab: (key: string) => `delivery-tab-${key}`,\n addressStrip: 'address-strip',\n addressSheet: 'address-sheet',\n addressCep: 'address-cep',\n addressNumber: 'address-number',\n addressComplement: 'address-complement',\n addressReference: 'address-reference',\n addressSave: 'address-save',\n addressAddNew: 'address-add-new',\n savedAddress: (id: string) => `saved-address-${id}`,\n itemSheetGroup: (label: string) => `item-sheet-group-${label}`,\n // delivery estimate (product page + cart)\n deliveryEstimator: 'delivery-estimator',\n deliveryCepInput: 'delivery-cep-input',\n deliveryCepSubmit: 'delivery-cep-submit',\n deliveryOption: 'delivery-option',\n deliveryUnserved: 'delivery-unserved',\n deliveryError: 'delivery-error',\n deliveryAddress: 'delivery-address',\n deliveryClear: 'delivery-clear',\n // checkout\n checkoutEmail: 'checkout-email',\n checkoutName: 'checkout-name',\n checkoutDocument: 'checkout-document',\n checkoutStreet: 'checkout-street',\n checkoutCity: 'checkout-city',\n checkoutZip: 'checkout-zip',\n checkoutCard: 'checkout-card',\n checkoutExpiry: 'checkout-expiry',\n checkoutCvc: 'checkout-cvc',\n placeOrder: 'place-order',\n // checkout em passos\n checkoutSteps: 'checkout-steps',\n checkoutStep: (n: number) => `checkout-step-${n}`,\n checkoutPayment: 'checkout-payment',\n checkoutPaymentTotal: 'checkout-payment-total',\n checkoutContinue: 'checkout-continue',\n checkoutBack: 'checkout-back',\n checkoutDone: 'checkout-done',\n // payment step\n pixPanel: 'pix-panel',\n pixCode: 'pix-code',\n pixCopy: 'pix-copy',\n pixConfirm: 'pix-confirm',\n checkoutError: 'checkout-error',\n checkoutProcessing: 'checkout-processing',\n // confirmation\n orderNumber: 'order-number',\n orderStatus: 'order-status',\n orderTracking: 'order-tracking',\n orderTrackingStep: (step: string) => `order-tracking-step-${step}`,\n orderTotal: 'order-total',\n viewPurchases: 'view-purchases',\n // account\n customerAccountShell: 'customer-account-shell',\n customerAccountMenu: 'customer-account-menu',\n orderDetail: 'order-detail',\n authTabSignin: 'auth-tab-signin',\n authTabSignup: 'auth-tab-signup',\n signinEmail: 'signin-email',\n signinPassword: 'signin-password',\n signinPasswordConfirm: 'signin-password-confirm',\n signinName: 'signin-name',\n signinSubmit: 'signin-submit',\n authError: 'auth-error',\n authNotice: 'auth-notice',\n checkoutExpired: 'checkout-expired',\n purchasesList: 'purchases-list',\n purchaseItem: 'purchase-item',\n purchasesEmpty: 'purchases-empty',\n signout: 'signout',\n} as const\n","import React from 'react'\nimport { imageSrcSet, imageVariantUrl, isStorageImageUrl, IMAGE_SRCSET_WIDTHS } from '@fayz-ai/shop'\nimport { useStorefrontConfigOptional, type StorefrontImageLoadingConfig } from '../document/config'\n\n/**\n * How large the image is drawn, so the browser can pick a variant.\n *\n * `width` — a fixed slot (a thumbnail): one variant at that width, at 2× for\n * dense screens. `sizes` — a fluid slot (a card, the gallery): the full\n * srcset ladder plus the CSS `sizes` hint. Both only take effect when the\n * store serves variants (`imageLoading.transform`) and the URL is a storage\n * object; otherwise the one file is loaded, as before.\n */\nexport interface SmoothImageVariant {\n width?: number\n sizes?: string\n widths?: readonly number[]\n quality?: number\n}\n\nexport interface SmoothImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {\n imageLoading?: StorefrontImageLoadingConfig\n variant?: SmoothImageVariant\n}\n\n/**\n * Has the app finished its first client render?\n *\n * The fade is a CLIENT entrance: an image that mounts while the shopper is\n * already looking at the store should arrive softly. An image that came down\n * in the server's HTML is a different thing — it is already on the page, and\n * starting it at `opacity: 0` means the browser holds a blank rectangle from\n * first paint until JavaScript has hydrated and the file has loaded. On the\n * Artorius catalogue that was eight blank cards for about a second, on a page\n * whose HTML had described them all along.\n *\n * So the reveal is skipped for the first render — the one the server also\n * performed, which keeps hydration matching — and applies to every mount after\n * it. Module scope, and only ever written from an effect: on the server it\n * stays false for the life of the worker, which is what makes the server's\n * markup and the client's first pass agree.\n */\nlet clientMounted = false\n\nexport function SmoothImage({\n imageLoading,\n variant,\n loading = 'lazy',\n decoding = 'async',\n onLoad,\n style,\n src,\n srcSet,\n sizes,\n ...props\n}: SmoothImageProps) {\n const config = useStorefrontConfigOptional()\n const resolved = {\n ...config?.imageLoading,\n ...imageLoading,\n }\n const mode = resolved.mode ?? 'fade'\n const durationMs = resolved.durationMs ?? 420\n const easing = resolved.easing ?? 'cubic-bezier(0.22, 1, 0.36, 1)'\n const blur = resolved.blur ?? true\n const transform = resolved.transform ?? 'none'\n const ref = React.useRef<HTMLImageElement | null>(null)\n const [loaded, setLoaded] = React.useState(() => mode === 'none' || !clientMounted)\n\n // Delivery-time variants, decided per render from the same three inputs\n // the browser will see. Explicit srcSet/sizes from the caller win.\n const delivered = React.useMemo(() => {\n if (transform !== 'supabase' || !src || srcSet || !isStorageImageUrl(src)) return { src, srcSet, sizes }\n if (variant?.width) {\n const w = variant.width\n const q = variant.quality\n return {\n src: imageVariantUrl(src, { width: w, quality: q }),\n srcSet: `${imageVariantUrl(src, { width: w, quality: q })} 1x, ${imageVariantUrl(src, { width: w * 2, quality: q })} 2x`,\n sizes,\n }\n }\n return {\n // A middle rung as the fallback `src`, for a browser without srcset.\n src: imageVariantUrl(src, { width: 960, quality: variant?.quality }),\n srcSet: imageSrcSet(src, variant?.widths ?? IMAGE_SRCSET_WIDTHS, { quality: variant?.quality }),\n sizes: variant?.sizes ?? sizes ?? '100vw',\n }\n }, [transform, src, srcSet, sizes, variant?.width, variant?.sizes, variant?.widths, variant?.quality])\n\n React.useEffect(() => {\n clientMounted = true\n }, [])\n\n React.useEffect(() => {\n if (mode === 'none') {\n setLoaded(true)\n return\n }\n // A cached file can finish before React attaches onLoad — without this the\n // image would stay at `opacity: 0` forever.\n if (ref.current?.complete && ref.current.naturalWidth > 0) setLoaded(true)\n }, [mode, delivered.src])\n\n const revealStyle: React.CSSProperties =\n mode === 'none'\n ? {}\n : {\n opacity: loaded ? 1 : 0,\n filter: blur && !loaded ? 'blur(10px)' : 'blur(0px)',\n transition: `opacity ${durationMs}ms ${easing}, filter ${durationMs}ms ${easing}, transform ${durationMs}ms ${easing}`,\n }\n\n return (\n <img\n {...props}\n src={delivered.src}\n srcSet={delivered.srcSet}\n sizes={delivered.sizes}\n ref={ref}\n loading={loading}\n decoding={decoding}\n data-sf-image-loaded={loaded ? 'true' : 'false'}\n style={{ ...style, ...revealStyle }}\n onLoad={(event) => {\n setLoaded(true)\n onLoad?.(event)\n }}\n />\n )\n}\n","import { useEffect } from 'react'\nimport { currentStaticRenderPass } from '../app/static-render'\nimport type { StaticHeadInput } from '../app/static-render'\n\n/**\n * Minimal per-route head manager: sets document.title and meta description so\n * each storefront page (product, catalog, account, checkout) has its own title\n * and shareable description instead of one static SPA title. A real SSR/prerender\n * pass (M12) layers OG/canonical on top; this covers the client-rendered baseline.\n *\n * Under a static render (`renderStore`, spine M8) there is no document and no\n * effect phase, so the same declaration is reported to the render pass instead.\n * That is how headless HTML gets the title THIS route sets, rather than a title\n * the renderer guessed by re-deriving the routing table on the server.\n *\n * Canonical, image, type and JSON-LD are static-render only by design: they\n * matter to a crawler reading the served HTML, and a client-side page that\n * injected them after hydration would be describing a URL that, under hash\n * addressing, is not its own anyway.\n */\nexport function useStorefrontHead(input: StaticHeadInput): void {\n const { title, description } = input\n currentStaticRenderPass()?.head(input)\n\n useEffect(() => {\n if (title) document.title = title\n }, [title])\n\n useEffect(() => {\n if (!description) return\n let tag = document.head.querySelector<HTMLMetaElement>('meta[name=\"description\"]')\n if (!tag) {\n tag = document.createElement('meta')\n tag.setAttribute('name', 'description')\n document.head.appendChild(tag)\n }\n tag.setAttribute('content', description.slice(0, 160))\n }, [description])\n}\n"]}
@@ -0,0 +1,41 @@
1
+ import { prefersReducedMotion } from './chunk-WXXYJZE6.js';
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+
4
+ var CONFETTI_COLORS = ["hsl(var(--primary))", "#f59e0b", "#10b981", "#3b82f6", "#ec4899"];
5
+ function SuccessMark() {
6
+ const reduced = prefersReducedMotion();
7
+ return /* @__PURE__ */ jsxs("div", { className: "relative mx-auto h-24 w-24", children: [
8
+ !reduced && Array.from({ length: 14 }, (_, i) => /* @__PURE__ */ jsx(
9
+ "span",
10
+ {
11
+ "aria-hidden": true,
12
+ className: "absolute h-2 w-2 animate-confetti-fall rounded-sm",
13
+ style: {
14
+ left: `${i * 7.3 % 100}%`,
15
+ top: "-4px",
16
+ backgroundColor: CONFETTI_COLORS[i % CONFETTI_COLORS.length],
17
+ animationDelay: `${200 + i % 7 * 90}ms`
18
+ }
19
+ },
20
+ i
21
+ )),
22
+ /* @__PURE__ */ jsx("span", { className: `absolute inset-0 rounded-full bg-emerald-100 ${reduced ? "" : "animate-pop-in"}` }),
23
+ /* @__PURE__ */ jsx("svg", { viewBox: "0 0 48 48", className: "absolute inset-0 h-full w-full p-6", "aria-hidden": true, children: /* @__PURE__ */ jsx(
24
+ "path",
25
+ {
26
+ d: "M10 25 L20 35 L38 14",
27
+ fill: "none",
28
+ stroke: "rgb(5 150 105)",
29
+ strokeWidth: "5",
30
+ strokeLinecap: "round",
31
+ strokeLinejoin: "round",
32
+ strokeDasharray: "48",
33
+ className: reduced ? "" : "animate-draw-check"
34
+ }
35
+ ) })
36
+ ] });
37
+ }
38
+
39
+ export { SuccessMark };
40
+ //# sourceMappingURL=chunk-WDQFNHYO.js.map
41
+ //# sourceMappingURL=chunk-WDQFNHYO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/order/SuccessMark.tsx"],"names":[],"mappings":";;;AAGA,IAAM,kBAAkB,CAAC,qBAAA,EAAuB,SAAA,EAAW,SAAA,EAAW,WAAW,SAAS,CAAA;AASnF,SAAS,WAAA,GAAc;AAC5B,EAAA,MAAM,UAAU,oBAAA,EAAqB;AACrC,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,4BAAA,EACZ,QAAA,EAAA;AAAA,IAAA,CAAC,OAAA,IACA,MAAM,IAAA,CAAK,EAAE,QAAQ,EAAA,EAAG,EAAG,CAAC,CAAA,EAAG,CAAA,qBAC7B,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QAEC,aAAA,EAAW,IAAA;AAAA,QACX,SAAA,EAAU,mDAAA;AAAA,QACV,KAAA,EAAO;AAAA,UACL,IAAA,EAAM,CAAA,EAAI,CAAA,GAAI,GAAA,GAAO,GAAG,CAAA,CAAA,CAAA;AAAA,UACxB,GAAA,EAAK,MAAA;AAAA,UACL,eAAA,EAAiB,eAAA,CAAgB,CAAA,GAAI,eAAA,CAAgB,MAAM,CAAA;AAAA,UAC3D,cAAA,EAAgB,CAAA,EAAG,GAAA,GAAO,CAAA,GAAI,IAAK,EAAE,CAAA,EAAA;AAAA;AACvC,OAAA;AAAA,MARK;AAAA,KAUR,CAAA;AAAA,wBACF,MAAA,EAAA,EAAK,SAAA,EAAW,gDAAgD,OAAA,GAAU,EAAA,GAAK,gBAAgB,CAAA,CAAA,EAAI,CAAA;AAAA,wBACnG,KAAA,EAAA,EAAI,OAAA,EAAQ,aAAY,SAAA,EAAU,oCAAA,EAAqC,eAAW,IAAA,EACjF,QAAA,kBAAA,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,CAAA,EAAE,sBAAA;AAAA,QACF,IAAA,EAAK,MAAA;AAAA,QACL,MAAA,EAAO,gBAAA;AAAA,QACP,WAAA,EAAY,GAAA;AAAA,QACZ,aAAA,EAAc,OAAA;AAAA,QACd,cAAA,EAAe,OAAA;AAAA,QACf,eAAA,EAAgB,IAAA;AAAA,QAChB,SAAA,EAAW,UAAU,EAAA,GAAK;AAAA;AAAA,KAC5B,EACF;AAAA,GAAA,EACF,CAAA;AAEJ","file":"chunk-WDQFNHYO.js","sourcesContent":["import React from 'react'\nimport { prefersReducedMotion } from '../../lib/motion'\n\nconst CONFETTI_COLORS = ['hsl(var(--primary))', '#f59e0b', '#10b981', '#3b82f6', '#ec4899']\n\n/**\n * A comemoração, e o cuidado que ela exige: só aparece quando o dinheiro entrou.\n *\n * Vive aqui porque duas telas a usam — o último passo do checkout e a página do\n * pedido pago. Uma cópia em cada uma foi como a página do pedido acabou\n * jogando confete para um pedido `pending`.\n */\nexport function SuccessMark() {\n const reduced = prefersReducedMotion()\n return (\n <div className=\"relative mx-auto h-24 w-24\">\n {!reduced &&\n Array.from({ length: 14 }, (_, i) => (\n <span\n key={i}\n aria-hidden\n className=\"absolute h-2 w-2 animate-confetti-fall rounded-sm\"\n style={{\n left: `${(i * 7.3) % 100}%`,\n top: '-4px',\n backgroundColor: CONFETTI_COLORS[i % CONFETTI_COLORS.length],\n animationDelay: `${200 + (i % 7) * 90}ms`,\n }}\n />\n ))}\n <span className={`absolute inset-0 rounded-full bg-emerald-100 ${reduced ? '' : 'animate-pop-in'}`} />\n <svg viewBox=\"0 0 48 48\" className=\"absolute inset-0 h-full w-full p-6\" aria-hidden>\n <path\n d=\"M10 25 L20 35 L38 14\"\n fill=\"none\"\n stroke=\"rgb(5 150 105)\"\n strokeWidth=\"5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeDasharray=\"48\"\n className={reduced ? '' : 'animate-draw-check'}\n />\n </svg>\n </div>\n )\n}\n"]}