@ecomiq/storefront 0.1.0 → 0.1.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/dist/nextjs.js CHANGED
@@ -1,20 +1,30 @@
1
+ import { z } from 'zod';
2
+ import { Modal } from '@ecomiq/ui/components/modal';
3
+ import { StorefrontPageDetailSchema as StorefrontPageDetailSchema$1, formatCurrency, useCart, useStore as useStore$1, useStorefrontAuthClient, useStorefrontSession, SignInForm, SignUpForm, signInWithEcomiqCredentials } from '@ecomiq/storefront/react';
4
+ import { toast, Toaster as Toaster$1 } from 'sonner';
5
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
6
+ import { useTheme } from 'next-themes';
1
7
  import { headers } from 'next/headers';
2
8
  import { StorefrontSettingsSchema, StorefrontProductsParamsSchema, StorefrontProductsResponseSchema, StorefrontProductDetailSchema, StorefrontCollectionsResponseSchema, StorefrontCollectionDetailSchema, StorefrontPageListItemSchema, StorefrontPageDetailSchema, CartCreateRequestSchema, CartResponseSchema, CartBuyerRequestSchema, CartAddressesRequestSchema, CartCouponRequestSchema, CartCheckoutRequestSchema, CartCheckoutResponseSchema, CartPaymentReceiptResponseSchema, CartCheckoutReadResponseSchema, ShippingOptionsResponseSchema, CartShippingMethodPutRequestSchema, CartItemRequestSchema } from '@ecomiq/storefront/core';
3
9
  import { getCloudflareContext } from '@opennextjs/cloudflare';
4
- import { z } from 'zod';
5
- import { useMutation, useQuery, useQueryClient, useInfiniteQuery } from '@tanstack/react-query';
6
- import { useMemo, useState, useEffect, useCallback, useRef } from 'react';
7
- import { toast } from 'sonner';
8
- import { StorefrontPageDetailSchema as StorefrontPageDetailSchema$1, formatCurrency, useCart } from '@ecomiq/storefront/react';
10
+ import { existsSync } from 'fs';
11
+ import { createRequire } from 'module';
12
+ import { join } from 'path';
13
+ import React2, { createContext, useEffect, useState, useMemo, useCallback, useRef } from 'react';
14
+ import { QueryClient, useMutation, useQuery, QueryClientProvider, useQueryClient, useInfiniteQuery } from '@tanstack/react-query';
9
15
  import { create } from 'zustand';
10
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
11
- import Link from 'next/link';
16
+
17
+ var __defProp = Object.defineProperty;
18
+ var __getOwnPropNames = Object.getOwnPropertyNames;
19
+ var __esm = (fn, res) => function __init() {
20
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
21
+ };
22
+ var __export = (target, all) => {
23
+ for (var name in all)
24
+ __defProp(target, name, { get: all[name], enumerable: true });
25
+ };
12
26
 
13
27
  // src/core/client/store-api-client.ts
14
- var STORE_API_PATH = "/api/store";
15
- var serverRequestOriginGetter = null;
16
- var serverStoreIdGetter = null;
17
- var clientStoreIdGetter = null;
18
28
  function setServerRequestOrigin(getter) {
19
29
  serverRequestOriginGetter = getter;
20
30
  }
@@ -41,100 +51,408 @@ async function getStoreApiClient() {
41
51
  const baseUrl = await getStoreApiBaseUrl();
42
52
  return new StoreApiClient(baseUrl);
43
53
  }
44
- var StoreApiClient = class {
45
- baseUrl;
46
- constructor(baseUrl = STORE_API_PATH) {
47
- this.baseUrl = baseUrl.replace(/\/$/, "");
48
- }
49
- async request(path, init, options) {
50
- const pathNorm = path.replace(/^\/+/, "");
51
- const url = path.startsWith("http") ? path : `${this.baseUrl}/${pathNorm}`;
52
- const headers3 = new Headers(init.headers ?? {});
53
- headers3.set("Content-Type", "application/json");
54
- headers3.set("Accept-Encoding", "identity");
55
- const explicitStoreId = options?.xStoreId?.trim();
56
- const runtimeStoreId = explicitStoreId || (typeof window === "undefined" ? serverStoreIdGetter : clientStoreIdGetter);
57
- if (runtimeStoreId && !headers3.has("x-store-id")) {
58
- headers3.set("X-Store-Id", runtimeStoreId);
59
- }
60
- if (options?.xStoreDomain) {
61
- headers3.set("X-Store-Domain", options.xStoreDomain);
62
- }
63
- if (options?.xCartId) {
64
- headers3.set("X-Cart-Token", options.xCartId);
65
- }
66
- const bearer = typeof options?.bearerToken === "string" && options.bearerToken.trim().length > 0 ? options.bearerToken.trim() : void 0;
67
- if (bearer) {
68
- headers3.set(
69
- "Authorization",
70
- bearer.toLowerCase().startsWith("bearer ") ? bearer : `Bearer ${bearer}`
71
- );
72
- }
73
- const isServer = typeof window === "undefined";
74
- const res = await fetch(url, {
75
- ...init,
76
- headers: headers3,
77
- credentials: isServer ? "same-origin" : "include",
78
- ...options?.noStore ? { cache: "no-store" } : {},
79
- ...options?.cacheKey && isServer && !options?.noStore ? {
80
- next: {
81
- revalidate: 60,
82
- tags: [options.cacheKey]
54
+ var STORE_API_PATH, serverRequestOriginGetter, serverStoreIdGetter, clientStoreIdGetter, StoreApiClient, storeApiClient;
55
+ var init_store_api_client = __esm({
56
+ "src/core/client/store-api-client.ts"() {
57
+ STORE_API_PATH = "/api/store";
58
+ serverRequestOriginGetter = null;
59
+ serverStoreIdGetter = null;
60
+ clientStoreIdGetter = null;
61
+ StoreApiClient = class {
62
+ baseUrl;
63
+ constructor(baseUrl = STORE_API_PATH) {
64
+ this.baseUrl = baseUrl.replace(/\/$/, "");
65
+ }
66
+ async request(path, init, options) {
67
+ const pathNorm = path.replace(/^\/+/, "");
68
+ const url = path.startsWith("http") ? path : `${this.baseUrl}/${pathNorm}`;
69
+ const headers3 = new Headers(init.headers ?? {});
70
+ headers3.set("Content-Type", "application/json");
71
+ headers3.set("Accept-Encoding", "identity");
72
+ const explicitStoreId = options?.xStoreId?.trim();
73
+ const runtimeStoreId = explicitStoreId || (typeof window === "undefined" ? serverStoreIdGetter : clientStoreIdGetter);
74
+ if (runtimeStoreId && !headers3.has("x-store-id")) {
75
+ headers3.set("X-Store-Id", runtimeStoreId);
83
76
  }
84
- } : {}
85
- });
86
- if (!res.ok) {
87
- let body;
88
- try {
89
- const errorText = await res.text();
90
- body = errorText ? JSON.parse(errorText) : void 0;
91
- } catch {
92
- body = void 0;
77
+ if (options?.xStoreDomain) {
78
+ headers3.set("X-Store-Domain", options.xStoreDomain);
79
+ }
80
+ if (options?.xCartId) {
81
+ headers3.set("X-Cart-Token", options.xCartId);
82
+ }
83
+ const bearer = typeof options?.bearerToken === "string" && options.bearerToken.trim().length > 0 ? options.bearerToken.trim() : void 0;
84
+ if (bearer) {
85
+ headers3.set(
86
+ "Authorization",
87
+ bearer.toLowerCase().startsWith("bearer ") ? bearer : `Bearer ${bearer}`
88
+ );
89
+ }
90
+ const isServer = typeof window === "undefined";
91
+ const res = await fetch(url, {
92
+ ...init,
93
+ headers: headers3,
94
+ credentials: isServer ? "same-origin" : "include",
95
+ ...options?.noStore ? { cache: "no-store" } : {},
96
+ ...options?.cacheKey && isServer && !options?.noStore ? {
97
+ next: {
98
+ revalidate: 60,
99
+ tags: [options.cacheKey]
100
+ }
101
+ } : {}
102
+ });
103
+ if (!res.ok) {
104
+ let body;
105
+ try {
106
+ const errorText = await res.text();
107
+ body = errorText ? JSON.parse(errorText) : void 0;
108
+ } catch {
109
+ body = void 0;
110
+ }
111
+ const msg = typeof body === "object" && body !== null && "title" in body && typeof body.title === "string" ? body.title : res.statusText || "Store API error";
112
+ const err = new Error(msg);
113
+ err.status = res.status;
114
+ err.body = body;
115
+ throw err;
116
+ }
117
+ const text = await res.text();
118
+ if (!text) return void 0;
119
+ return JSON.parse(text);
93
120
  }
94
- const msg = typeof body === "object" && body !== null && "title" in body && typeof body.title === "string" ? body.title : res.statusText || "Store API error";
95
- const err = new Error(msg);
96
- err.status = res.status;
97
- err.body = body;
98
- throw err;
99
- }
100
- const text = await res.text();
101
- if (!text) return void 0;
102
- return JSON.parse(text);
103
- }
104
- get(path, options) {
105
- return this.request(path, { method: "GET" }, options);
121
+ get(path, options) {
122
+ return this.request(path, { method: "GET" }, options);
123
+ }
124
+ post(path, data, options) {
125
+ return this.request(
126
+ path,
127
+ {
128
+ method: "POST",
129
+ body: data != null ? JSON.stringify(data) : void 0
130
+ },
131
+ options
132
+ );
133
+ }
134
+ patch(path, data, options) {
135
+ return this.request(path, {
136
+ method: "PATCH",
137
+ body: data != null ? JSON.stringify(data) : void 0
138
+ }, options);
139
+ }
140
+ put(path, data, options) {
141
+ return this.request(
142
+ path,
143
+ {
144
+ method: "PUT",
145
+ body: data != null ? JSON.stringify(data) : void 0
146
+ },
147
+ options
148
+ );
149
+ }
150
+ delete(path, options) {
151
+ return this.request(path, { method: "DELETE" }, options);
152
+ }
153
+ };
154
+ storeApiClient = new StoreApiClient(STORE_API_PATH);
106
155
  }
107
- post(path, data, options) {
108
- return this.request(
109
- path,
110
- {
111
- method: "POST",
112
- body: data != null ? JSON.stringify(data) : void 0
113
- },
114
- options
115
- );
156
+ });
157
+ function customerMeToProfilePatch(me) {
158
+ return {
159
+ firstName: me.firstName,
160
+ lastName: me.lastName,
161
+ phone: me.phone ?? "",
162
+ identificationNumber: me.identificationNumber,
163
+ identificationType: me.identificationType,
164
+ entityName: me.entityName,
165
+ entityIdentificationNumber: me.entityIdentificationNumber,
166
+ gender: me.gender,
167
+ role: me.role,
168
+ companyName: me.companyName,
169
+ dateOfBirth: me.dateOfBirth,
170
+ consent: me.consent,
171
+ countryIsoCode: me.countryIsoCode || "PE"
172
+ };
173
+ }
174
+ function customerAuthOptions(accessToken) {
175
+ const token = typeof accessToken === "string" && accessToken.trim().length > 0 ? accessToken.trim() : void 0;
176
+ return token ? { bearerToken: token } : {};
177
+ }
178
+ async function registerCustomer(data) {
179
+ const payload = CustomerRegisterRequestSchema.parse(data);
180
+ const client = await getStoreApiClient();
181
+ return client.post("customer/register", payload);
182
+ }
183
+ async function getCustomerAddresses(accessToken) {
184
+ const client = await getStoreApiClient();
185
+ const token = typeof accessToken === "string" && accessToken.trim().length > 0 ? accessToken.trim() : void 0;
186
+ const response = await client.get("customer/addresses", {
187
+ ...token ? { bearerToken: token } : {}
188
+ });
189
+ return z.array(CustomerAddressSchema).parse(response);
190
+ }
191
+ async function createCustomerAddress(data, accessToken) {
192
+ const client = await getStoreApiClient();
193
+ const token = typeof accessToken === "string" && accessToken.trim().length > 0 ? accessToken.trim() : void 0;
194
+ const payload = CustomerAddressUpsertSchema.parse(data);
195
+ return client.post("customer/addresses", payload, {
196
+ ...token ? { bearerToken: token } : {}
197
+ });
198
+ }
199
+ async function updateCustomerAddress(addressId, data, accessToken) {
200
+ const client = await getStoreApiClient();
201
+ const token = typeof accessToken === "string" && accessToken.trim().length > 0 ? accessToken.trim() : void 0;
202
+ const payload = CustomerAddressUpsertSchema.parse(data);
203
+ const id = addressId.trim();
204
+ if (!id) throw new Error("addressId requerido");
205
+ return client.put(`customer/addresses/${encodeURIComponent(id)}`, payload, {
206
+ ...token ? { bearerToken: token } : {}
207
+ });
208
+ }
209
+ async function deleteCustomerAddress(addressId, accessToken) {
210
+ const client = await getStoreApiClient();
211
+ const token = typeof accessToken === "string" && accessToken.trim().length > 0 ? accessToken.trim() : void 0;
212
+ const id = addressId.trim();
213
+ if (!id) throw new Error("addressId requerido");
214
+ return client.delete(`customer/addresses/${encodeURIComponent(id)}`, {
215
+ ...token ? { bearerToken: token } : {}
216
+ });
217
+ }
218
+ async function getCustomerMe(accessToken) {
219
+ const client = await getStoreApiClient();
220
+ const response = await client.get("customer", customerAuthOptions(accessToken));
221
+ return CustomerMeSchema.parse(response);
222
+ }
223
+ async function patchCustomer(data, accessToken) {
224
+ const client = await getStoreApiClient();
225
+ const payload = CustomerProfilePatchSchema.parse(data);
226
+ await client.patch("customer", payload, customerAuthOptions(accessToken));
227
+ }
228
+ var CustomerRegisterRequestSchema, CustomerAddressSchema, CustomerAddressUpsertSchema, CustomerMeSchema, CustomerProfilePatchSchema;
229
+ var init_store_api_customer_service = __esm({
230
+ "src/core/client/store-api-customer.service.ts"() {
231
+ init_store_api_client();
232
+ CustomerRegisterRequestSchema = z.object({
233
+ email: z.string().email(),
234
+ firstName: z.string().trim().min(1),
235
+ lastName: z.string().trim().min(1),
236
+ countryIsoCode: z.string().trim().length(2),
237
+ password: z.string(),
238
+ phone: z.string().trim().optional()
239
+ });
240
+ CustomerAddressSchema = z.object({
241
+ /** Presente en listados cuando el upstream expone el id para PUT/DELETE. */
242
+ id: z.string().optional(),
243
+ addressKey: z.string(),
244
+ countryIsoCode: z.string(),
245
+ addressLine: z.string(),
246
+ addressNumber: z.string(),
247
+ department: z.string(),
248
+ province: z.string(),
249
+ district: z.string(),
250
+ phone: z.string(),
251
+ cellPhone: z.string(),
252
+ postalCode: z.string(),
253
+ reference: z.string(),
254
+ latitude: z.number().nullable(),
255
+ longitude: z.number().nullable(),
256
+ isDefault: z.boolean()
257
+ });
258
+ CustomerAddressUpsertSchema = CustomerAddressSchema.omit({ id: true });
259
+ CustomerMeSchema = z.object({
260
+ id: z.string(),
261
+ storeId: z.string(),
262
+ email: z.string().email(),
263
+ firstName: z.string(),
264
+ lastName: z.string(),
265
+ phone: z.string(),
266
+ identificationNumber: z.string().nullable(),
267
+ identificationType: z.string().nullable(),
268
+ entityName: z.string().nullable(),
269
+ dateOfBirth: z.string().nullable(),
270
+ gender: z.string().nullable(),
271
+ countryIsoCode: z.string(),
272
+ role: z.string().nullable(),
273
+ companyName: z.string().nullable(),
274
+ consent: z.boolean(),
275
+ userId: z.string(),
276
+ customerType: z.string(),
277
+ status: z.string(),
278
+ entityIdentificationNumber: z.string().nullable(),
279
+ defaultAddressId: z.string().nullable(),
280
+ metadata: z.unknown().nullable(),
281
+ totalOrders: z.number(),
282
+ avgOrders: z.number(),
283
+ lastOrderId: z.string().nullable(),
284
+ lastOrderDate: z.string().nullable(),
285
+ loyaltyPoints: z.number(),
286
+ addresses: z.array(CustomerAddressSchema),
287
+ createdOn: z.string(),
288
+ updatedOn: z.string().nullable()
289
+ });
290
+ CustomerProfilePatchSchema = z.object({
291
+ firstName: z.string().trim().min(1),
292
+ lastName: z.string().trim().min(1),
293
+ phone: z.string().trim(),
294
+ identificationNumber: z.string().nullable(),
295
+ identificationType: z.string().nullable(),
296
+ entityName: z.string().nullable(),
297
+ entityIdentificationNumber: z.string().nullable(),
298
+ gender: z.string().nullable(),
299
+ role: z.string().nullable(),
300
+ companyName: z.string().nullable(),
301
+ dateOfBirth: z.string().nullable(),
302
+ consent: z.boolean(),
303
+ countryIsoCode: z.string().trim().length(2)
304
+ });
116
305
  }
117
- patch(path, data, options) {
118
- return this.request(path, {
119
- method: "PATCH",
120
- body: data != null ? JSON.stringify(data) : void 0
121
- }, options);
306
+ });
307
+ var ModalsFactory;
308
+ var init_modals_factory = __esm({
309
+ "src/react/shell/components/modals-factory.tsx"() {
310
+ "use client";
311
+ init_store_api_customer_service();
312
+ ModalsFactory = () => {
313
+ const cart = useCart();
314
+ const store = useStore$1();
315
+ const authClient = useStorefrontAuthClient();
316
+ const { refetch } = useStorefrontSession();
317
+ const handlerLogin = async (values) => {
318
+ try {
319
+ await signInWithEcomiqCredentials(authClient, store.data, values);
320
+ const me = await getCustomerMe();
321
+ const displayName = `${me.firstName} ${me.lastName}`.trim() || me.email;
322
+ const updateUserResponse = await authClient.$fetch("/update-user", {
323
+ method: "POST",
324
+ body: {
325
+ name: displayName,
326
+ firstName: me.firstName,
327
+ lastName: me.lastName,
328
+ phone: me.phone
329
+ }
330
+ });
331
+ if (updateUserResponse.error) {
332
+ throw new Error(updateUserResponse.error?.message ?? "No se pudo sincronizar el perfil");
333
+ }
334
+ if (me.email) {
335
+ cart.setCheckoutCustomerLocal({
336
+ email: me.email,
337
+ firstName: me.firstName,
338
+ lastName: me.lastName,
339
+ phone: me.phone ?? ""
340
+ });
341
+ }
342
+ await refetch();
343
+ toast.success("Sesi\xF3n iniciada correctamente");
344
+ store.closeModal("login");
345
+ } catch (error) {
346
+ console.error("Error al iniciar sesion:", error);
347
+ toast.error("Error al iniciar sesion");
348
+ }
349
+ };
350
+ const handlerSignup = async (values) => {
351
+ try {
352
+ await registerCustomer({
353
+ email: values.email,
354
+ firstName: values.firstName,
355
+ lastName: values.lastName,
356
+ countryIsoCode: values.countryIsoCode,
357
+ password: values.password,
358
+ phone: values.phone
359
+ });
360
+ toast.success("Cuenta creada correctamente");
361
+ store.closeModal("signup");
362
+ setTimeout(() => {
363
+ store.openModal("login");
364
+ }, 1e3);
365
+ } catch (error) {
366
+ console.error("Error al registrarse:", error);
367
+ toast.error("Error al registrarse");
368
+ }
369
+ };
370
+ return /* @__PURE__ */ jsxs(
371
+ Modal,
372
+ {
373
+ isOpen: store.modals.login || store.modals.signup,
374
+ onClose: () => store.closeAllModals(),
375
+ children: [
376
+ store.modals.login && /* @__PURE__ */ jsxs(Fragment, { children: [
377
+ /* @__PURE__ */ jsx(SignInForm, { onSubmit: (values) => handlerLogin(values) }),
378
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-center items-center mt-4", children: [
379
+ /* @__PURE__ */ jsx("p", { className: "text-gray-500", children: "No tienes cuenta?" }),
380
+ /* @__PURE__ */ jsx(
381
+ "button",
382
+ {
383
+ type: "button",
384
+ onClick: () => store.openModal("signup"),
385
+ className: "text-primary hover:underline ml-2 cursor-pointer",
386
+ children: "Registrate"
387
+ }
388
+ )
389
+ ] })
390
+ ] }),
391
+ store.modals.signup && /* @__PURE__ */ jsxs(Fragment, { children: [
392
+ /* @__PURE__ */ jsx(SignUpForm, { onSubmit: (values) => handlerSignup(values) }),
393
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-center items-center mt-4", children: [
394
+ /* @__PURE__ */ jsx("p", { className: "text-gray-500", children: "Ya tienes cuenta?" }),
395
+ /* @__PURE__ */ jsx(
396
+ "button",
397
+ {
398
+ type: "button",
399
+ onClick: () => store.openModal("login"),
400
+ className: "text-primary hover:underline ml-2 cursor-pointer",
401
+ children: "Inicia sesion"
402
+ }
403
+ )
404
+ ] })
405
+ ] })
406
+ ]
407
+ }
408
+ );
409
+ };
122
410
  }
123
- put(path, data, options) {
124
- return this.request(
125
- path,
126
- {
127
- method: "PUT",
128
- body: data != null ? JSON.stringify(data) : void 0
129
- },
130
- options
131
- );
411
+ });
412
+ var Toaster;
413
+ var init_Toaster = __esm({
414
+ "src/react/shell/components/Toaster.tsx"() {
415
+ "use client";
416
+ Toaster = ({ ...props }) => {
417
+ const { theme = "system" } = useTheme();
418
+ return /* @__PURE__ */ jsx(
419
+ Toaster$1,
420
+ {
421
+ theme,
422
+ className: "toaster group",
423
+ style: {
424
+ "--normal-bg": "var(--popover)",
425
+ "--normal-text": "var(--popover-foreground)",
426
+ "--normal-border": "var(--border)"
427
+ },
428
+ ...props
429
+ }
430
+ );
431
+ };
132
432
  }
133
- delete(path, options) {
134
- return this.request(path, { method: "DELETE" }, options);
433
+ });
434
+
435
+ // src/react/shell/providers/ecomiq-shell-ui.tsx
436
+ var ecomiq_shell_ui_exports = {};
437
+ __export(ecomiq_shell_ui_exports, {
438
+ EcomiqShellUi: () => EcomiqShellUi
439
+ });
440
+ function EcomiqShellUi() {
441
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
442
+ /* @__PURE__ */ jsx(ModalsFactory, {}),
443
+ /* @__PURE__ */ jsx(Toaster, { position: "bottom-right" })
444
+ ] });
445
+ }
446
+ var init_ecomiq_shell_ui = __esm({
447
+ "src/react/shell/providers/ecomiq-shell-ui.tsx"() {
448
+ "use client";
449
+ init_modals_factory();
450
+ init_Toaster();
135
451
  }
136
- };
137
- var storeApiClient = new StoreApiClient(STORE_API_PATH);
452
+ });
453
+
454
+ // src/react/nextjs/actions/getHostName.ts
455
+ init_store_api_client();
138
456
  async function getHostname() {
139
457
  const hd = await headers();
140
458
  const host = hd.get("host");
@@ -144,6 +462,9 @@ async function getHostname() {
144
462
  setServerRequestOrigin(`${secure ? "https" : "http"}://${hostname}`);
145
463
  return hostname;
146
464
  }
465
+
466
+ // src/core/client/store-api-store.service.ts
467
+ init_store_api_client();
147
468
  async function getStorefrontSettings(subdomain, cacheKey) {
148
469
  const client = await getStoreApiClient();
149
470
  const response = await client.get("settings", {
@@ -180,8 +501,17 @@ function resolveStorefrontSettingsHost(hostHeader) {
180
501
  }
181
502
  return host;
182
503
  }
504
+ function buildStorefrontKvSnapshotKeyFromStoreKey(storeKey) {
505
+ const key = storeKey.trim();
506
+ if (!key) {
507
+ throw Object.assign(new Error("Store key vac\xEDo para KV"), { status: 400 });
508
+ }
509
+ return `storefront:snapshots:store:${key}`;
510
+ }
183
511
  function buildStorefrontKvSnapshotKey(hostHeader) {
184
- return `storefront:snapshots:store:${resolveStorefrontSettingsHost(hostHeader)}`;
512
+ return buildStorefrontKvSnapshotKeyFromStoreKey(
513
+ resolveStorefrontSettingsHost(hostHeader)
514
+ );
185
515
  }
186
516
  function getKvNamespace(env) {
187
517
  if (!env || typeof env !== "object") return void 0;
@@ -191,7 +521,7 @@ function getKvNamespace(env) {
191
521
  }
192
522
  return ns;
193
523
  }
194
- async function getStorefrontSettingsFromKv(hostHeader) {
524
+ async function getStorefrontSettingsFromKvByStoreKey(storeKey) {
195
525
  const { env } = await getCloudflareContext({ async: true });
196
526
  const kv = getKvNamespace(env);
197
527
  if (!kv) {
@@ -200,7 +530,7 @@ async function getStorefrontSettingsFromKv(hostHeader) {
200
530
  );
201
531
  throw Object.assign(err, { status: 500 });
202
532
  }
203
- const cacheKey = buildStorefrontKvSnapshotKey(hostHeader);
533
+ const cacheKey = buildStorefrontKvSnapshotKeyFromStoreKey(storeKey);
204
534
  const raw = await kv.get(cacheKey, { type: "json" });
205
535
  if (raw == null) {
206
536
  const err = new Error("Store settings not found in KV");
@@ -208,6 +538,68 @@ async function getStorefrontSettingsFromKv(hostHeader) {
208
538
  }
209
539
  return StorefrontSettingsSchema.parse(raw);
210
540
  }
541
+ async function getStorefrontSettingsFromKv(hostHeader) {
542
+ return getStorefrontSettingsFromKvByStoreKey(
543
+ resolveStorefrontSettingsHost(hostHeader)
544
+ );
545
+ }
546
+ var CONFIG_FILENAMES = [
547
+ "ecomiq.config.js",
548
+ "ecomiq.config.cjs",
549
+ "ecomiq.config.mjs"
550
+ ];
551
+ var EcomiqConfigSchema = z.object({
552
+ /**
553
+ * Slug de tienda en Ecomiq (p. ej. `mi-tienda` para `mi-tienda.ecomiq.app`).
554
+ * Si está definido, tiene prioridad sobre el `Host` de la request (útil en `localhost`).
555
+ */
556
+ slugStore: z.string().min(1).optional()
557
+ });
558
+ var cachedConfig;
559
+ function parseExportedConfig(raw) {
560
+ const candidate = raw && typeof raw === "object" && "default" in raw ? raw.default : raw;
561
+ const parsed = EcomiqConfigSchema.safeParse(candidate);
562
+ if (!parsed.success) {
563
+ console.warn(
564
+ "[ecomiq] ecomiq.config.* inv\xE1lido:",
565
+ parsed.error.flatten().fieldErrors
566
+ );
567
+ return null;
568
+ }
569
+ const slugStore = parsed.data.slugStore?.trim();
570
+ return slugStore ? { slugStore } : {};
571
+ }
572
+ function loadEcomiqConfig(cwd = process.cwd()) {
573
+ if (cachedConfig !== void 0) return cachedConfig;
574
+ for (const filename of CONFIG_FILENAMES) {
575
+ const configPath = join(cwd, filename);
576
+ if (!existsSync(configPath)) continue;
577
+ try {
578
+ const requireFromApp = createRequire(join(cwd, "package.json"));
579
+ const loaded = requireFromApp(configPath);
580
+ const parsed = parseExportedConfig(loaded);
581
+ cachedConfig = parsed;
582
+ return cachedConfig;
583
+ } catch (error) {
584
+ console.warn(`[ecomiq] No se pudo cargar ${configPath}:`, error);
585
+ }
586
+ }
587
+ cachedConfig = null;
588
+ return null;
589
+ }
590
+ function resolvePublicStoreKey(hostHeader, cwd) {
591
+ const slugFromConfig = loadEcomiqConfig(cwd)?.slugStore?.trim();
592
+ if (slugFromConfig) return slugFromConfig;
593
+ if (!hostHeader?.trim()) {
594
+ throw Object.assign(
595
+ new Error(
596
+ "Host is required, o define slugStore en ecomiq.config.js en la ra\xEDz del proyecto"
597
+ ),
598
+ { status: 400 }
599
+ );
600
+ }
601
+ return resolveStorefrontSettingsHost(hostHeader);
602
+ }
211
603
 
212
604
  // src/react/shell/lib/public-store-settings-source.ts
213
605
  var ENV_PUBLIC_STORE_SETTINGS_SOURCE = "PUBLIC_STORE_SETTINGS_SOURCE";
@@ -217,30 +609,37 @@ function resolvePublicStoreSettingsSource(envValue = process.env[ENV_PUBLIC_STOR
217
609
  }
218
610
 
219
611
  // src/react/nextjs/actions/getPublicStore.ts
612
+ init_store_api_client();
220
613
  async function getPublicStore(options) {
221
614
  const headerList = await headers();
222
615
  const host = headerList.get("host");
223
- if (!host?.trim()) {
616
+ let storeKey;
617
+ try {
618
+ storeKey = resolvePublicStoreKey(host);
619
+ } catch (error) {
620
+ const err = error;
224
621
  return {
225
622
  data: null,
226
623
  error: {
227
- message: "Host is required",
228
- statusCode: 400,
624
+ message: err.message ?? "Host is required",
625
+ statusCode: err.status ?? 400,
229
626
  isNotFound: true,
230
627
  subdomain: void 0
231
628
  }
232
629
  };
233
630
  }
234
- const storeHost = normalizeStoreHost(host);
235
- const proto = headerList.get("x-forwarded-proto") ?? headerList.get("x-forwarded-ssl") ?? "http";
236
- const secure = proto === "https" || (headerList.get("x-forwarded-ssl") ?? "") === "on";
237
- setServerRequestOrigin(`${secure ? "https" : "http"}://${host}`);
631
+ if (host?.trim()) {
632
+ const proto = headerList.get("x-forwarded-proto") ?? headerList.get("x-forwarded-ssl") ?? "http";
633
+ const secure = proto === "https" || (headerList.get("x-forwarded-ssl") ?? "") === "on";
634
+ setServerRequestOrigin(`${secure ? "https" : "http"}://${host}`);
635
+ }
238
636
  const source = options?.source ?? resolvePublicStoreSettingsSource();
239
- let storeDomain;
240
637
  try {
241
- storeDomain = resolveStorefrontSettingsHost(host);
242
638
  setServerStoreId(null);
243
- const data = source === "kv" ? await getStorefrontSettingsFromKv(storeHost) : await getStorefrontSettings(storeDomain, `storefront-settings-${storeDomain}`);
639
+ const data = source === "kv" ? await getStorefrontSettingsFromKvByStoreKey(storeKey) : await getStorefrontSettings(
640
+ storeKey,
641
+ `storefront-settings-${storeKey}`
642
+ );
244
643
  setServerStoreId(data.store.id);
245
644
  return { data, error: null };
246
645
  } catch (error) {
@@ -252,11 +651,114 @@ async function getPublicStore(options) {
252
651
  message: err.message ?? "Error fetching store settings",
253
652
  statusCode,
254
653
  isNotFound: statusCode === 404,
255
- subdomain: storeDomain
654
+ subdomain: storeKey
256
655
  }
257
656
  };
258
657
  }
259
658
  }
659
+ var StorefrontAuthContext = createContext(null);
660
+ function StorefrontAuthProvider({
661
+ authClient,
662
+ children
663
+ }) {
664
+ return /* @__PURE__ */ jsx(StorefrontAuthContext.Provider, { value: authClient, children });
665
+ }
666
+ var useStore = create()(
667
+ (set) => ({
668
+ data: null,
669
+ drawers: {
670
+ cart: false,
671
+ search: false,
672
+ menu: false,
673
+ filter: false
674
+ },
675
+ openDrawer: (drawer) => set((state) => ({
676
+ drawers: {
677
+ ...state.drawers,
678
+ [drawer]: true
679
+ }
680
+ })),
681
+ closeDrawer: (drawer) => set((state) => ({
682
+ drawers: {
683
+ ...state.drawers,
684
+ [drawer]: false
685
+ }
686
+ })),
687
+ toggleDrawer: (drawer) => set((state) => ({
688
+ drawers: {
689
+ ...state.drawers,
690
+ [drawer]: !state.drawers[drawer]
691
+ }
692
+ })),
693
+ closeAllDrawers: () => set((state) => ({
694
+ drawers: Object.keys(state.drawers).reduce(
695
+ (acc, key) => ({ ...acc, [key]: false }),
696
+ {}
697
+ )
698
+ })),
699
+ modals: {
700
+ login: false,
701
+ signup: false
702
+ },
703
+ openModal: (modal) => set((state) => ({
704
+ modals: {
705
+ ...state.modals,
706
+ login: false,
707
+ signup: false,
708
+ [modal]: true
709
+ }
710
+ })),
711
+ closeModal: (modal) => set((state) => ({
712
+ modals: {
713
+ ...state.modals,
714
+ login: false,
715
+ signup: false,
716
+ [modal]: false
717
+ }
718
+ })),
719
+ toggleModal: (modal) => set((state) => ({
720
+ modals: {
721
+ ...state.modals,
722
+ [modal]: !state.modals[modal]
723
+ }
724
+ })),
725
+ closeAllModals: () => set((state) => ({
726
+ modals: Object.keys(state.modals).reduce(
727
+ (acc, key) => ({ ...acc, [key]: false }),
728
+ {}
729
+ )
730
+ }))
731
+ })
732
+ );
733
+
734
+ // src/react/shell/providers/EcomiqProvider.tsx
735
+ init_store_api_client();
736
+ function EcomiqProvider({
737
+ store,
738
+ authClient,
739
+ children,
740
+ withShellUi = false
741
+ }) {
742
+ useStore.setState({ data: store ?? null });
743
+ useEffect(() => {
744
+ setClientStoreId(store?.store.id ?? null);
745
+ return () => setClientStoreId(null);
746
+ }, [store]);
747
+ const [queryClient] = useState(() => new QueryClient());
748
+ const tree = /* @__PURE__ */ jsxs(QueryClientProvider, { client: queryClient, children: [
749
+ children,
750
+ withShellUi ? /* @__PURE__ */ jsx(EcomiqShellUi2, {}) : null
751
+ ] });
752
+ if (!authClient) return tree;
753
+ return /* @__PURE__ */ jsx(StorefrontAuthProvider, { authClient, children: tree });
754
+ }
755
+ function EcomiqShellUi2() {
756
+ const [ui, setUi] = useState(null);
757
+ useEffect(() => {
758
+ void Promise.resolve().then(() => (init_ecomiq_shell_ui(), ecomiq_shell_ui_exports)).then((mod) => setUi(() => mod.EcomiqShellUi));
759
+ }, []);
760
+ return ui ? React2.createElement(ui) : null;
761
+ }
260
762
 
261
763
  // src/core/client/store-api-errors.ts
262
764
  function isCartNotActiveApiError(error) {
@@ -267,6 +769,12 @@ function isCartNotActiveApiError(error) {
267
769
  const keys = body?.errors ? Object.keys(body.errors) : [];
268
770
  return keys.includes("Carts.NotActive");
269
771
  }
772
+
773
+ // src/core/client/index.ts
774
+ init_store_api_client();
775
+
776
+ // src/core/client/store-api-product.service.ts
777
+ init_store_api_client();
270
778
  async function getStorefrontProducts(params, cacheKey) {
271
779
  const parsed = StorefrontProductsParamsSchema.parse(params ?? {});
272
780
  const searchParams = new URLSearchParams();
@@ -295,6 +803,9 @@ async function getStorefrontProductBySlug(slug) {
295
803
  const response = await client.get(path);
296
804
  return StorefrontProductDetailSchema.parse(response);
297
805
  }
806
+
807
+ // src/core/client/store-api-collection.service.ts
808
+ init_store_api_client();
298
809
  async function getStorefrontCollections() {
299
810
  const client = await getStoreApiClient();
300
811
  const response = await client.get("collections");
@@ -307,6 +818,9 @@ async function getStorefrontCollectionBySlug(slug) {
307
818
  );
308
819
  return StorefrontCollectionDetailSchema.parse(response);
309
820
  }
821
+
822
+ // src/core/client/store-api-pages.service.ts
823
+ init_store_api_client();
310
824
  async function getStorefrontPages() {
311
825
  const client = await getStoreApiClient();
312
826
  const response = await client.get("pages");
@@ -324,6 +838,9 @@ async function getStorefrontPagePreview(slug, token) {
324
838
  const response = await client.get(path);
325
839
  return StorefrontPageDetailSchema.parse(response);
326
840
  }
841
+
842
+ // src/core/client/store-api-cart.service.ts
843
+ init_store_api_client();
327
844
  async function createCart(data) {
328
845
  const payload = CartCreateRequestSchema.parse(data);
329
846
  const client = await getStoreApiClient();
@@ -468,150 +985,12 @@ async function getCartPaymentMethods(cartId) {
468
985
  const { paymentMethods } = await getCartCheckout(cartId);
469
986
  return paymentMethods;
470
987
  }
471
- var CustomerRegisterRequestSchema = z.object({
472
- email: z.string().email(),
473
- firstName: z.string().trim().min(1),
474
- lastName: z.string().trim().min(1),
475
- countryIsoCode: z.string().trim().length(2),
476
- password: z.string(),
477
- phone: z.string().trim().optional()
478
- });
479
- var CustomerAddressSchema = z.object({
480
- /** Presente en listados cuando el upstream expone el id para PUT/DELETE. */
481
- id: z.string().optional(),
482
- addressKey: z.string(),
483
- countryIsoCode: z.string(),
484
- addressLine: z.string(),
485
- addressNumber: z.string(),
486
- department: z.string(),
487
- province: z.string(),
488
- district: z.string(),
489
- phone: z.string(),
490
- cellPhone: z.string(),
491
- postalCode: z.string(),
492
- reference: z.string(),
493
- latitude: z.number().nullable(),
494
- longitude: z.number().nullable(),
495
- isDefault: z.boolean()
496
- });
497
- var CustomerAddressUpsertSchema = CustomerAddressSchema.omit({ id: true });
498
- var CustomerMeSchema = z.object({
499
- id: z.string(),
500
- storeId: z.string(),
501
- email: z.string().email(),
502
- firstName: z.string(),
503
- lastName: z.string(),
504
- phone: z.string(),
505
- identificationNumber: z.string().nullable(),
506
- identificationType: z.string().nullable(),
507
- entityName: z.string().nullable(),
508
- dateOfBirth: z.string().nullable(),
509
- gender: z.string().nullable(),
510
- countryIsoCode: z.string(),
511
- role: z.string().nullable(),
512
- companyName: z.string().nullable(),
513
- consent: z.boolean(),
514
- userId: z.string(),
515
- customerType: z.string(),
516
- status: z.string(),
517
- entityIdentificationNumber: z.string().nullable(),
518
- defaultAddressId: z.string().nullable(),
519
- metadata: z.unknown().nullable(),
520
- totalOrders: z.number(),
521
- avgOrders: z.number(),
522
- lastOrderId: z.string().nullable(),
523
- lastOrderDate: z.string().nullable(),
524
- loyaltyPoints: z.number(),
525
- addresses: z.array(CustomerAddressSchema),
526
- createdOn: z.string(),
527
- updatedOn: z.string().nullable()
528
- });
529
- var CustomerProfilePatchSchema = z.object({
530
- firstName: z.string().trim().min(1),
531
- lastName: z.string().trim().min(1),
532
- phone: z.string().trim(),
533
- identificationNumber: z.string().nullable(),
534
- identificationType: z.string().nullable(),
535
- entityName: z.string().nullable(),
536
- entityIdentificationNumber: z.string().nullable(),
537
- gender: z.string().nullable(),
538
- role: z.string().nullable(),
539
- companyName: z.string().nullable(),
540
- dateOfBirth: z.string().nullable(),
541
- consent: z.boolean(),
542
- countryIsoCode: z.string().trim().length(2)
543
- });
544
- function customerMeToProfilePatch(me) {
545
- return {
546
- firstName: me.firstName,
547
- lastName: me.lastName,
548
- phone: me.phone ?? "",
549
- identificationNumber: me.identificationNumber,
550
- identificationType: me.identificationType,
551
- entityName: me.entityName,
552
- entityIdentificationNumber: me.entityIdentificationNumber,
553
- gender: me.gender,
554
- role: me.role,
555
- companyName: me.companyName,
556
- dateOfBirth: me.dateOfBirth,
557
- consent: me.consent,
558
- countryIsoCode: me.countryIsoCode || "PE"
559
- };
560
- }
561
- function customerAuthOptions(accessToken) {
562
- const token = typeof accessToken === "string" && accessToken.trim().length > 0 ? accessToken.trim() : void 0;
563
- return token ? { bearerToken: token } : {};
564
- }
565
- async function registerCustomer(data) {
566
- const payload = CustomerRegisterRequestSchema.parse(data);
567
- const client = await getStoreApiClient();
568
- return client.post("customer/register", payload);
569
- }
570
- async function getCustomerAddresses(accessToken) {
571
- const client = await getStoreApiClient();
572
- const token = typeof accessToken === "string" && accessToken.trim().length > 0 ? accessToken.trim() : void 0;
573
- const response = await client.get("customer/addresses", {
574
- ...token ? { bearerToken: token } : {}
575
- });
576
- return z.array(CustomerAddressSchema).parse(response);
577
- }
578
- async function createCustomerAddress(data, accessToken) {
579
- const client = await getStoreApiClient();
580
- const token = typeof accessToken === "string" && accessToken.trim().length > 0 ? accessToken.trim() : void 0;
581
- const payload = CustomerAddressUpsertSchema.parse(data);
582
- return client.post("customer/addresses", payload, {
583
- ...token ? { bearerToken: token } : {}
584
- });
585
- }
586
- async function updateCustomerAddress(addressId, data, accessToken) {
587
- const client = await getStoreApiClient();
588
- const token = typeof accessToken === "string" && accessToken.trim().length > 0 ? accessToken.trim() : void 0;
589
- const payload = CustomerAddressUpsertSchema.parse(data);
590
- const id = addressId.trim();
591
- if (!id) throw new Error("addressId requerido");
592
- return client.put(`customer/addresses/${encodeURIComponent(id)}`, payload, {
593
- ...token ? { bearerToken: token } : {}
594
- });
595
- }
596
- async function deleteCustomerAddress(addressId, accessToken) {
597
- const client = await getStoreApiClient();
598
- const token = typeof accessToken === "string" && accessToken.trim().length > 0 ? accessToken.trim() : void 0;
599
- const id = addressId.trim();
600
- if (!id) throw new Error("addressId requerido");
601
- return client.delete(`customer/addresses/${encodeURIComponent(id)}`, {
602
- ...token ? { bearerToken: token } : {}
603
- });
604
- }
605
- async function getCustomerMe(accessToken) {
606
- const client = await getStoreApiClient();
607
- const response = await client.get("customer", customerAuthOptions(accessToken));
608
- return CustomerMeSchema.parse(response);
609
- }
610
- async function patchCustomer(data, accessToken) {
611
- const client = await getStoreApiClient();
612
- const payload = CustomerProfilePatchSchema.parse(data);
613
- await client.patch("customer", payload, customerAuthOptions(accessToken));
614
- }
988
+
989
+ // src/core/client/index.ts
990
+ init_store_api_customer_service();
991
+
992
+ // src/core/client/store-api-customer-order.service.ts
993
+ init_store_api_client();
615
994
  var CustomerOrderShippingAddressSchema = z.object({
616
995
  name: z.string().nullable().optional(),
617
996
  company: z.string().nullable().optional(),
@@ -825,6 +1204,7 @@ var OrderDraftSchema = z.object({
825
1204
  });
826
1205
 
827
1206
  // src/core/client/store-api-order-draft.service.ts
1207
+ init_store_api_client();
828
1208
  async function getSharedOrderDraft(shareToken) {
829
1209
  const client = await getStoreApiClient();
830
1210
  const response = await client.get(
@@ -833,6 +1213,240 @@ async function getSharedOrderDraft(shareToken) {
833
1213
  );
834
1214
  return OrderDraftSchema.parse(response);
835
1215
  }
1216
+
1217
+ // src/npm/nextjs.ts
1218
+ init_store_api_customer_service();
1219
+ var StorefrontCheckoutSettingsSchema = z.object({
1220
+ allowGuestCheckout: z.boolean().optional(),
1221
+ identityScope: z.enum(["store", "tenant", "global"]).optional(),
1222
+ signInMethods: z.array(z.string()).optional()
1223
+ });
1224
+ var looseRecord = z.record(z.string(), z.unknown());
1225
+ var StorefrontThemeConfigSchema = z.object({
1226
+ name: z.string().nullable().optional(),
1227
+ mode: z.string().nullable().optional(),
1228
+ colors: looseRecord.optional(),
1229
+ fonts: looseRecord.optional(),
1230
+ assets: looseRecord.optional()
1231
+ }).passthrough();
1232
+ var StorefrontFeaturesEnabledSchema = z.object({
1233
+ flags: looseRecord.optional()
1234
+ }).passthrough();
1235
+ var StorefrontCmsBrandingSchema = z.object({
1236
+ logoUrl: z.string().nullable().optional(),
1237
+ logoDarkUrl: z.string().nullable().optional(),
1238
+ faviconUrl: z.string().nullable().optional(),
1239
+ socialImageUrl: z.string().nullable().optional()
1240
+ });
1241
+ var StorefrontCmsSeoSchema = z.object({
1242
+ siteName: z.string().nullable().optional(),
1243
+ metaTitle: z.string().nullable().optional(),
1244
+ metaDescription: z.string().nullable().optional(),
1245
+ titleTemplate: z.string().nullable().optional(),
1246
+ robotsIndex: z.boolean().optional()
1247
+ });
1248
+ var StorefrontCmsSocialLinksSchema = z.object({
1249
+ instagram: z.string().nullable().optional(),
1250
+ facebook: z.string().nullable().optional(),
1251
+ tiktok: z.string().nullable().optional(),
1252
+ youtube: z.string().nullable().optional(),
1253
+ x: z.string().nullable().optional()
1254
+ });
1255
+ var StorefrontCmsContactSchema = z.object({
1256
+ supportEmail: z.string().nullable().optional(),
1257
+ phone: z.string().nullable().optional(),
1258
+ whatsapp: z.string().nullable().optional(),
1259
+ address: z.string().nullable().optional(),
1260
+ socialLinks: StorefrontCmsSocialLinksSchema.optional()
1261
+ });
1262
+ var StorefrontCmsTrackingSchema = z.object({
1263
+ googleAnalyticsMeasurementId: z.string().nullable().optional(),
1264
+ metaPixelId: z.string().nullable().optional(),
1265
+ googleTagManagerContainerId: z.string().nullable().optional()
1266
+ });
1267
+ var StorefrontCmsCustomScriptsSchema = z.object({
1268
+ enabled: z.boolean().optional(),
1269
+ head: z.string().nullable().optional(),
1270
+ bodyEnd: z.string().nullable().optional()
1271
+ });
1272
+ var StorefrontCmsSettingsSchema = z.object({
1273
+ themeKey: z.string().optional(),
1274
+ branding: StorefrontCmsBrandingSchema.optional(),
1275
+ seo: StorefrontCmsSeoSchema.optional(),
1276
+ contact: StorefrontCmsContactSchema.optional(),
1277
+ tracking: StorefrontCmsTrackingSchema.optional(),
1278
+ customScripts: StorefrontCmsCustomScriptsSchema.optional(),
1279
+ updatedOn: z.string().nullable().optional()
1280
+ });
1281
+ var StorefrontCmsPageSchema = z.object({
1282
+ id: z.string(),
1283
+ name: z.string(),
1284
+ slug: z.string(),
1285
+ layout: z.string().optional(),
1286
+ version: z.number().optional(),
1287
+ settings: z.record(z.string(), z.unknown()).optional().nullable(),
1288
+ sections: z.array(z.unknown()).optional(),
1289
+ status: z.string().optional(),
1290
+ hasPublishedVersion: z.boolean().optional(),
1291
+ publishedOn: z.string().nullable().optional(),
1292
+ publishedBy: z.string().nullable().optional(),
1293
+ createdOn: z.string().nullable().optional(),
1294
+ updatedOn: z.string().nullable().optional(),
1295
+ createdBy: z.string().nullable().optional(),
1296
+ updatedBy: z.string().nullable().optional(),
1297
+ lastModifiedBy: z.string().nullable().optional()
1298
+ }).passthrough();
1299
+ var StorefrontSettingsLegacyFlatSchema = z.object({
1300
+ id: z.coerce.string(),
1301
+ tenantId: z.string().nullable().optional(),
1302
+ name: z.string(),
1303
+ slug: z.coerce.string().optional(),
1304
+ description: z.string().nullable().optional(),
1305
+ visibility: z.string().nullable().optional(),
1306
+ logo: z.string().nullable().optional(),
1307
+ favicon: z.string().nullable().optional(),
1308
+ icon: z.string().nullable().optional(),
1309
+ currency: z.string().nullable().optional(),
1310
+ language: z.string().nullable().optional(),
1311
+ themeConfig: z.unknown().optional().nullable(),
1312
+ featuresEnabled: z.unknown().optional().nullable(),
1313
+ checkoutSettings: StorefrontCheckoutSettingsSchema.optional().nullable()
1314
+ }).passthrough();
1315
+ function unwrapSettingsResponseBody(v) {
1316
+ if (!v || typeof v !== "object" || Array.isArray(v)) return v;
1317
+ const o = v;
1318
+ if ("data" in o && o.data != null && typeof o.data === "object" && !Array.isArray(o.data)) {
1319
+ return o.data;
1320
+ }
1321
+ return v;
1322
+ }
1323
+ function isLegacyFlatSettingsPayload(v) {
1324
+ if (!v || typeof v !== "object" || Array.isArray(v)) return false;
1325
+ const o = v;
1326
+ if ("store" in o || "schemaVersion" in o || "cms" in o) return false;
1327
+ return (typeof o.id === "string" || typeof o.id === "number") && typeof o.name === "string";
1328
+ }
1329
+ function normalizeStorefrontSettingsPayload(v) {
1330
+ const body = unwrapSettingsResponseBody(v);
1331
+ if (!isLegacyFlatSettingsPayload(body)) return body;
1332
+ const raw = body;
1333
+ const parsed = StorefrontSettingsLegacyFlatSchema.safeParse(raw);
1334
+ if (!parsed.success) return body;
1335
+ const l = parsed.data;
1336
+ const currency = l.currency?.trim() ? l.currency : "PEN";
1337
+ const language = l.language?.trim() ? l.language : "es";
1338
+ const slug = l.slug?.trim() ? l.slug : l.id;
1339
+ return {
1340
+ schemaVersion: 0,
1341
+ generatedAt: (/* @__PURE__ */ new Date(0)).toISOString(),
1342
+ store: {
1343
+ id: l.id,
1344
+ tenantId: l.tenantId ?? void 0,
1345
+ name: l.name,
1346
+ slug,
1347
+ description: l.description ?? null,
1348
+ logo: l.logo ?? null,
1349
+ icon: l.icon ?? null,
1350
+ visibility: l.visibility ?? void 0,
1351
+ currency,
1352
+ language,
1353
+ themeConfig: l.themeConfig ?? void 0,
1354
+ featuresEnabled: l.featuresEnabled ?? void 0,
1355
+ checkoutSettings: l.checkoutSettings ?? void 0
1356
+ },
1357
+ cms: {
1358
+ settings: {
1359
+ branding: {
1360
+ faviconUrl: l.favicon ?? null,
1361
+ logoUrl: l.logo ?? null,
1362
+ logoDarkUrl: null,
1363
+ socialImageUrl: null
1364
+ }
1365
+ },
1366
+ pages: []
1367
+ }
1368
+ };
1369
+ }
1370
+ var StorefrontStoreSchema = z.object({
1371
+ id: z.string(),
1372
+ tenantId: z.string().optional(),
1373
+ sellerId: z.string().optional(),
1374
+ plan: z.string().optional(),
1375
+ storageLimitBytes: z.number().optional(),
1376
+ monthlyTransferLimitBytes: z.number().optional(),
1377
+ maxUploadSizeBytes: z.number().optional(),
1378
+ maxStores: z.number().optional(),
1379
+ maxMembers: z.number().optional(),
1380
+ maxProducts: z.number().optional(),
1381
+ maxCategories: z.number().optional(),
1382
+ maxBrands: z.number().optional(),
1383
+ maxAttributes: z.number().optional(),
1384
+ maxCollections: z.number().optional(),
1385
+ enableApi: z.boolean().optional(),
1386
+ isActive: z.boolean().optional(),
1387
+ name: z.string(),
1388
+ description: z.string().nullable().optional(),
1389
+ avatarUrl: z.string().nullable().optional(),
1390
+ logo: z.string().nullable().optional(),
1391
+ icon: z.string().nullable().optional(),
1392
+ slug: z.string(),
1393
+ domain: z.string().nullable().optional(),
1394
+ domains: z.array(z.string()).optional(),
1395
+ timeZone: z.string().nullable().optional(),
1396
+ currency: z.string(),
1397
+ language: z.string(),
1398
+ visibility: z.string().optional(),
1399
+ privateAccessHash: z.string().nullable().optional(),
1400
+ privateAccessVersion: z.number().optional(),
1401
+ themeConfig: StorefrontThemeConfigSchema.optional(),
1402
+ featuresEnabled: StorefrontFeaturesEnabledSchema.optional(),
1403
+ checkoutSettings: StorefrontCheckoutSettingsSchema.optional().nullable()
1404
+ }).passthrough();
1405
+ var StorefrontSettingsEnvelopeSchema = z.object({
1406
+ schemaVersion: z.number(),
1407
+ generatedAt: z.string(),
1408
+ store: StorefrontStoreSchema,
1409
+ cms: z.object({
1410
+ settings: StorefrontCmsSettingsSchema,
1411
+ pages: z.array(StorefrontCmsPageSchema)
1412
+ })
1413
+ }).passthrough();
1414
+ z.preprocess(
1415
+ normalizeStorefrontSettingsPayload,
1416
+ StorefrontSettingsEnvelopeSchema
1417
+ );
1418
+ function storefrontStoreRecord(settings) {
1419
+ return settings?.store ?? null;
1420
+ }
1421
+
1422
+ // src/core/lib/ecomiq-oauth-identity.ts
1423
+ function buildEcomiqOAuthIdentityHeaders(settings) {
1424
+ const record = storefrontStoreRecord(settings);
1425
+ if (!record?.id) {
1426
+ throw new Error("Tienda no disponible para iniciar sesi\xF3n");
1427
+ }
1428
+ const checkout = record.checkoutSettings;
1429
+ const identityScope = checkout?.identityScope === "tenant" ? "tenant" : "store";
1430
+ const headers3 = {
1431
+ "x-Identity-Scope": identityScope,
1432
+ "x-Store-Id": record.id
1433
+ };
1434
+ if (record.tenantId) headers3["x-Tenant-Id"] = record.tenantId;
1435
+ return headers3;
1436
+ }
1437
+
1438
+ // src/react/auth/ecomiq-storefront-sign-in.ts
1439
+ async function signInWithEcomiqCredentials2(authClient, settings, credentials) {
1440
+ const response = await authClient.$fetch("/ecomiq-oauth/sign-in", {
1441
+ method: "POST",
1442
+ headers: buildEcomiqOAuthIdentityHeaders(settings),
1443
+ body: credentials
1444
+ });
1445
+ if (response.error) {
1446
+ throw new Error(response.error.message ?? "Error al iniciar sesi\xF3n");
1447
+ }
1448
+ return response;
1449
+ }
836
1450
  function useStoreProducts() {
837
1451
  const useStorefrontProductsList = (params) => {
838
1452
  return useQuery({
@@ -1048,73 +1662,6 @@ function useStoreCart() {
1048
1662
  useRemoveCartCoupon
1049
1663
  };
1050
1664
  }
1051
- var useStore = create()(
1052
- (set) => ({
1053
- data: null,
1054
- drawers: {
1055
- cart: false,
1056
- search: false,
1057
- menu: false,
1058
- filter: false
1059
- },
1060
- openDrawer: (drawer) => set((state) => ({
1061
- drawers: {
1062
- ...state.drawers,
1063
- [drawer]: true
1064
- }
1065
- })),
1066
- closeDrawer: (drawer) => set((state) => ({
1067
- drawers: {
1068
- ...state.drawers,
1069
- [drawer]: false
1070
- }
1071
- })),
1072
- toggleDrawer: (drawer) => set((state) => ({
1073
- drawers: {
1074
- ...state.drawers,
1075
- [drawer]: !state.drawers[drawer]
1076
- }
1077
- })),
1078
- closeAllDrawers: () => set((state) => ({
1079
- drawers: Object.keys(state.drawers).reduce(
1080
- (acc, key) => ({ ...acc, [key]: false }),
1081
- {}
1082
- )
1083
- })),
1084
- modals: {
1085
- login: false,
1086
- signup: false
1087
- },
1088
- openModal: (modal) => set((state) => ({
1089
- modals: {
1090
- ...state.modals,
1091
- login: false,
1092
- signup: false,
1093
- [modal]: true
1094
- }
1095
- })),
1096
- closeModal: (modal) => set((state) => ({
1097
- modals: {
1098
- ...state.modals,
1099
- login: false,
1100
- signup: false,
1101
- [modal]: false
1102
- }
1103
- })),
1104
- toggleModal: (modal) => set((state) => ({
1105
- modals: {
1106
- ...state.modals,
1107
- [modal]: !state.modals[modal]
1108
- }
1109
- })),
1110
- closeAllModals: () => set((state) => ({
1111
- modals: Object.keys(state.modals).reduce(
1112
- (acc, key) => ({ ...acc, [key]: false }),
1113
- {}
1114
- )
1115
- }))
1116
- })
1117
- );
1118
1665
  function isRenderableCmsPage(p) {
1119
1666
  if (!p.status) return true;
1120
1667
  return p.status === "published";
@@ -1129,88 +1676,6 @@ function findStorefrontCmsPageBySlug(settings, slug) {
1129
1676
  const parsed = StorefrontPageDetailSchema$1.safeParse(raw);
1130
1677
  return parsed.success ? parsed.data : null;
1131
1678
  }
1132
- function SafeThemeInjector({ theme, className }) {
1133
- try {
1134
- if (!theme || typeof theme !== "object") {
1135
- console.warn("ThemeInjector: Invalid theme provided");
1136
- return null;
1137
- }
1138
- if (!theme.colors || typeof theme.colors !== "object") {
1139
- console.warn("ThemeInjector: Theme colors are required");
1140
- return null;
1141
- }
1142
- const generateSafeCSSVariables = () => {
1143
- const cssRules = [":root {"];
1144
- const toKebabCase = (input) => input.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/_/g, "-").toLowerCase();
1145
- const sanitizeCSSValue = (value) => {
1146
- if (typeof value !== "string") return null;
1147
- const trimmed = value.trim();
1148
- if (!trimmed) return null;
1149
- const isValidCSSValue = /^[a-zA-Z0-9\s,()#.-]+$/.test(trimmed);
1150
- return isValidCSSValue ? trimmed : null;
1151
- };
1152
- if (theme.colors && typeof theme.colors === "object") {
1153
- Object.entries(theme.colors).forEach(([key, value]) => {
1154
- const sanitizedValue = sanitizeCSSValue(value);
1155
- if (sanitizedValue) {
1156
- cssRules.push(` --color-${key}: ${sanitizedValue};`);
1157
- cssRules.push(` --theme-${key}: ${sanitizedValue};`);
1158
- cssRules.push(` --${key}: ${sanitizedValue};`);
1159
- cssRules.push(` --${toKebabCase(key)}: ${sanitizedValue};`);
1160
- }
1161
- });
1162
- }
1163
- if (theme.fonts && typeof theme.fonts === "object") {
1164
- Object.entries(theme.fonts).forEach(([key, value]) => {
1165
- const sanitizedValue = sanitizeCSSValue(value);
1166
- if (sanitizedValue) {
1167
- cssRules.push(` --font-${key}: ${sanitizedValue};`);
1168
- }
1169
- });
1170
- }
1171
- if (theme.spacing && typeof theme.spacing === "object") {
1172
- Object.entries(theme.spacing).forEach(([key, value]) => {
1173
- const sanitizedValue = sanitizeCSSValue(value);
1174
- if (sanitizedValue) {
1175
- cssRules.push(` --spacing-${key}: ${sanitizedValue};`);
1176
- }
1177
- });
1178
- }
1179
- if (theme.borderRadius && typeof theme.borderRadius === "object") {
1180
- Object.entries(theme.borderRadius).forEach(([key, value]) => {
1181
- const sanitizedValue = sanitizeCSSValue(value);
1182
- if (sanitizedValue) {
1183
- cssRules.push(` --radius-${key}: ${sanitizedValue};`);
1184
- }
1185
- });
1186
- }
1187
- if (theme.shadows && typeof theme.shadows === "object") {
1188
- Object.entries(theme.shadows).forEach(([key, value]) => {
1189
- const sanitizedValue = sanitizeCSSValue(value);
1190
- if (sanitizedValue) {
1191
- cssRules.push(` --shadow-${key}: ${sanitizedValue};`);
1192
- }
1193
- });
1194
- }
1195
- cssRules.push("}");
1196
- return cssRules.join("\n");
1197
- };
1198
- const cssVariables = generateSafeCSSVariables();
1199
- return /* @__PURE__ */ jsx(
1200
- "style",
1201
- {
1202
- dangerouslySetInnerHTML: { __html: cssVariables },
1203
- "data-theme-injector": theme.id,
1204
- "data-theme-name": theme.name,
1205
- className,
1206
- suppressHydrationWarning: true
1207
- }
1208
- );
1209
- } catch (error) {
1210
- console.error("ThemeInjector: Error generating theme styles", error);
1211
- return null;
1212
- }
1213
- }
1214
1679
  function buildOptionGroups(variants) {
1215
1680
  const map = /* @__PURE__ */ new Map();
1216
1681
  for (const v of variants) {
@@ -1320,1086 +1785,9 @@ function ProductVariantSelector({
1320
1785
  ] });
1321
1786
  }
1322
1787
 
1323
- // src/react/components/cms-sections/utils.ts
1324
- var PRODUCT_SORTS = /* @__PURE__ */ new Set([
1325
- "price_asc",
1326
- "price_desc",
1327
- "name_asc",
1328
- "name_desc",
1329
- "newest"
1330
- ]);
1331
- function orderedBlocks(blocks) {
1332
- return [...blocks ?? []].sort((a, b) => a.order - b.order);
1333
- }
1334
- function getCmsSectionKey(section, index) {
1335
- return section.id ?? `${canonicalSectionType(section.type)}-${section.order}-${index}`;
1336
- }
1337
- function getCmsBlockKey(block, index) {
1338
- return block.id ?? `${block.type}-${block.order}-${index}`;
1339
- }
1340
- function canonicalSectionType(type) {
1341
- if (type === "page-hero") {
1342
- return "hero";
1343
- }
1344
- if (type === "featured-products") {
1345
- return "product-list";
1346
- }
1347
- return type;
1348
- }
1349
- function storefrontHref(value) {
1350
- const href = value.trim();
1351
- if (!href) {
1352
- return "#";
1353
- }
1354
- if (href === "#" || href.startsWith("http://") || href.startsWith("https://") || href.startsWith("mailto:") || href.startsWith("tel:")) {
1355
- return href;
1356
- }
1357
- if (href === "/") {
1358
- return "/store";
1359
- }
1360
- if (href.startsWith("/store") || href.startsWith("/product")) {
1361
- return href;
1362
- }
1363
- if (href.startsWith("/collections") || href.startsWith("/pages") || href.startsWith("/account")) {
1364
- return `/store${href}`;
1365
- }
1366
- return href;
1367
- }
1368
- function sectionTitleContent(section) {
1369
- return settingContent(section.settings, "title") || settingContent(section.settings, "name");
1370
- }
1371
- function settingString(settings, key) {
1372
- const value = settings?.[key];
1373
- return typeof value === "string" ? value : "";
1374
- }
1375
- function settingContent(settings, key) {
1376
- const value = settings?.[key];
1377
- if (typeof value === "string" || typeof value === "number") {
1378
- return value;
1379
- }
1380
- if (value == null || typeof value === "boolean") {
1381
- return "";
1382
- }
1383
- return value;
1384
- }
1385
- function settingNumber(settings, key, fallback) {
1386
- const value = settings?.[key];
1387
- if (typeof value === "number" && Number.isFinite(value)) {
1388
- return value;
1389
- }
1390
- if (typeof value === "string") {
1391
- const parsed = Number(value);
1392
- return Number.isFinite(parsed) ? parsed : fallback;
1393
- }
1394
- return fallback;
1395
- }
1396
- function layoutChildren(settings, key) {
1397
- const children = settings.children;
1398
- if (typeof children !== "object" || children === null || Array.isArray(children)) {
1399
- return [];
1400
- }
1401
- const value = children[key];
1402
- return Array.isArray(value) ? value : [];
1403
- }
1404
- function layoutPadding(value) {
1405
- switch (value) {
1406
- case "none":
1407
- return "py-0";
1408
- case "small":
1409
- return "py-6";
1410
- case "large":
1411
- return "py-16";
1412
- default:
1413
- return "py-10";
1414
- }
1415
- }
1416
- function layoutMaxWidth(value) {
1417
- switch (value) {
1418
- case "full":
1419
- return "max-w-none";
1420
- case "narrow":
1421
- return "max-w-3xl";
1422
- default:
1423
- return "max-w-7xl";
1424
- }
1425
- }
1426
- function layoutBackground(value) {
1427
- switch (value) {
1428
- case "muted":
1429
- return "bg-neutral-50";
1430
- case "dark":
1431
- return "bg-neutral-950 text-white";
1432
- default:
1433
- return "bg-white";
1434
- }
1435
- }
1436
- function layoutGap(value) {
1437
- switch (value) {
1438
- case "none":
1439
- return "gap-0";
1440
- case "small":
1441
- return "gap-3";
1442
- case "large":
1443
- return "gap-8";
1444
- default:
1445
- return "gap-5";
1446
- }
1447
- }
1448
- function layoutAlign(value) {
1449
- switch (value) {
1450
- case "start":
1451
- return "items-start";
1452
- case "center":
1453
- return "items-center";
1454
- case "end":
1455
- return "items-end";
1456
- default:
1457
- return "items-stretch";
1458
- }
1459
- }
1460
- function layoutJustify(value) {
1461
- switch (value) {
1462
- case "center":
1463
- return "justify-center";
1464
- case "end":
1465
- return "justify-end";
1466
- case "between":
1467
- return "justify-between";
1468
- default:
1469
- return "justify-start";
1470
- }
1471
- }
1472
- function productSortValue(value) {
1473
- return PRODUCT_SORTS.has(value) ? value : "newest";
1474
- }
1475
- function sanitizeHtml(html) {
1476
- return html.replace(/<script[\s\S]*?>[\s\S]*?<\/script>/gi, "").replace(/<style[\s\S]*?>[\s\S]*?<\/style>/gi, "").replace(/<(iframe|object|embed|link|meta)[\s\S]*?>/gi, "").replace(/\son\w+\s*=\s*(['"]).*?\1/gi, "").replace(/\s(href|src)\s*=\s*(['"])\s*javascript:[\s\S]*?\2/gi, "");
1477
- }
1478
- var DEFAULT_CMS_IMAGE_URL = "data:image/svg+xml;charset=UTF-8," + encodeURIComponent(`
1479
- <svg xmlns="http://www.w3.org/2000/svg" width="640" height="360" viewBox="0 0 640 360">
1480
- <rect width="640" height="360" fill="#f4f4f5"/>
1481
- <rect x="40" y="36" width="560" height="288" rx="20" fill="#ffffff" stroke="#d4d4d8"/>
1482
- <path d="M148 246l102-102 78 78 48-48 120 120H148z" fill="#d4d4d8"/>
1483
- <circle cx="456" cy="118" r="32" fill="#e4e4e7"/>
1484
- </svg>
1485
- `);
1486
- function SectionHeading({ section }) {
1487
- const title = sectionTitleContent(section);
1488
- const subtitle = settingContent(section.settings, "subtitle");
1489
- if (!title && !subtitle) {
1490
- return null;
1491
- }
1492
- return /* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
1493
- title ? /* @__PURE__ */ jsx("h2", { className: "text-2xl font-semibold tracking-tight text-neutral-950", children: title }) : null,
1494
- subtitle ? /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-neutral-600", children: subtitle }) : null
1495
- ] });
1496
- }
1497
- function EmptyState({ children }) {
1498
- return /* @__PURE__ */ jsx("p", { className: "rounded-lg border border-dashed p-6 text-center text-sm text-neutral-500", children });
1499
- }
1500
- function DefaultLink({ href, className, children }) {
1501
- return /* @__PURE__ */ jsx("a", { href, className, children });
1502
- }
1503
- function CmsImage({
1504
- src,
1505
- fallbackSrc = DEFAULT_CMS_IMAGE_URL,
1506
- onError,
1507
- ...props
1508
- }) {
1509
- const imageSrc = src?.trim() || fallbackSrc;
1510
- return /* @__PURE__ */ jsx(
1511
- "img",
1512
- {
1513
- src: imageSrc,
1514
- onError: (event) => {
1515
- onError?.(event);
1516
- const image = event.currentTarget;
1517
- if (image.dataset.cmsFallback === "true") {
1518
- return;
1519
- }
1520
- image.dataset.cmsFallback = "true";
1521
- image.src = fallbackSrc;
1522
- },
1523
- ...props
1524
- }
1525
- );
1526
- }
1527
- function RichTextSection({ section }) {
1528
- const html = settingString(section.settings, "html") || settingString(section.settings, "content") || settingString(section.settings, "richText");
1529
- return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-10", children: [
1530
- /* @__PURE__ */ jsx(SectionHeading, { section }),
1531
- html ? /* @__PURE__ */ jsx(
1532
- "div",
1533
- {
1534
- className: "prose prose-neutral max-w-none",
1535
- dangerouslySetInnerHTML: { __html: sanitizeHtml(html) }
1536
- }
1537
- ) : null
1538
- ] });
1539
- }
1540
- function CustomHtmlSection({ section }) {
1541
- const html = settingString(section.settings, "html") || settingString(section.settings, "content");
1542
- if (!html) {
1543
- return null;
1544
- }
1545
- return /* @__PURE__ */ jsx(
1546
- "section",
1547
- {
1548
- className: "cms-custom-html",
1549
- dangerouslySetInnerHTML: { __html: sanitizeHtml(html) }
1550
- }
1551
- );
1552
- }
1553
- function FloatingBlockSection({
1554
- section,
1555
- linkComponent: LinkComponent
1556
- }) {
1557
- const settings = section.settings ?? {};
1558
- const title = settingContent(settings, "title");
1559
- const text = settingContent(settings, "text");
1560
- const imageUrl = settingString(settings, "imageUrl");
1561
- const linkText = settingContent(settings, "linkText");
1562
- const linkUrl = storefrontHref(settingString(settings, "linkUrl"));
1563
- const x = boundedPercent(settingNumber(settings, "x", 8));
1564
- const y = boundedPercent(settingNumber(settings, "y", 12));
1565
- const width = Math.min(
1566
- Math.max(boundedPercent(settingNumber(settings, "width", 28)), 12),
1567
- 90
1568
- );
1569
- const zIndex = Math.max(Math.round(settingNumber(settings, "zIndex", 20)), 1);
1570
- if (!title && !text && !imageUrl) {
1571
- return null;
1572
- }
1573
- const content = /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-lg border border-black/10 bg-white text-neutral-950 shadow-lg", children: [
1574
- imageUrl ? /* @__PURE__ */ jsx("div", { className: "aspect-[16/9] bg-neutral-100", children: /* @__PURE__ */ jsx(
1575
- CmsImage,
1576
- {
1577
- src: imageUrl,
1578
- alt: "",
1579
- className: "h-full w-full object-cover",
1580
- loading: "lazy"
1581
- }
1582
- ) }) : null,
1583
- /* @__PURE__ */ jsxs("div", { className: "p-4", children: [
1584
- title ? /* @__PURE__ */ jsx("p", { className: "text-base font-semibold leading-6", children: title }) : null,
1585
- text ? /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm leading-5 text-neutral-600", children: text }) : null,
1586
- linkText && linkUrl !== "#" ? /* @__PURE__ */ jsx("span", { className: "mt-3 inline-flex text-sm font-medium underline underline-offset-4", children: linkText }) : null
1587
- ] })
1588
- ] });
1589
- return /* @__PURE__ */ jsx(
1590
- "div",
1591
- {
1592
- className: "absolute",
1593
- style: {
1594
- left: `${x}%`,
1595
- top: `${y}%`,
1596
- width: `${width}%`,
1597
- zIndex
1598
- },
1599
- children: linkText && linkUrl !== "#" ? /* @__PURE__ */ jsx(LinkComponent, { href: linkUrl, children: content }) : content
1600
- }
1601
- );
1602
- }
1603
- function FaqSection({ section }) {
1604
- const items = orderedBlocks(section.blocks);
1605
- return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
1606
- /* @__PURE__ */ jsx(SectionHeading, { section }),
1607
- /* @__PURE__ */ jsx("div", { className: "divide-y rounded-lg border bg-white", children: items.map((item, index) => /* @__PURE__ */ jsxs("details", { className: "group p-4", children: [
1608
- /* @__PURE__ */ jsx("summary", { className: "cursor-pointer text-sm font-medium text-neutral-950", children: settingContent(item.settings, "question") || settingContent(item.settings, "title") }),
1609
- /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm leading-6 text-neutral-600", children: settingContent(item.settings, "answer") || settingContent(item.settings, "content") })
1610
- ] }, getCmsBlockKey(item, index))) })
1611
- ] });
1612
- }
1613
- function boundedPercent(value) {
1614
- if (!Number.isFinite(value)) {
1615
- return 0;
1616
- }
1617
- return Math.min(Math.max(value, 0), 100);
1618
- }
1619
- function NewsletterSection({ section }) {
1620
- const title = sectionTitleContent(section) || "Recibe novedades";
1621
- const subtitle = settingContent(section.settings, "subtitle");
1622
- const placeholder = settingString(section.settings, "placeholder") || "tu@email.com";
1623
- const buttonText = settingContent(section.settings, "buttonText") || "Suscribirme";
1624
- return /* @__PURE__ */ jsx("section", { className: "bg-neutral-950 px-4 py-14 text-white", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-2xl text-center", children: [
1625
- /* @__PURE__ */ jsx("h2", { className: "text-3xl font-semibold", children: title }),
1626
- subtitle ? /* @__PURE__ */ jsx("p", { className: "mt-3 text-white/70", children: subtitle }) : null,
1627
- /* @__PURE__ */ jsxs("form", { className: "mt-6 flex flex-col gap-2 sm:flex-row", children: [
1628
- /* @__PURE__ */ jsx(
1629
- "input",
1630
- {
1631
- type: "email",
1632
- placeholder,
1633
- className: "h-10 flex-1 rounded-md border border-white/20 bg-white px-3 text-sm text-neutral-950 outline-none"
1634
- }
1635
- ),
1636
- /* @__PURE__ */ jsx(
1637
- "button",
1638
- {
1639
- type: "submit",
1640
- className: "h-10 rounded-md bg-white px-5 text-sm font-medium text-neutral-950",
1641
- children: buttonText
1642
- }
1643
- )
1644
- ] })
1645
- ] }) });
1646
- }
1647
- function IconRowSection({
1648
- section,
1649
- linkComponent: LinkComponent
1650
- }) {
1651
- return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-10", children: [
1652
- /* @__PURE__ */ jsx(SectionHeading, { section }),
1653
- /* @__PURE__ */ jsx("div", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-4", children: orderedBlocks(section.blocks).map((block, index) => {
1654
- const settings = block.settings ?? {};
1655
- const href = storefrontHref(settingString(settings, "linkUrl"));
1656
- const content = /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-white p-4", children: [
1657
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-neutral-950", children: settingContent(settings, "title") || settingContent(settings, "label") }),
1658
- /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-neutral-600", children: settingContent(settings, "subtitle") || settingContent(settings, "description") })
1659
- ] });
1660
- return href === "#" ? /* @__PURE__ */ jsx("div", { children: content }, getCmsBlockKey(block, index)) : /* @__PURE__ */ jsx(LinkComponent, { href, children: content }, getCmsBlockKey(block, index));
1661
- }) })
1662
- ] });
1663
- }
1664
- function TestimonialsSection({
1665
- section
1666
- }) {
1667
- return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
1668
- /* @__PURE__ */ jsx(SectionHeading, { section }),
1669
- /* @__PURE__ */ jsx("div", { className: "grid gap-4 md:grid-cols-3", children: orderedBlocks(section.blocks).map((block, index) => /* @__PURE__ */ jsxs(
1670
- "blockquote",
1671
- {
1672
- className: "rounded-lg border bg-white p-5",
1673
- children: [
1674
- /* @__PURE__ */ jsx("p", { className: "text-sm leading-6 text-neutral-700", children: settingString(block.settings, "quote") || settingContent(block.settings, "content") || settingContent(block.settings, "text") }),
1675
- /* @__PURE__ */ jsx("footer", { className: "mt-4 text-sm font-medium text-neutral-950", children: settingContent(block.settings, "author") || settingContent(block.settings, "name") })
1676
- ]
1677
- },
1678
- getCmsBlockKey(block, index)
1679
- )) })
1680
- ] });
1681
- }
1682
- function StatsSection({ section }) {
1683
- return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
1684
- /* @__PURE__ */ jsx(SectionHeading, { section }),
1685
- /* @__PURE__ */ jsx("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4", children: orderedBlocks(section.blocks).map((block, index) => /* @__PURE__ */ jsxs(
1686
- "div",
1687
- {
1688
- className: "rounded-lg border bg-white p-5",
1689
- children: [
1690
- /* @__PURE__ */ jsx("p", { className: "text-3xl font-semibold text-neutral-950", children: settingContent(block.settings, "value") }),
1691
- /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-neutral-600", children: settingContent(block.settings, "label") || settingContent(block.settings, "title") })
1692
- ]
1693
- },
1694
- getCmsBlockKey(block, index)
1695
- )) })
1696
- ] });
1697
- }
1698
- function TimelineSection({ section }) {
1699
- return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
1700
- /* @__PURE__ */ jsx(SectionHeading, { section }),
1701
- /* @__PURE__ */ jsx("div", { className: "space-y-4 border-l pl-5", children: orderedBlocks(section.blocks).map((block, index) => /* @__PURE__ */ jsxs("article", { className: "relative", children: [
1702
- /* @__PURE__ */ jsx("span", { className: "absolute -left-[27px] top-1 size-3 rounded-full bg-neutral-950" }),
1703
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-neutral-950", children: settingContent(block.settings, "title") }),
1704
- /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-neutral-600", children: settingContent(block.settings, "description") || settingContent(block.settings, "content") })
1705
- ] }, getCmsBlockKey(block, index))) })
1706
- ] });
1707
- }
1708
- function ContactFormSection({ section }) {
1709
- const fields = orderedBlocks(section.blocks);
1710
- const submitText = settingString(section.settings, "submitText") || "Enviar";
1711
- return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
1712
- /* @__PURE__ */ jsx(SectionHeading, { section }),
1713
- /* @__PURE__ */ jsxs("form", { className: "mx-auto grid max-w-2xl gap-3", children: [
1714
- (fields.length > 0 ? fields : defaultContactFields()).map(
1715
- (field, index) => /* @__PURE__ */ jsx(ContactField, { field }, getCmsBlockKey(field, index))
1716
- ),
1717
- /* @__PURE__ */ jsx("button", { className: "h-10 rounded-md bg-neutral-950 px-4 text-sm font-medium text-white", children: submitText })
1718
- ] })
1719
- ] });
1720
- }
1721
- function ContactField({ field }) {
1722
- const type = settingString(field.settings, "type") || "text";
1723
- const label = settingString(field.settings, "label");
1724
- const placeholder = settingString(field.settings, "placeholder");
1725
- const name = settingString(field.settings, "name");
1726
- const className = "h-10 rounded-md border px-3 text-sm";
1727
- if (type === "textarea") {
1728
- return /* @__PURE__ */ jsx(
1729
- "textarea",
1730
- {
1731
- name,
1732
- "aria-label": label || placeholder,
1733
- className: "min-h-32 rounded-md border px-3 py-2 text-sm",
1734
- placeholder: placeholder || label
1735
- }
1736
- );
1737
- }
1738
- if (type === "select") {
1739
- const rawOptions = field.settings?.options;
1740
- const options = Array.isArray(rawOptions) ? rawOptions.filter((item) => typeof item === "string") : settingString(field.settings, "options").split("\n").map((item) => item.trim()).filter(Boolean);
1741
- return /* @__PURE__ */ jsxs("select", { name, "aria-label": label, className, children: [
1742
- /* @__PURE__ */ jsx("option", { value: "", children: placeholder || label }),
1743
- options.map((option) => /* @__PURE__ */ jsx("option", { value: option, children: option }, option))
1744
- ] });
1745
- }
1746
- return /* @__PURE__ */ jsx(
1747
- "input",
1748
- {
1749
- name,
1750
- type,
1751
- "aria-label": label || placeholder,
1752
- className,
1753
- placeholder: placeholder || label
1754
- }
1755
- );
1756
- }
1757
- function defaultContactFields() {
1758
- return [
1759
- {
1760
- type: "field",
1761
- order: 1,
1762
- settings: { name: "fullName", type: "text", label: "Nombre" }
1763
- },
1764
- {
1765
- type: "field",
1766
- order: 2,
1767
- settings: { name: "email", type: "email", label: "Email" }
1768
- },
1769
- {
1770
- type: "field",
1771
- order: 3,
1772
- settings: { name: "message", type: "textarea", label: "Mensaje" }
1773
- }
1774
- ];
1775
- }
1776
- function UnknownSection({ section }) {
1777
- return /* @__PURE__ */ jsx("section", { className: "container mx-auto px-4 py-8", children: /* @__PURE__ */ jsxs("div", { className: "rounded border border-dashed p-4 text-sm text-neutral-500", children: [
1778
- 'Seccion tipo "',
1779
- section.type,
1780
- '" pendiente de renderer.'
1781
- ] }) });
1782
- }
1783
-
1784
- // src/core/constants/currency.ts
1785
- var countryCurrency = {
1786
- "PEN": "es-PE",
1787
- "USD": "en-US",
1788
- "COP": "es-CO",
1789
- "MXN": "es-MX"
1790
- };
1791
-
1792
- // src/core/utils/format-currency.ts
1793
- function formatCurrency2(amount, currency = "USD") {
1794
- const locale = countryCurrency[currency] ?? "en-US";
1795
- return new Intl.NumberFormat(locale, {
1796
- style: "currency",
1797
- currency
1798
- }).format(amount);
1799
- }
1800
- function AnnouncementBarSection({
1801
- section,
1802
- linkComponent: LinkComponent
1803
- }) {
1804
- const text = settingContent(section.settings, "text") || sectionTitleContent(section);
1805
- const linkText = settingContent(section.settings, "linkText");
1806
- const href = storefrontHref(settingString(section.settings, "linkUrl"));
1807
- if (!text) {
1808
- return null;
1809
- }
1810
- return /* @__PURE__ */ jsx("section", { className: "bg-neutral-950 px-4 py-2 text-white", children: /* @__PURE__ */ jsxs("div", { className: "container mx-auto flex flex-wrap items-center justify-center gap-2 text-center text-sm", children: [
1811
- /* @__PURE__ */ jsx("span", { children: text }),
1812
- linkText && href !== "#" ? /* @__PURE__ */ jsx(
1813
- LinkComponent,
1814
- {
1815
- href,
1816
- className: "font-medium underline underline-offset-4",
1817
- children: linkText
1818
- }
1819
- ) : null
1820
- ] }) });
1821
- }
1822
- function HeroSection({
1823
- section,
1824
- linkComponent: LinkComponent
1825
- }) {
1826
- const slides = orderedBlocks(section.blocks);
1827
- const fallbackSlide = {
1828
- id: `${section.id ?? "section"}-fallback`,
1829
- type: "slide",
1830
- order: 1,
1831
- settings: section.settings ?? {}
1832
- };
1833
- const visibleSlides = slides.length > 0 ? slides : [fallbackSlide];
1834
- return /* @__PURE__ */ jsx("section", { className: "bg-neutral-950 text-white", children: /* @__PURE__ */ jsx("div", { className: "flex snap-x overflow-x-auto", children: visibleSlides.map((slide, index) => {
1835
- const settings = slide.settings ?? {};
1836
- const imageUrl = settingString(settings, "imageUrl") || settingString(section.settings, "imageUrl") || DEFAULT_CMS_IMAGE_URL;
1837
- const title = settingContent(settings, "title") || settingContent(section.settings, "title") || sectionTitleContent(section);
1838
- const subtitle = settingContent(settings, "subtitle") || settingContent(section.settings, "subtitle");
1839
- const ctaText = settingContent(settings, "ctaText") || settingContent(section.settings, "ctaText");
1840
- const ctaUrl = settingString(settings, "ctaUrl") || settingString(section.settings, "ctaUrl");
1841
- const href = storefrontHref(ctaUrl);
1842
- return /* @__PURE__ */ jsxs(
1843
- "article",
1844
- {
1845
- className: "relative min-h-[520px] w-full shrink-0 snap-start overflow-hidden",
1846
- children: [
1847
- /* @__PURE__ */ jsx(
1848
- CmsImage,
1849
- {
1850
- src: imageUrl,
1851
- alt: "",
1852
- className: "absolute inset-0 h-full w-full object-cover opacity-75"
1853
- }
1854
- ),
1855
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-r from-black/70 via-black/35 to-transparent" }),
1856
- /* @__PURE__ */ jsx("div", { className: "container relative z-10 mx-auto flex min-h-[520px] items-center px-4", children: /* @__PURE__ */ jsxs("div", { className: "max-w-2xl py-16", children: [
1857
- /* @__PURE__ */ jsx("h1", { className: "text-4xl font-semibold tracking-tight md:text-6xl", children: title }),
1858
- subtitle ? /* @__PURE__ */ jsx("p", { className: "mt-4 max-w-xl text-base text-white/85 md:text-lg", children: subtitle }) : null,
1859
- ctaText && href !== "#" ? /* @__PURE__ */ jsx(
1860
- LinkComponent,
1861
- {
1862
- href,
1863
- className: "mt-8 inline-flex h-10 items-center rounded-md bg-white px-5 text-sm font-medium text-neutral-950 transition hover:bg-white/90",
1864
- children: ctaText
1865
- }
1866
- ) : null
1867
- ] }) })
1868
- ]
1869
- },
1870
- getCmsBlockKey(slide, index)
1871
- );
1872
- }) }) });
1873
- }
1874
- function ProductsSection({
1875
- section,
1876
- products,
1877
- carousel,
1878
- linkComponent,
1879
- currency,
1880
- preview
1881
- }) {
1882
- const placeholders = preview && products.length === 0;
1883
- const count = Math.min(
1884
- productPreviewCount(section, carousel),
1885
- carousel ? 5 : 8
1886
- );
1887
- return /* @__PURE__ */ jsxs("section", { className: carousel ? "py-12" : "container mx-auto px-4 py-12", children: [
1888
- carousel ? /* @__PURE__ */ jsx("div", { className: "container mx-auto px-4", children: /* @__PURE__ */ jsx(SectionHeading, { section }) }) : /* @__PURE__ */ jsx(SectionHeading, { section }),
1889
- /* @__PURE__ */ jsx("div", { className: carousel ? "container mx-auto overflow-x-auto px-4" : "", children: /* @__PURE__ */ jsx(
1890
- "div",
1891
- {
1892
- className: carousel ? "flex min-w-full gap-4 pb-2" : "grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4",
1893
- children: placeholders ? Array.from({ length: count }).map((_, index) => /* @__PURE__ */ jsx(ProductPlaceholder, { carousel }, index)) : products.map((product) => /* @__PURE__ */ jsx(
1894
- ProductCard,
1895
- {
1896
- product,
1897
- carousel,
1898
- linkComponent,
1899
- currency
1900
- },
1901
- product.id
1902
- ))
1903
- }
1904
- ) }),
1905
- !placeholders && products.length === 0 ? /* @__PURE__ */ jsx(EmptyState, { children: "No hay productos para mostrar." }) : null
1906
- ] });
1907
- }
1908
- function CategoryGridSection({
1909
- section,
1910
- collections,
1911
- linkComponent: LinkComponent,
1912
- preview
1913
- }) {
1914
- const blockItems = orderedBlocks(section.blocks).map((block) => {
1915
- const settings = block.settings ?? {};
1916
- const name = settingContent(settings, "name") || settingContent(settings, "title");
1917
- const url = settingString(settings, "url") || settingString(settings, "linkUrl");
1918
- const imageUrl = settingString(settings, "imageUrl");
1919
- if (!name) {
1920
- return null;
1921
- }
1922
- return {
1923
- id: getCmsBlockKey(block, block.order),
1924
- name,
1925
- href: storefrontHref(url || "/collections"),
1926
- imageUrl: imageUrl || DEFAULT_CMS_IMAGE_URL
1927
- };
1928
- }).filter(Boolean);
1929
- const collectionItems = collections.map((collection) => ({
1930
- id: collection.id,
1931
- name: collection.name,
1932
- href: `/store/collections/${collection.slug}`,
1933
- imageUrl: collection.imageUrl || DEFAULT_CMS_IMAGE_URL
1934
- }));
1935
- const previewItems = preview ? createPreviewCollections(section) : [];
1936
- const items = blockItems.length > 0 ? blockItems : collectionItems.length > 0 ? collectionItems : previewItems;
1937
- return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
1938
- /* @__PURE__ */ jsx(SectionHeading, { section }),
1939
- items.length > 0 ? /* @__PURE__ */ jsx("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3", children: items.map((item) => /* @__PURE__ */ jsxs(
1940
- LinkComponent,
1941
- {
1942
- href: item.href,
1943
- className: "group overflow-hidden rounded-lg border bg-white",
1944
- children: [
1945
- /* @__PURE__ */ jsx("div", { className: "aspect-[4/3] overflow-hidden bg-neutral-100", children: /* @__PURE__ */ jsx(
1946
- CmsImage,
1947
- {
1948
- src: item.imageUrl,
1949
- alt: "",
1950
- className: "h-full w-full object-cover transition duration-300 group-hover:scale-105"
1951
- }
1952
- ) }),
1953
- /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx("h3", { className: "text-base font-medium text-neutral-950", children: item.name }) })
1954
- ]
1955
- },
1956
- item.id
1957
- )) }) : /* @__PURE__ */ jsx(EmptyState, { children: "No hay categorias para mostrar." })
1958
- ] });
1959
- }
1960
- function PromoCardsSection({
1961
- section,
1962
- linkComponent: LinkComponent
1963
- }) {
1964
- const cards = orderedBlocks(section.blocks);
1965
- return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
1966
- /* @__PURE__ */ jsx(SectionHeading, { section }),
1967
- /* @__PURE__ */ jsx("div", { className: "grid gap-4 md:grid-cols-2", children: cards.map((card, index) => {
1968
- const settings = card.settings ?? {};
1969
- const title = settingContent(settings, "title");
1970
- const subtitle = settingContent(settings, "subtitle");
1971
- const imageUrl = settingString(settings, "imageUrl") || DEFAULT_CMS_IMAGE_URL;
1972
- const ctaText = settingContent(settings, "ctaText");
1973
- const ctaUrl = storefrontHref(
1974
- settingString(settings, "ctaUrl") || settingString(settings, "url")
1975
- );
1976
- return /* @__PURE__ */ jsxs(
1977
- LinkComponent,
1978
- {
1979
- href: ctaUrl,
1980
- className: "group relative min-h-[260px] overflow-hidden rounded-lg bg-neutral-900 text-white",
1981
- children: [
1982
- /* @__PURE__ */ jsx(
1983
- CmsImage,
1984
- {
1985
- src: imageUrl,
1986
- alt: "",
1987
- className: "absolute inset-0 h-full w-full object-cover opacity-75 transition duration-300 group-hover:scale-105"
1988
- }
1989
- ),
1990
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/35" }),
1991
- /* @__PURE__ */ jsxs("div", { className: "relative z-10 flex min-h-[260px] flex-col justify-end p-6", children: [
1992
- /* @__PURE__ */ jsx("h3", { className: "text-2xl font-semibold", children: title }),
1993
- subtitle ? /* @__PURE__ */ jsx("p", { className: "mt-2 text-white/85", children: subtitle }) : null,
1994
- ctaText ? /* @__PURE__ */ jsx("span", { className: "mt-4 text-sm font-medium", children: ctaText }) : null
1995
- ] })
1996
- ]
1997
- },
1998
- getCmsBlockKey(card, index)
1999
- );
2000
- }) })
2001
- ] });
2002
- }
2003
- function LogoSliderSection({
2004
- section,
2005
- linkComponent: LinkComponent
2006
- }) {
2007
- return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-10", children: [
2008
- /* @__PURE__ */ jsx(SectionHeading, { section }),
2009
- /* @__PURE__ */ jsx("div", { className: "flex gap-4 overflow-x-auto", children: orderedBlocks(section.blocks).map((block, index) => {
2010
- const settings = block.settings ?? {};
2011
- const imageUrl = settingString(settings, "imageUrl") || DEFAULT_CMS_IMAGE_URL;
2012
- const alt = settingString(settings, "alt") || "Logo";
2013
- const href = storefrontHref(settingString(settings, "linkUrl"));
2014
- const logo = /* @__PURE__ */ jsx("div", { className: "flex h-24 w-40 shrink-0 items-center justify-center rounded-lg border bg-white p-4", children: /* @__PURE__ */ jsx(
2015
- CmsImage,
2016
- {
2017
- src: imageUrl,
2018
- alt,
2019
- className: "max-h-full max-w-full object-contain"
2020
- }
2021
- ) });
2022
- return href !== "#" ? /* @__PURE__ */ jsx(LinkComponent, { href, children: logo }, getCmsBlockKey(block, index)) : /* @__PURE__ */ jsx("div", { children: logo }, getCmsBlockKey(block, index));
2023
- }) })
2024
- ] });
2025
- }
2026
- function ProductCard({
2027
- product,
2028
- carousel,
2029
- linkComponent: LinkComponent,
2030
- currency
2031
- }) {
2032
- const onSale = product.compareAtPrice != null && product.compareAtPrice > product.price;
2033
- return /* @__PURE__ */ jsxs(
2034
- LinkComponent,
2035
- {
2036
- href: `/product/${product.slug}`,
2037
- className: carousel ? "group w-[220px] shrink-0 sm:w-[250px] md:w-[280px]" : "group",
2038
- children: [
2039
- /* @__PURE__ */ jsx("div", { className: "aspect-square overflow-hidden rounded-lg border border-neutral-200 bg-neutral-100 transition-all duration-300 group-hover:border-neutral-300", children: /* @__PURE__ */ jsx(
2040
- CmsImage,
2041
- {
2042
- src: product.imageUrl || DEFAULT_CMS_IMAGE_URL,
2043
- alt: product.name,
2044
- className: "h-full w-full object-cover object-center transition-transform duration-500 group-hover:scale-105"
2045
- }
2046
- ) }),
2047
- /* @__PURE__ */ jsxs("div", { className: "mt-4 flex flex-col", children: [
2048
- /* @__PURE__ */ jsx("h3", { className: "line-clamp-2 text-sm font-medium text-neutral-950", children: product.name }),
2049
- /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-2", children: [
2050
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-neutral-950", children: formatCurrency2(product.price, currency) }),
2051
- onSale ? /* @__PURE__ */ jsx("span", { className: "text-sm text-neutral-500 line-through", children: formatCurrency2(product.compareAtPrice ?? 0, currency) }) : null
2052
- ] })
2053
- ] })
2054
- ]
2055
- }
2056
- );
2057
- }
2058
- function ProductPlaceholder({ carousel }) {
2059
- return /* @__PURE__ */ jsxs(
2060
- "div",
2061
- {
2062
- className: carousel ? "w-[220px] shrink-0 sm:w-[250px] md:w-[280px]" : "",
2063
- children: [
2064
- /* @__PURE__ */ jsx("div", { className: "aspect-square rounded-lg bg-neutral-100" }),
2065
- /* @__PURE__ */ jsx("div", { className: "mt-4 h-3 w-3/4 rounded bg-neutral-200" }),
2066
- /* @__PURE__ */ jsx("div", { className: "mt-2 h-3 w-1/2 rounded bg-neutral-100" })
2067
- ]
2068
- }
2069
- );
2070
- }
2071
- function productPreviewCount(section, carousel) {
2072
- const configuredBlocks = orderedBlocks(section.blocks).length;
2073
- if (configuredBlocks > 0) {
2074
- return configuredBlocks;
2075
- }
2076
- return settingNumber(section.settings, "limit", carousel ? 5 : 8);
2077
- }
2078
- function createPreviewCollections(section) {
2079
- const count = Math.min(settingNumber(section.settings, "limit", 6), 6);
2080
- return Array.from({ length: count }, (_, index) => ({
2081
- id: `preview-collection-${index + 1}`,
2082
- name: `Categoria ${index + 1}`,
2083
- href: "/store/collections/all",
2084
- imageUrl: DEFAULT_CMS_IMAGE_URL
2085
- }));
2086
- }
2087
- function LayoutSection({ section, renderSections }) {
2088
- const settings = section.settings ?? {};
2089
- const paddingY = settingString(settings, "paddingY") || "medium";
2090
- const maxWidth = settingString(settings, "maxWidth") || "container";
2091
- const background = settingString(settings, "background") || "default";
2092
- return /* @__PURE__ */ jsx(
2093
- "section",
2094
- {
2095
- className: `${layoutBackground(background)} ${layoutPadding(paddingY)}`,
2096
- children: /* @__PURE__ */ jsx("div", { className: `mx-auto px-4 ${layoutMaxWidth(maxWidth)}`, children: renderSections(layoutChildren(settings, "content")) })
2097
- }
2098
- );
2099
- }
2100
- function LayoutGrid({ section, renderSections }) {
2101
- const settings = section.settings ?? {};
2102
- const columnCount = Math.min(
2103
- Math.max(Math.round(settingNumber(settings, "columnCount", 2)), 1),
2104
- 6
2105
- );
2106
- return /* @__PURE__ */ jsx(
2107
- "div",
2108
- {
2109
- className: `grid ${layoutGap(settingString(settings, "gap"))}`,
2110
- style: {
2111
- gridTemplateColumns: `repeat(${columnCount}, minmax(0, 1fr))`
2112
- },
2113
- children: renderSections(layoutChildren(settings, "content"))
2114
- }
2115
- );
2116
- }
2117
- function LayoutFlex({ section, renderSections }) {
2118
- const settings = section.settings ?? {};
2119
- return /* @__PURE__ */ jsx(
2120
- "div",
2121
- {
2122
- className: [
2123
- "flex",
2124
- settingString(settings, "direction") === "column" ? "flex-col" : "flex-col md:flex-row",
2125
- settingString(settings, "wrap") === "nowrap" ? "flex-nowrap" : "flex-wrap",
2126
- layoutGap(settingString(settings, "gap")),
2127
- layoutAlign(settingString(settings, "align")),
2128
- layoutJustify(settingString(settings, "justify"))
2129
- ].join(" "),
2130
- children: renderSections(layoutChildren(settings, "content"))
2131
- }
2132
- );
2133
- }
2134
- function LayoutSpace({ section }) {
2135
- const settings = section.settings ?? {};
2136
- const size = settingString(settings, "size") || "24px";
2137
- const direction = settingString(settings, "direction") || "vertical";
2138
- const isHorizontal = direction === "horizontal";
2139
- const isBoth = direction === "both";
2140
- return /* @__PURE__ */ jsx(
2141
- "div",
2142
- {
2143
- "aria-hidden": "true",
2144
- style: {
2145
- display: "block",
2146
- width: isHorizontal || isBoth ? size : "100%",
2147
- height: isHorizontal ? "100%" : size
2148
- }
2149
- }
2150
- );
2151
- }
2152
- function CmsSectionsRenderer({
2153
- sections,
2154
- sectionData,
2155
- linkComponent,
2156
- currency = "PEN",
2157
- preview = false,
2158
- wrap = true
2159
- }) {
2160
- const LinkComponent = linkComponent ?? DefaultLink;
2161
- const sortedSections = [...sections].sort((a, b) => a.order - b.order);
2162
- const content = /* @__PURE__ */ jsx(Fragment, { children: sortedSections.map((section, index) => {
2163
- const sectionKey = getCmsSectionKey(section, index);
2164
- return /* @__PURE__ */ jsx(
2165
- CmsSection,
2166
- {
2167
- section,
2168
- data: sectionData?.[sectionKey],
2169
- linkComponent: LinkComponent,
2170
- currency,
2171
- preview
2172
- },
2173
- sectionKey
2174
- );
2175
- }) });
2176
- return wrap ? /* @__PURE__ */ jsx("div", { className: "relative", children: content }) : content;
2177
- }
2178
- function CmsSection({
2179
- section,
2180
- data,
2181
- linkComponent,
2182
- currency,
2183
- preview
2184
- }) {
2185
- const type = canonicalSectionType(section.type);
2186
- const renderSections = (sections) => /* @__PURE__ */ jsx(
2187
- CmsSectionsRenderer,
2188
- {
2189
- sections,
2190
- linkComponent,
2191
- currency,
2192
- preview,
2193
- wrap: false
2194
- }
2195
- );
2196
- if (type === "layout-section") {
2197
- return /* @__PURE__ */ jsx(
2198
- LayoutSection,
2199
- {
2200
- section,
2201
- linkComponent,
2202
- currency,
2203
- preview,
2204
- renderSections
2205
- }
2206
- );
2207
- }
2208
- if (type === "layout-grid") {
2209
- return /* @__PURE__ */ jsx(
2210
- LayoutGrid,
2211
- {
2212
- section,
2213
- linkComponent,
2214
- currency,
2215
- preview,
2216
- renderSections
2217
- }
2218
- );
2219
- }
2220
- if (type === "layout-flex") {
2221
- return /* @__PURE__ */ jsx(
2222
- LayoutFlex,
2223
- {
2224
- section,
2225
- linkComponent,
2226
- currency,
2227
- preview,
2228
- renderSections
2229
- }
2230
- );
2231
- }
2232
- if (type === "layout-space") {
2233
- return /* @__PURE__ */ jsx(
2234
- LayoutSpace,
2235
- {
2236
- section,
2237
- linkComponent,
2238
- currency,
2239
- preview,
2240
- renderSections
2241
- }
2242
- );
2243
- }
2244
- if (type === "hero") {
2245
- return /* @__PURE__ */ jsx(HeroSection, { section, linkComponent });
2246
- }
2247
- if (type === "announcement-bar") {
2248
- return /* @__PURE__ */ jsx(AnnouncementBarSection, { section, linkComponent });
2249
- }
2250
- if (type === "product-list" || type === "product-carousel") {
2251
- return /* @__PURE__ */ jsx(
2252
- ProductsSection,
2253
- {
2254
- section,
2255
- products: data?.products ?? [],
2256
- carousel: type === "product-carousel",
2257
- linkComponent,
2258
- currency,
2259
- preview
2260
- }
2261
- );
2262
- }
2263
- if (type === "category-grid" || type === "collection-list") {
2264
- return /* @__PURE__ */ jsx(
2265
- CategoryGridSection,
2266
- {
2267
- section,
2268
- collections: data?.collections ?? [],
2269
- linkComponent,
2270
- preview
2271
- }
2272
- );
2273
- }
2274
- if (type === "promo-cards") {
2275
- return /* @__PURE__ */ jsx(PromoCardsSection, { section, linkComponent });
2276
- }
2277
- if (type === "rich-text" || type === "seo-text") {
2278
- return /* @__PURE__ */ jsx(RichTextSection, { section });
2279
- }
2280
- if (type === "custom-html") {
2281
- return /* @__PURE__ */ jsx(CustomHtmlSection, { section });
2282
- }
2283
- if (type === "floating-block") {
2284
- return /* @__PURE__ */ jsx(FloatingBlockSection, { section, linkComponent });
2285
- }
2286
- if (type === "faq") {
2287
- return /* @__PURE__ */ jsx(FaqSection, { section });
2288
- }
2289
- if (type === "newsletter") {
2290
- return /* @__PURE__ */ jsx(NewsletterSection, { section });
2291
- }
2292
- if (type === "trust-badges" || type === "widget-row") {
2293
- return /* @__PURE__ */ jsx(IconRowSection, { section, linkComponent });
2294
- }
2295
- if (type === "logo-slider") {
2296
- return /* @__PURE__ */ jsx(LogoSliderSection, { section, linkComponent });
2297
- }
2298
- if (type === "testimonials") {
2299
- return /* @__PURE__ */ jsx(TestimonialsSection, { section });
2300
- }
2301
- if (type === "stats") {
2302
- return /* @__PURE__ */ jsx(StatsSection, { section });
2303
- }
2304
- if (type === "timeline") {
2305
- return /* @__PURE__ */ jsx(TimelineSection, { section });
2306
- }
2307
- if (type === "contact-form") {
2308
- return /* @__PURE__ */ jsx(ContactFormSection, { section });
2309
- }
2310
- return /* @__PURE__ */ jsx(UnknownSection, { section });
2311
- }
2312
- async function DefaultCmsSectionsRenderer({
2313
- sections
2314
- }) {
2315
- const sortedSections = [...sections].sort((a, b) => a.order - b.order);
2316
- const dataEntries = await Promise.all(
2317
- sortedSections.map(async (section, index) => {
2318
- const data = await resolveSectionData(section);
2319
- return [getCmsSectionKey(section, index), data];
2320
- })
2321
- );
2322
- const sectionData = Object.fromEntries(dataEntries);
2323
- return /* @__PURE__ */ jsx(
2324
- CmsSectionsRenderer,
2325
- {
2326
- sections,
2327
- sectionData,
2328
- linkComponent: Link
2329
- }
2330
- );
2331
- }
2332
- async function resolveSectionData(section) {
2333
- const type = canonicalSectionType(section.type);
2334
- if (type === "product-list" || type === "product-carousel") {
2335
- return { products: await resolveSectionProducts(section) };
2336
- }
2337
- if ((type === "category-grid" || type === "collection-list") && !hasConfiguredCollectionBlocks(section)) {
2338
- return {
2339
- collections: (await getCollectionsSafe()).slice(
2340
- 0,
2341
- settingNumber2(section.settings, "limit", 6)
2342
- )
2343
- };
2344
- }
2345
- return {};
2346
- }
2347
- async function resolveSectionProducts(section) {
2348
- const slugs = orderedBlocks2(section.blocks).map((block) => settingString2(block.settings, "productSlug")).filter(Boolean).slice(0, settingNumber2(section.settings, "limit", 8));
2349
- if (slugs.length > 0) {
2350
- const products = await Promise.all(
2351
- slugs.map((slug) => getStorefrontProductBySlug(slug).catch(() => null))
2352
- );
2353
- return products.filter(Boolean);
2354
- }
2355
- const settings = section.settings ?? {};
2356
- const limit = settingNumber2(
2357
- settings,
2358
- "limit",
2359
- settingNumber2(settings, "pageSize", 8)
2360
- );
2361
- const sort = productSortValue(
2362
- settingString2(settings, "sort")
2363
- );
2364
- const collection = settingString2(settings, "collectionSlug") || settingString2(settings, "collection") || void 0;
2365
- const category = settingString2(settings, "category") || void 0;
2366
- const brand = settingString2(settings, "brand") || void 0;
2367
- const search = settingString2(settings, "search") || void 0;
2368
- const params = {
2369
- page: 1,
2370
- pageSize: limit,
2371
- sort,
2372
- collection,
2373
- category,
2374
- brand,
2375
- search
2376
- };
2377
- const response = await getStorefrontProducts(params).catch(() => null);
2378
- return response?.products ?? [];
2379
- }
2380
- async function getCollectionsSafe() {
2381
- return getStorefrontCollections().catch(() => []);
2382
- }
2383
- function hasConfiguredCollectionBlocks(section) {
2384
- return orderedBlocks2(section.blocks).some(
2385
- (block) => settingString2(block.settings, "name") || settingString2(block.settings, "title")
2386
- );
2387
- }
2388
- function orderedBlocks2(blocks) {
2389
- return [...blocks ?? []].sort((a, b) => a.order - b.order);
2390
- }
2391
- function settingString2(settings, key) {
2392
- const value = settings?.[key];
2393
- return typeof value === "string" ? value : "";
2394
- }
2395
- function settingNumber2(settings, key, fallback) {
2396
- const value = settings?.[key];
2397
- return typeof value === "number" && Number.isFinite(value) ? value : fallback;
2398
- }
2399
-
2400
1788
  // src/npm/nextjs.ts
2401
1789
  var usePublicStore = () => useStore.getState().data;
2402
1790
 
2403
- export { CustomerAddressSchema, CustomerAddressUpsertSchema, CustomerMeSchema, CustomerOrderDetailSchema, CustomerOrderListItemSchema, CustomerProfilePatchSchema, CustomerRegisterRequestSchema, DefaultCmsSectionsRenderer, ECOMIQ_CLIENTS_STORE_KV_BINDING, ProductVariantSelector, SafeThemeInjector, StoreApiClient, addCartCoupon, buildStorefrontKvSnapshotKey, checkoutCart, createCart, createCustomerAddress, createStoreApiClient, customerMeToProfilePatch, deleteCustomerAddress, findStorefrontCmsPageBySlug, getCart, getCartCheckout, getCartPaymentMethods, getCustomerAddresses, getCustomerMe, getCustomerOrder, getCustomerOrders, getHostname, getPublicStore, getSharedOrderDraft, getShippingOptions, getStoreApiBaseUrl, getStoreApiClient, getStorefrontCollectionBySlug, getStorefrontCollections, getStorefrontPageBySlug, getStorefrontPagePreview, getStorefrontPages, getStorefrontProductBySlug, getStorefrontProducts, getStorefrontSettings, getStorefrontSettingsFromKv, isCartNotActiveApiError, normalizeStoreHost, patchCartAddresses, patchCartBuyer, patchCustomer, putCartShippingMethod, registerCustomer, removeCartCoupon, resolvePublicStoreSettingsSource, resolveStorefrontSettingsHost, sanitizeHtml, setClientStoreId, setServerRequestOrigin, setServerStoreId, storeApiClient, updateCustomerAddress, uploadPaymentReceipt, usePublicStore, useStore, useStoreCart, useStoreCollections, useStorePages, useStoreProducts };
1791
+ export { CustomerAddressSchema, CustomerAddressUpsertSchema, CustomerMeSchema, CustomerOrderDetailSchema, CustomerOrderListItemSchema, CustomerProfilePatchSchema, CustomerRegisterRequestSchema, ECOMIQ_CLIENTS_STORE_KV_BINDING, EcomiqProvider, ProductVariantSelector, StoreApiClient, addCartCoupon, buildStorefrontKvSnapshotKey, buildStorefrontKvSnapshotKeyFromStoreKey, checkoutCart, createCart, createCustomerAddress, createStoreApiClient, customerMeToProfilePatch, deleteCustomerAddress, findStorefrontCmsPageBySlug, getCart, getCartCheckout, getCartPaymentMethods, getCustomerAddresses, getCustomerMe, getCustomerOrder, getCustomerOrders, getHostname, getPublicStore, getSharedOrderDraft, getShippingOptions, getStoreApiBaseUrl, getStoreApiClient, getStorefrontCollectionBySlug, getStorefrontCollections, getStorefrontPageBySlug, getStorefrontPagePreview, getStorefrontPages, getStorefrontProductBySlug, getStorefrontProducts, getStorefrontSettings, getStorefrontSettingsFromKv, getStorefrontSettingsFromKvByStoreKey, isCartNotActiveApiError, normalizeStoreHost, patchCartAddresses, patchCartBuyer, patchCustomer, putCartShippingMethod, registerCustomer, removeCartCoupon, resolvePublicStoreSettingsSource, resolveStorefrontSettingsHost, setClientStoreId, setServerRequestOrigin, setServerStoreId, signInWithEcomiqCredentials2 as signInWithEcomiqCredentials, storeApiClient, updateCustomerAddress, uploadPaymentReceipt, usePublicStore, useStore, useStoreCart, useStoreCollections, useStorePages, useStoreProducts };
2404
1792
  //# sourceMappingURL=nextjs.js.map
2405
1793
  //# sourceMappingURL=nextjs.js.map