@ecomiq/storefront 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +177 -0
- package/dist/core.d.ts +3400 -0
- package/dist/core.js +1127 -0
- package/dist/core.js.map +1 -0
- package/dist/find-storefront-cms-page-Bo0-G1FK.d.ts +119 -0
- package/dist/nextjs/api.d.ts +49 -0
- package/dist/nextjs/api.js +170 -0
- package/dist/nextjs/api.js.map +1 -0
- package/dist/nextjs/globals.css +14 -0
- package/dist/nextjs.d.ts +3208 -0
- package/dist/nextjs.js +2405 -0
- package/dist/nextjs.js.map +1 -0
- package/dist/postcss.config.mjs +6 -0
- package/dist/react.d.ts +1044 -0
- package/dist/react.js +3199 -0
- package/dist/react.js.map +1 -0
- package/dist/store-CYBCpY6v.d.ts +4333 -0
- package/package.json +73 -0
package/dist/react.js
ADDED
|
@@ -0,0 +1,3199 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { QueryClient, hydrate, QueryClientProvider, useMutation, useQuery, useQueryClient, useInfiniteQuery } from '@tanstack/react-query';
|
|
4
|
+
import { createContext, useRef, useEffect, useContext, useState, useMemo, useCallback } from 'react';
|
|
5
|
+
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
6
|
+
import { create } from 'zustand';
|
|
7
|
+
import { persist } from 'zustand/middleware';
|
|
8
|
+
import { createAuthMiddleware, createAuthEndpoint, formCsrfMiddleware } from 'better-auth/api';
|
|
9
|
+
import { APIError } from 'better-auth';
|
|
10
|
+
import { setSessionCookie } from 'better-auth/cookies';
|
|
11
|
+
import { parseUserOutput } from 'better-auth/db';
|
|
12
|
+
import { formatCurrency as formatCurrency$1, StorefrontPageDetailSchema as StorefrontPageDetailSchema$1 } from '@ecomiq/storefront/react';
|
|
13
|
+
|
|
14
|
+
// src/core/constants/api-paths.ts
|
|
15
|
+
var STOREFRONT_API_PATH_PREFIX = "v1";
|
|
16
|
+
|
|
17
|
+
// src/core/constants/storefront-ecomiq-oauth-cookie.ts
|
|
18
|
+
var STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME = "ecomiq_sf_oauth_at";
|
|
19
|
+
var STOREFRONT_ECOMIQ_OAUTH_COOKIE_PATH = "/api/store";
|
|
20
|
+
|
|
21
|
+
// src/core/constants/currency.ts
|
|
22
|
+
var countryCurrency = {
|
|
23
|
+
"PEN": "es-PE",
|
|
24
|
+
"USD": "en-US",
|
|
25
|
+
"COP": "es-CO",
|
|
26
|
+
"MXN": "es-MX"
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// src/core/utils/format-currency.ts
|
|
30
|
+
function formatCurrency(amount, currency = "USD") {
|
|
31
|
+
const locale = countryCurrency[currency] ?? "en-US";
|
|
32
|
+
return new Intl.NumberFormat(locale, {
|
|
33
|
+
style: "currency",
|
|
34
|
+
currency
|
|
35
|
+
}).format(amount);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/core/lib/customer-order-labels.ts
|
|
39
|
+
var ORDER_STATUS_LABELS = {
|
|
40
|
+
New: "Pedido realizado",
|
|
41
|
+
Confirmed: "Confirmado",
|
|
42
|
+
Processing: "En preparaci\xF3n",
|
|
43
|
+
InTransit: "En camino",
|
|
44
|
+
Delivered: "Entregado",
|
|
45
|
+
Cancelled: "Cancelado",
|
|
46
|
+
Canceled: "Cancelado",
|
|
47
|
+
Refunded: "Reembolsado",
|
|
48
|
+
Pending: "Pendiente",
|
|
49
|
+
Paid: "Pagado",
|
|
50
|
+
Captured: "Pago confirmado"
|
|
51
|
+
};
|
|
52
|
+
function formatCustomerOrderStatus(status) {
|
|
53
|
+
const trimmed = status.trim();
|
|
54
|
+
if (!trimmed) return "Desconocido";
|
|
55
|
+
return ORDER_STATUS_LABELS[trimmed] ?? trimmed.replace(/([A-Z])/g, " $1").trim();
|
|
56
|
+
}
|
|
57
|
+
function customerOrderStatusTone(status) {
|
|
58
|
+
const s = status.toLowerCase();
|
|
59
|
+
if (s.includes("cancel") || s.includes("refund")) return "danger";
|
|
60
|
+
if (s.includes("deliver")) return "success";
|
|
61
|
+
if (s.includes("transit") || s.includes("ship")) return "info";
|
|
62
|
+
if (s.includes("confirm") || s.includes("paid") || s.includes("capture")) return "success";
|
|
63
|
+
if (s.includes("pending") || s.includes("new") || s.includes("process")) return "warning";
|
|
64
|
+
return "default";
|
|
65
|
+
}
|
|
66
|
+
function formatOrderDate(iso, locale = "es-PE") {
|
|
67
|
+
const d = new Date(iso);
|
|
68
|
+
if (Number.isNaN(d.getTime())) return iso;
|
|
69
|
+
return new Intl.DateTimeFormat(locale, {
|
|
70
|
+
day: "numeric",
|
|
71
|
+
month: "long",
|
|
72
|
+
year: "numeric"
|
|
73
|
+
}).format(d);
|
|
74
|
+
}
|
|
75
|
+
function formatOrderDateTime(iso, locale = "es-PE") {
|
|
76
|
+
const d = new Date(iso);
|
|
77
|
+
if (Number.isNaN(d.getTime())) return iso;
|
|
78
|
+
return new Intl.DateTimeFormat(locale, {
|
|
79
|
+
day: "numeric",
|
|
80
|
+
month: "short",
|
|
81
|
+
year: "numeric",
|
|
82
|
+
hour: "2-digit",
|
|
83
|
+
minute: "2-digit"
|
|
84
|
+
}).format(d);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/core/lib/storefront-geo-inei.ts
|
|
88
|
+
function toGeoItems(data) {
|
|
89
|
+
if (!Array.isArray(data)) return [];
|
|
90
|
+
return data.map((raw) => {
|
|
91
|
+
if (!raw || typeof raw !== "object") return null;
|
|
92
|
+
const item = raw;
|
|
93
|
+
return {
|
|
94
|
+
code: String(item.code ?? ""),
|
|
95
|
+
name: String(item.name ?? "")
|
|
96
|
+
};
|
|
97
|
+
}).filter((x) => !!x && !!x.code && !!x.name);
|
|
98
|
+
}
|
|
99
|
+
var departmentsCache = null;
|
|
100
|
+
var departmentsRequest = null;
|
|
101
|
+
function loadStorefrontGeoDepartments(headers) {
|
|
102
|
+
if (departmentsCache) return Promise.resolve(departmentsCache);
|
|
103
|
+
if (departmentsRequest) return departmentsRequest;
|
|
104
|
+
departmentsRequest = fetch(
|
|
105
|
+
`/api/store/geo/departments?countryCode=PE&source=inei&limit=200`,
|
|
106
|
+
{ cache: "no-store", headers }
|
|
107
|
+
).then((r) => r.json()).then((data) => {
|
|
108
|
+
const items = toGeoItems(data);
|
|
109
|
+
departmentsCache = items;
|
|
110
|
+
return items;
|
|
111
|
+
}).catch(() => {
|
|
112
|
+
departmentsCache = [];
|
|
113
|
+
return [];
|
|
114
|
+
}).finally(() => {
|
|
115
|
+
departmentsRequest = null;
|
|
116
|
+
});
|
|
117
|
+
return departmentsRequest;
|
|
118
|
+
}
|
|
119
|
+
async function fetchStorefrontGeoProvinces(headers, countryCode, departmentCode) {
|
|
120
|
+
const res = await fetch(
|
|
121
|
+
`/api/store/geo/provinces?countryCode=${encodeURIComponent(
|
|
122
|
+
countryCode
|
|
123
|
+
)}&departmentCode=${encodeURIComponent(departmentCode)}&source=inei&limit=200`,
|
|
124
|
+
{ headers }
|
|
125
|
+
);
|
|
126
|
+
const data = await res.json();
|
|
127
|
+
return toGeoItems(data);
|
|
128
|
+
}
|
|
129
|
+
async function fetchStorefrontGeoDistricts(headers, countryCode, provinceCode) {
|
|
130
|
+
const res = await fetch(
|
|
131
|
+
`/api/store/geo/districts?countryCode=${encodeURIComponent(
|
|
132
|
+
countryCode
|
|
133
|
+
)}&provinceCode=${encodeURIComponent(provinceCode)}&source=inei`,
|
|
134
|
+
{ headers }
|
|
135
|
+
);
|
|
136
|
+
const data = await res.json();
|
|
137
|
+
return toGeoItems(data);
|
|
138
|
+
}
|
|
139
|
+
async function resolveIneiCodesFromLabels(storeId, labels, countryCode = "PE") {
|
|
140
|
+
const id = storeId.trim();
|
|
141
|
+
if (!id) return null;
|
|
142
|
+
const headers = { "X-Store-Id": id };
|
|
143
|
+
const departments = await loadStorefrontGeoDepartments(headers);
|
|
144
|
+
const dept = departments.find((d) => d.name.trim() === labels.department.trim());
|
|
145
|
+
if (!dept) return null;
|
|
146
|
+
const provinces = await fetchStorefrontGeoProvinces(headers, countryCode, dept.code);
|
|
147
|
+
const prov = provinces.find((p) => p.name.trim() === labels.province.trim());
|
|
148
|
+
if (!prov) {
|
|
149
|
+
return { departmentCode: dept.code, provinceCode: "", districtCode: "" };
|
|
150
|
+
}
|
|
151
|
+
const districts = await fetchStorefrontGeoDistricts(headers, countryCode, prov.code);
|
|
152
|
+
const dist = districts.find((d) => d.name.trim() === labels.district.trim());
|
|
153
|
+
return {
|
|
154
|
+
departmentCode: dept.code,
|
|
155
|
+
provinceCode: prov.code,
|
|
156
|
+
districtCode: dist?.code ?? ""
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
var ApiClient = class {
|
|
160
|
+
client;
|
|
161
|
+
storeId;
|
|
162
|
+
storeDomain;
|
|
163
|
+
constructor(baseURL = "https://storefront.ecomiq.pe") {
|
|
164
|
+
this.client = axios.create({
|
|
165
|
+
baseURL,
|
|
166
|
+
timeout: 1e4,
|
|
167
|
+
headers: {
|
|
168
|
+
"Content-Type": "application/json"
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
this.client.interceptors.request.use(
|
|
172
|
+
(config) => {
|
|
173
|
+
if (config.headers) {
|
|
174
|
+
if (this.storeId) config.headers["X-Store-Id"] = this.storeId;
|
|
175
|
+
if (this.storeDomain) config.headers["X-Store-Domain"] = this.storeDomain;
|
|
176
|
+
}
|
|
177
|
+
return config;
|
|
178
|
+
}
|
|
179
|
+
);
|
|
180
|
+
this.client.interceptors.response.use(
|
|
181
|
+
(response) => response,
|
|
182
|
+
(error) => {
|
|
183
|
+
console.error("API Error:", error);
|
|
184
|
+
return Promise.reject(error);
|
|
185
|
+
}
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
setStoreId(storeId) {
|
|
189
|
+
this.storeId = storeId;
|
|
190
|
+
}
|
|
191
|
+
/** Subdominio para endpoints que usan X-Store-Domain (ej. GET /v1/storefront/settings) */
|
|
192
|
+
setStoreDomain(domain) {
|
|
193
|
+
this.storeDomain = domain;
|
|
194
|
+
}
|
|
195
|
+
get(url, config) {
|
|
196
|
+
return this.client.get(url, config).then((response) => response.data);
|
|
197
|
+
}
|
|
198
|
+
post(url, data, config) {
|
|
199
|
+
return this.client.post(url, data, config).then((response) => response.data);
|
|
200
|
+
}
|
|
201
|
+
put(url, data, config) {
|
|
202
|
+
return this.client.put(url, data, config).then((response) => response.data);
|
|
203
|
+
}
|
|
204
|
+
patch(url, data, config) {
|
|
205
|
+
return this.client.patch(url, data, config).then((response) => response.data);
|
|
206
|
+
}
|
|
207
|
+
delete(url, config) {
|
|
208
|
+
return this.client.delete(url, config).then((response) => response.data);
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
var apiClient = new ApiClient();
|
|
212
|
+
var ProductVariantSchema = z.object({
|
|
213
|
+
id: z.coerce.string(),
|
|
214
|
+
name: z.string(),
|
|
215
|
+
storeId: z.string(),
|
|
216
|
+
productId: z.coerce.string(),
|
|
217
|
+
basePrice: z.number().positive().optional().nullable(),
|
|
218
|
+
comparePrice: z.number().positive().optional().nullable(),
|
|
219
|
+
//TODO: remove this field
|
|
220
|
+
originalPrice: z.number().positive().optional().nullable(),
|
|
221
|
+
costPrice: z.number().positive().optional().nullable(),
|
|
222
|
+
isDefault: z.boolean().optional().nullable(),
|
|
223
|
+
reserveStock: z.number().nonnegative().optional().nullable(),
|
|
224
|
+
weight: z.number().nonnegative().optional().nullable().default(0),
|
|
225
|
+
width: z.number().nonnegative().optional().nullable(),
|
|
226
|
+
height: z.number().nonnegative().optional().nullable(),
|
|
227
|
+
unitOfMeasure: z.string().optional().nullable(),
|
|
228
|
+
order: z.number().nonnegative().optional().nullable().default(0),
|
|
229
|
+
sku: z.string().optional().nullable(),
|
|
230
|
+
stock: z.number().nonnegative().optional().nullable(),
|
|
231
|
+
leadTime: z.string().optional().nullable(),
|
|
232
|
+
barCode: z.string().optional().nullable(),
|
|
233
|
+
shippingWeight: z.number().nonnegative().optional().nullable(),
|
|
234
|
+
images: z.array(z.string()).optional().nullable(),
|
|
235
|
+
attributes: z.array(z.string()).optional().nullable(),
|
|
236
|
+
variantStatus: z.string().optional().nullable(),
|
|
237
|
+
status: z.string().optional().nullable(),
|
|
238
|
+
createdOn: z.string().optional().nullable(),
|
|
239
|
+
updatedOn: z.string().optional().nullable(),
|
|
240
|
+
deletedOn: z.string().optional().nullable()
|
|
241
|
+
});
|
|
242
|
+
var ProductSchema = z.object({
|
|
243
|
+
id: z.coerce.string(),
|
|
244
|
+
name: z.string(),
|
|
245
|
+
images: z.array(z.object({
|
|
246
|
+
url: z.string().url(),
|
|
247
|
+
name: z.string().optional(),
|
|
248
|
+
isPrimary: z.boolean().optional()
|
|
249
|
+
})),
|
|
250
|
+
basePrice: z.number().positive().optional(),
|
|
251
|
+
salePrice: z.number().positive().optional(),
|
|
252
|
+
slug: z.string(),
|
|
253
|
+
description: z.string().optional(),
|
|
254
|
+
categories: z.array(z.object({
|
|
255
|
+
id: z.coerce.string(),
|
|
256
|
+
name: z.string(),
|
|
257
|
+
slug: z.string(),
|
|
258
|
+
logo: z.string().optional(),
|
|
259
|
+
icon: z.string().optional()
|
|
260
|
+
})).optional(),
|
|
261
|
+
tags: z.array(z.string()).optional(),
|
|
262
|
+
inStock: z.boolean().optional(),
|
|
263
|
+
variants: z.array(ProductVariantSchema).optional()
|
|
264
|
+
});
|
|
265
|
+
var ProductsResponseSchema = z.object({
|
|
266
|
+
items: z.array(ProductSchema),
|
|
267
|
+
meta: z.object({
|
|
268
|
+
total: z.number().int().positive(),
|
|
269
|
+
page: z.number().int().positive(),
|
|
270
|
+
pageSize: z.number().int().positive(),
|
|
271
|
+
hasNextPage: z.boolean()
|
|
272
|
+
})
|
|
273
|
+
});
|
|
274
|
+
var ProductsFiltersSchema = z.object({
|
|
275
|
+
category: z.string().optional(),
|
|
276
|
+
search: z.string().optional(),
|
|
277
|
+
minPrice: z.number().positive().optional(),
|
|
278
|
+
maxPrice: z.number().positive().optional(),
|
|
279
|
+
inStock: z.boolean().optional(),
|
|
280
|
+
sortBy: z.enum(["name", "price", "createdAt"]).optional(),
|
|
281
|
+
sortOrder: z.enum(["asc", "desc"]).optional(),
|
|
282
|
+
page: z.number().int().positive().optional(),
|
|
283
|
+
limit: z.number().int().positive().optional()
|
|
284
|
+
});
|
|
285
|
+
var StorefrontProductSchema = z.object({
|
|
286
|
+
id: z.coerce.string(),
|
|
287
|
+
name: z.string(),
|
|
288
|
+
slug: z.string(),
|
|
289
|
+
productType: z.string().optional().nullable(),
|
|
290
|
+
imageUrl: z.string().optional().nullable(),
|
|
291
|
+
price: z.number().nonnegative(),
|
|
292
|
+
compareAtPrice: z.number().nonnegative().optional().nullable(),
|
|
293
|
+
variantCount: z.number().int().nonnegative().optional().default(0),
|
|
294
|
+
isAvailable: z.boolean(),
|
|
295
|
+
totalInventory: z.number().int().nonnegative(),
|
|
296
|
+
bundleItemsCount: z.number().int().nonnegative().optional().default(0),
|
|
297
|
+
brand: z.string().optional().nullable(),
|
|
298
|
+
category: z.string().optional().nullable(),
|
|
299
|
+
status: z.string().optional().nullable(),
|
|
300
|
+
tags: z.array(z.string()).optional().nullable()
|
|
301
|
+
});
|
|
302
|
+
var StorefrontFacetSchema = z.object({
|
|
303
|
+
value: z.string(),
|
|
304
|
+
count: z.number().int().nonnegative()
|
|
305
|
+
});
|
|
306
|
+
var StorefrontProductsResponseSchema = z.object({
|
|
307
|
+
pageIndex: z.number().int().positive(),
|
|
308
|
+
pageSize: z.number().int().positive(),
|
|
309
|
+
totalCount: z.number().int().nonnegative(),
|
|
310
|
+
totalPages: z.number().int().nonnegative(),
|
|
311
|
+
products: z.array(StorefrontProductSchema),
|
|
312
|
+
categories: z.array(StorefrontFacetSchema).optional().default([]),
|
|
313
|
+
brands: z.array(StorefrontFacetSchema).optional().default([]),
|
|
314
|
+
minPrice: z.number().nonnegative().optional().nullable(),
|
|
315
|
+
maxPrice: z.number().nonnegative().optional().nullable()
|
|
316
|
+
});
|
|
317
|
+
var StorefrontProductsParamsSchema = z.object({
|
|
318
|
+
page: z.number().int().positive().optional().default(1),
|
|
319
|
+
pageSize: z.number().int().positive().optional().default(20),
|
|
320
|
+
sort: z.enum(["price_asc", "price_desc", "name_asc", "name_desc", "newest"]).optional().default("price_asc"),
|
|
321
|
+
sellerId: z.string().optional(),
|
|
322
|
+
search: z.string().optional(),
|
|
323
|
+
collection: z.string().optional(),
|
|
324
|
+
category: z.string().optional(),
|
|
325
|
+
brand: z.string().optional(),
|
|
326
|
+
productType: z.string().optional(),
|
|
327
|
+
inStock: z.boolean().optional(),
|
|
328
|
+
minPrice: z.number().nonnegative().optional(),
|
|
329
|
+
maxPrice: z.number().nonnegative().optional()
|
|
330
|
+
});
|
|
331
|
+
var StorefrontVariantOptionSchema = z.object({
|
|
332
|
+
key: z.string(),
|
|
333
|
+
name: z.string(),
|
|
334
|
+
value: z.string()
|
|
335
|
+
});
|
|
336
|
+
var StorefrontProductImageSchema = z.object({
|
|
337
|
+
url: z.string(),
|
|
338
|
+
name: z.string().optional().nullable(),
|
|
339
|
+
order: z.number().int().nonnegative().optional()
|
|
340
|
+
});
|
|
341
|
+
var StorefrontVariantSchema = z.object({
|
|
342
|
+
id: z.coerce.string().optional().default(""),
|
|
343
|
+
sku: z.string(),
|
|
344
|
+
status: z.string().optional().nullable(),
|
|
345
|
+
price: z.number().nonnegative(),
|
|
346
|
+
compareAtPrice: z.number().nonnegative().optional().nullable(),
|
|
347
|
+
quantity: z.number().int().nonnegative(),
|
|
348
|
+
options: z.array(StorefrontVariantOptionSchema).optional().default([]),
|
|
349
|
+
images: z.array(StorefrontProductImageSchema).optional().default([])
|
|
350
|
+
});
|
|
351
|
+
var StorefrontPriceTierSchema = z.object({
|
|
352
|
+
variantId: z.coerce.string(),
|
|
353
|
+
minQuantity: z.number().int().positive(),
|
|
354
|
+
maxQuantity: z.number().int().positive().optional().nullable(),
|
|
355
|
+
unitPrice: z.number().nonnegative()
|
|
356
|
+
});
|
|
357
|
+
var StorefrontBundleItemSchema = z.object({
|
|
358
|
+
productId: z.coerce.string(),
|
|
359
|
+
variantId: z.coerce.string(),
|
|
360
|
+
productName: z.string(),
|
|
361
|
+
variantName: z.string().optional().nullable(),
|
|
362
|
+
sku: z.string().optional().nullable(),
|
|
363
|
+
brand: z.string().optional().nullable(),
|
|
364
|
+
imageUrl: z.string().optional().nullable(),
|
|
365
|
+
quantity: z.number().int(),
|
|
366
|
+
availableStock: z.number().int().optional().default(0),
|
|
367
|
+
allowBackorders: z.boolean().optional().default(false),
|
|
368
|
+
requiresShipping: z.boolean().optional().default(true)
|
|
369
|
+
});
|
|
370
|
+
var StorefrontProductDetailSchema = z.object({
|
|
371
|
+
id: z.coerce.string(),
|
|
372
|
+
name: z.string(),
|
|
373
|
+
slug: z.string(),
|
|
374
|
+
description: z.string().optional().nullable(),
|
|
375
|
+
productType: z.string().optional().nullable(),
|
|
376
|
+
status: z.string().optional().nullable(),
|
|
377
|
+
imageUrl: z.string().optional().nullable(),
|
|
378
|
+
price: z.number().nonnegative(),
|
|
379
|
+
compareAtPrice: z.number().nonnegative().optional().nullable(),
|
|
380
|
+
isAvailable: z.boolean(),
|
|
381
|
+
totalInventory: z.number().int().nonnegative(),
|
|
382
|
+
brand: z.string().optional().nullable(),
|
|
383
|
+
category: z.string().optional().nullable(),
|
|
384
|
+
categoryId: z.coerce.string().optional().nullable(),
|
|
385
|
+
tags: z.array(z.string()).optional().nullable(),
|
|
386
|
+
specifications: z.array(z.record(z.string(), z.unknown())).optional().default([]),
|
|
387
|
+
variants: z.array(StorefrontVariantSchema).optional().default([]),
|
|
388
|
+
images: z.array(StorefrontProductImageSchema).optional().default([]),
|
|
389
|
+
bundleItems: z.array(StorefrontBundleItemSchema).optional().default([]),
|
|
390
|
+
priceTiers: z.array(StorefrontPriceTierSchema).optional().default([]),
|
|
391
|
+
createdAt: z.string().optional().nullable(),
|
|
392
|
+
updatedAt: z.string().optional().nullable()
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
// src/core/services/product.service.ts
|
|
396
|
+
var ProductService = class _ProductService {
|
|
397
|
+
static instance;
|
|
398
|
+
constructor() {
|
|
399
|
+
}
|
|
400
|
+
static getInstance() {
|
|
401
|
+
if (!_ProductService.instance) {
|
|
402
|
+
_ProductService.instance = new _ProductService();
|
|
403
|
+
}
|
|
404
|
+
return _ProductService.instance;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Obtiene todos los productos del store
|
|
408
|
+
*/
|
|
409
|
+
async getProducts(filters) {
|
|
410
|
+
if (filters) {
|
|
411
|
+
ProductsFiltersSchema.parse(filters);
|
|
412
|
+
}
|
|
413
|
+
const params = new URLSearchParams();
|
|
414
|
+
if (filters) {
|
|
415
|
+
if (filters.category) params.append("category", filters.category);
|
|
416
|
+
if (filters.search) params.append("search", filters.search);
|
|
417
|
+
if (filters.minPrice) params.append("minPrice", filters.minPrice.toString());
|
|
418
|
+
if (filters.maxPrice) params.append("maxPrice", filters.maxPrice.toString());
|
|
419
|
+
if (filters.sortBy) params.append("sortBy", filters.sortBy);
|
|
420
|
+
if (filters.sortOrder) params.append("sortOrder", filters.sortOrder);
|
|
421
|
+
if (filters.page) params.append("page", filters.page.toString());
|
|
422
|
+
if (filters.limit) params.append("limit", filters.limit.toString());
|
|
423
|
+
}
|
|
424
|
+
const queryString = params.toString();
|
|
425
|
+
const url = `/${STOREFRONT_API_PATH_PREFIX}/products${queryString ? `?${queryString}` : ""}`;
|
|
426
|
+
const response = await apiClient.get(url);
|
|
427
|
+
return ProductsResponseSchema.parse(response);
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Obtiene un producto específico por ID
|
|
431
|
+
*/
|
|
432
|
+
async getProduct(id) {
|
|
433
|
+
const response = await apiClient.get(`/${STOREFRONT_API_PATH_PREFIX}/products/${id}`);
|
|
434
|
+
return ProductSchema.parse(response);
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Obtiene un producto específico por slug
|
|
438
|
+
*/
|
|
439
|
+
async getProductBySlug(slug) {
|
|
440
|
+
const response = await apiClient.get(`/${STOREFRONT_API_PATH_PREFIX}/products/${encodeURIComponent(slug)}`);
|
|
441
|
+
return ProductSchema.parse(response);
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Busca productos por término de búsqueda
|
|
445
|
+
*/
|
|
446
|
+
async searchProducts(query, filters) {
|
|
447
|
+
return this.getProducts({ ...filters, search: query });
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Obtiene productos por categoría
|
|
451
|
+
*/
|
|
452
|
+
async getProductsByCategory(category, filters) {
|
|
453
|
+
return this.getProducts({ ...filters, category });
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Obtiene productos en oferta (con descuento)
|
|
457
|
+
*/
|
|
458
|
+
async getProductsOnSale(filters) {
|
|
459
|
+
return this.getProducts({ ...filters, minPrice: 0 });
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Obtiene productos en stock
|
|
463
|
+
*/
|
|
464
|
+
async getProductsInStock(filters) {
|
|
465
|
+
return this.getProducts({ ...filters, inStock: true });
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Lista de productos del storefront (API v1/storefront/products).
|
|
469
|
+
* Soporta paginación, orden y filtros por categoría, marca y precio.
|
|
470
|
+
*/
|
|
471
|
+
async getStorefrontProducts(params) {
|
|
472
|
+
const parsed = StorefrontProductsParamsSchema.parse(params ?? {});
|
|
473
|
+
const searchParams = new URLSearchParams();
|
|
474
|
+
searchParams.set("page", String(parsed.page));
|
|
475
|
+
searchParams.set("pageSize", String(parsed.pageSize));
|
|
476
|
+
if (parsed.sort) searchParams.set("sort", parsed.sort);
|
|
477
|
+
if (parsed.sellerId) searchParams.set("sellerId", parsed.sellerId);
|
|
478
|
+
if (parsed.collection) searchParams.set("collection", parsed.collection);
|
|
479
|
+
if (parsed.category) searchParams.set("category", parsed.category);
|
|
480
|
+
if (parsed.brand) searchParams.set("brand", parsed.brand);
|
|
481
|
+
if (parsed.productType) searchParams.set("productType", parsed.productType);
|
|
482
|
+
if (parsed.inStock != null) searchParams.set("inStock", String(parsed.inStock));
|
|
483
|
+
if (parsed.minPrice != null) searchParams.set("minPrice", String(parsed.minPrice));
|
|
484
|
+
if (parsed.maxPrice != null) searchParams.set("maxPrice", String(parsed.maxPrice));
|
|
485
|
+
if (parsed.search) searchParams.set("search", parsed.search);
|
|
486
|
+
const url = `/${STOREFRONT_API_PATH_PREFIX}/products?${searchParams.toString()}`;
|
|
487
|
+
const response = await apiClient.get(url);
|
|
488
|
+
return StorefrontProductsResponseSchema.parse(response);
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Obtiene un producto del storefront por slug (API v1/storefront/products/by-slug/:slug).
|
|
492
|
+
*/
|
|
493
|
+
async getStorefrontProductBySlug(slug) {
|
|
494
|
+
const response = await apiClient.get(`/${STOREFRONT_API_PATH_PREFIX}/products/by-slug/${encodeURIComponent(slug)}`);
|
|
495
|
+
return StorefrontProductDetailSchema.parse(response);
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
var productService = ProductService.getInstance();
|
|
499
|
+
var StorefrontCollectionSchema = z.object({
|
|
500
|
+
id: z.coerce.string(),
|
|
501
|
+
slug: z.string(),
|
|
502
|
+
name: z.string(),
|
|
503
|
+
description: z.string().nullable().optional(),
|
|
504
|
+
imageUrl: z.string().nullable().optional(),
|
|
505
|
+
type: z.string(),
|
|
506
|
+
productCount: z.number().int().nonnegative()
|
|
507
|
+
});
|
|
508
|
+
var StorefrontCollectionsResponseSchema = z.array(StorefrontCollectionSchema);
|
|
509
|
+
var StorefrontCollectionDetailSchema = StorefrontCollectionSchema;
|
|
510
|
+
|
|
511
|
+
// src/core/services/collection.service.ts
|
|
512
|
+
var CollectionService = class _CollectionService {
|
|
513
|
+
static instance;
|
|
514
|
+
constructor() {
|
|
515
|
+
}
|
|
516
|
+
static getInstance() {
|
|
517
|
+
if (!_CollectionService.instance) {
|
|
518
|
+
_CollectionService.instance = new _CollectionService();
|
|
519
|
+
}
|
|
520
|
+
return _CollectionService.instance;
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Lista de colecciones del storefront (GET /v1/collections).
|
|
524
|
+
*/
|
|
525
|
+
async getStorefrontCollections() {
|
|
526
|
+
const response = await apiClient.get(
|
|
527
|
+
`/${STOREFRONT_API_PATH_PREFIX}/collections`
|
|
528
|
+
);
|
|
529
|
+
return StorefrontCollectionsResponseSchema.parse(response);
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Obtiene una colección del storefront por slug (GET /v1/collections/by-slug/:slug).
|
|
533
|
+
*/
|
|
534
|
+
async getStorefrontCollectionBySlug(slug) {
|
|
535
|
+
const response = await apiClient.get(
|
|
536
|
+
`/${STOREFRONT_API_PATH_PREFIX}/collections/by-slug/${encodeURIComponent(slug)}`
|
|
537
|
+
);
|
|
538
|
+
return StorefrontCollectionDetailSchema.parse(response);
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
var collectionService = CollectionService.getInstance();
|
|
542
|
+
var StorefrontPageListItemSchema = z.object({
|
|
543
|
+
id: z.string(),
|
|
544
|
+
name: z.string(),
|
|
545
|
+
slug: z.string(),
|
|
546
|
+
layout: z.string()
|
|
547
|
+
});
|
|
548
|
+
var StorefrontPageSeoSchema = z.object({
|
|
549
|
+
title: z.string().optional(),
|
|
550
|
+
description: z.string().optional()
|
|
551
|
+
}).optional();
|
|
552
|
+
var StorefrontPageSettingsSchema = z.object({
|
|
553
|
+
seo: StorefrontPageSeoSchema,
|
|
554
|
+
html: z.string().optional(),
|
|
555
|
+
title: z.string().optional()
|
|
556
|
+
}).catchall(z.unknown());
|
|
557
|
+
var StorefrontPageBlockSchema = z.object({
|
|
558
|
+
id: z.string(),
|
|
559
|
+
type: z.string(),
|
|
560
|
+
order: z.number(),
|
|
561
|
+
settings: z.record(z.unknown()).optional()
|
|
562
|
+
});
|
|
563
|
+
var StorefrontPageSectionSchema = z.object({
|
|
564
|
+
id: z.string(),
|
|
565
|
+
type: z.string(),
|
|
566
|
+
order: z.number(),
|
|
567
|
+
settings: z.record(z.unknown()).optional(),
|
|
568
|
+
blocks: z.array(StorefrontPageBlockSchema).optional().default([])
|
|
569
|
+
});
|
|
570
|
+
var StorefrontPageDetailSchema = z.object({
|
|
571
|
+
id: z.string(),
|
|
572
|
+
name: z.string(),
|
|
573
|
+
slug: z.string(),
|
|
574
|
+
layout: z.string(),
|
|
575
|
+
settings: StorefrontPageSettingsSchema.optional(),
|
|
576
|
+
sections: z.array(StorefrontPageSectionSchema).optional()
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
// src/core/services/page.service.ts
|
|
580
|
+
var PageService = class _PageService {
|
|
581
|
+
static instance;
|
|
582
|
+
constructor() {
|
|
583
|
+
}
|
|
584
|
+
static getInstance() {
|
|
585
|
+
if (!_PageService.instance) {
|
|
586
|
+
_PageService.instance = new _PageService();
|
|
587
|
+
}
|
|
588
|
+
return _PageService.instance;
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Lista de páginas del storefront (GET /v1/pages).
|
|
592
|
+
*/
|
|
593
|
+
async getPages() {
|
|
594
|
+
const response = await apiClient.get(
|
|
595
|
+
`/${STOREFRONT_API_PATH_PREFIX}/pages`
|
|
596
|
+
);
|
|
597
|
+
return z.array(StorefrontPageListItemSchema).parse(response);
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Obtiene una página por slug (GET /v1/pages/{slug}).
|
|
601
|
+
* sections puede no venir en la respuesta.
|
|
602
|
+
*/
|
|
603
|
+
async getPageBySlug(slug) {
|
|
604
|
+
const response = await apiClient.get(
|
|
605
|
+
`/${STOREFRONT_API_PATH_PREFIX}/pages/${encodeURIComponent(slug)}`
|
|
606
|
+
);
|
|
607
|
+
return StorefrontPageDetailSchema.parse(response);
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
var pageService = PageService.getInstance();
|
|
611
|
+
var StorefrontCheckoutSettingsSchema = z.object({
|
|
612
|
+
allowGuestCheckout: z.boolean().optional(),
|
|
613
|
+
identityScope: z.enum(["store", "tenant", "global"]).optional(),
|
|
614
|
+
signInMethods: z.array(z.string()).optional()
|
|
615
|
+
});
|
|
616
|
+
var looseRecord = z.record(z.string(), z.unknown());
|
|
617
|
+
var StorefrontThemeConfigSchema = z.object({
|
|
618
|
+
name: z.string().nullable().optional(),
|
|
619
|
+
mode: z.string().nullable().optional(),
|
|
620
|
+
colors: looseRecord.optional(),
|
|
621
|
+
fonts: looseRecord.optional(),
|
|
622
|
+
assets: looseRecord.optional()
|
|
623
|
+
}).passthrough();
|
|
624
|
+
var StorefrontFeaturesEnabledSchema = z.object({
|
|
625
|
+
flags: looseRecord.optional()
|
|
626
|
+
}).passthrough();
|
|
627
|
+
var StorefrontCmsBrandingSchema = z.object({
|
|
628
|
+
logoUrl: z.string().nullable().optional(),
|
|
629
|
+
logoDarkUrl: z.string().nullable().optional(),
|
|
630
|
+
faviconUrl: z.string().nullable().optional(),
|
|
631
|
+
socialImageUrl: z.string().nullable().optional()
|
|
632
|
+
});
|
|
633
|
+
var StorefrontCmsSeoSchema = z.object({
|
|
634
|
+
siteName: z.string().nullable().optional(),
|
|
635
|
+
metaTitle: z.string().nullable().optional(),
|
|
636
|
+
metaDescription: z.string().nullable().optional(),
|
|
637
|
+
titleTemplate: z.string().nullable().optional(),
|
|
638
|
+
robotsIndex: z.boolean().optional()
|
|
639
|
+
});
|
|
640
|
+
var StorefrontCmsSocialLinksSchema = z.object({
|
|
641
|
+
instagram: z.string().nullable().optional(),
|
|
642
|
+
facebook: z.string().nullable().optional(),
|
|
643
|
+
tiktok: z.string().nullable().optional(),
|
|
644
|
+
youtube: z.string().nullable().optional(),
|
|
645
|
+
x: z.string().nullable().optional()
|
|
646
|
+
});
|
|
647
|
+
var StorefrontCmsContactSchema = z.object({
|
|
648
|
+
supportEmail: z.string().nullable().optional(),
|
|
649
|
+
phone: z.string().nullable().optional(),
|
|
650
|
+
whatsapp: z.string().nullable().optional(),
|
|
651
|
+
address: z.string().nullable().optional(),
|
|
652
|
+
socialLinks: StorefrontCmsSocialLinksSchema.optional()
|
|
653
|
+
});
|
|
654
|
+
var StorefrontCmsTrackingSchema = z.object({
|
|
655
|
+
googleAnalyticsMeasurementId: z.string().nullable().optional(),
|
|
656
|
+
metaPixelId: z.string().nullable().optional(),
|
|
657
|
+
googleTagManagerContainerId: z.string().nullable().optional()
|
|
658
|
+
});
|
|
659
|
+
var StorefrontCmsCustomScriptsSchema = z.object({
|
|
660
|
+
enabled: z.boolean().optional(),
|
|
661
|
+
head: z.string().nullable().optional(),
|
|
662
|
+
bodyEnd: z.string().nullable().optional()
|
|
663
|
+
});
|
|
664
|
+
var StorefrontCmsSettingsSchema = z.object({
|
|
665
|
+
themeKey: z.string().optional(),
|
|
666
|
+
branding: StorefrontCmsBrandingSchema.optional(),
|
|
667
|
+
seo: StorefrontCmsSeoSchema.optional(),
|
|
668
|
+
contact: StorefrontCmsContactSchema.optional(),
|
|
669
|
+
tracking: StorefrontCmsTrackingSchema.optional(),
|
|
670
|
+
customScripts: StorefrontCmsCustomScriptsSchema.optional(),
|
|
671
|
+
updatedOn: z.string().nullable().optional()
|
|
672
|
+
});
|
|
673
|
+
var StorefrontCmsPageSchema = z.object({
|
|
674
|
+
id: z.string(),
|
|
675
|
+
name: z.string(),
|
|
676
|
+
slug: z.string(),
|
|
677
|
+
layout: z.string().optional(),
|
|
678
|
+
version: z.number().optional(),
|
|
679
|
+
settings: z.record(z.string(), z.unknown()).optional().nullable(),
|
|
680
|
+
sections: z.array(z.unknown()).optional(),
|
|
681
|
+
status: z.string().optional(),
|
|
682
|
+
hasPublishedVersion: z.boolean().optional(),
|
|
683
|
+
publishedOn: z.string().nullable().optional(),
|
|
684
|
+
publishedBy: z.string().nullable().optional(),
|
|
685
|
+
createdOn: z.string().nullable().optional(),
|
|
686
|
+
updatedOn: z.string().nullable().optional(),
|
|
687
|
+
createdBy: z.string().nullable().optional(),
|
|
688
|
+
updatedBy: z.string().nullable().optional(),
|
|
689
|
+
lastModifiedBy: z.string().nullable().optional()
|
|
690
|
+
}).passthrough();
|
|
691
|
+
var StorefrontSettingsLegacyFlatSchema = z.object({
|
|
692
|
+
id: z.coerce.string(),
|
|
693
|
+
tenantId: z.string().nullable().optional(),
|
|
694
|
+
name: z.string(),
|
|
695
|
+
slug: z.coerce.string().optional(),
|
|
696
|
+
description: z.string().nullable().optional(),
|
|
697
|
+
visibility: z.string().nullable().optional(),
|
|
698
|
+
logo: z.string().nullable().optional(),
|
|
699
|
+
favicon: z.string().nullable().optional(),
|
|
700
|
+
icon: z.string().nullable().optional(),
|
|
701
|
+
currency: z.string().nullable().optional(),
|
|
702
|
+
language: z.string().nullable().optional(),
|
|
703
|
+
themeConfig: z.unknown().optional().nullable(),
|
|
704
|
+
featuresEnabled: z.unknown().optional().nullable(),
|
|
705
|
+
checkoutSettings: StorefrontCheckoutSettingsSchema.optional().nullable()
|
|
706
|
+
}).passthrough();
|
|
707
|
+
function unwrapSettingsResponseBody(v) {
|
|
708
|
+
if (!v || typeof v !== "object" || Array.isArray(v)) return v;
|
|
709
|
+
const o = v;
|
|
710
|
+
if ("data" in o && o.data != null && typeof o.data === "object" && !Array.isArray(o.data)) {
|
|
711
|
+
return o.data;
|
|
712
|
+
}
|
|
713
|
+
return v;
|
|
714
|
+
}
|
|
715
|
+
function isLegacyFlatSettingsPayload(v) {
|
|
716
|
+
if (!v || typeof v !== "object" || Array.isArray(v)) return false;
|
|
717
|
+
const o = v;
|
|
718
|
+
if ("store" in o || "schemaVersion" in o || "cms" in o) return false;
|
|
719
|
+
return (typeof o.id === "string" || typeof o.id === "number") && typeof o.name === "string";
|
|
720
|
+
}
|
|
721
|
+
function normalizeStorefrontSettingsPayload(v) {
|
|
722
|
+
const body = unwrapSettingsResponseBody(v);
|
|
723
|
+
if (!isLegacyFlatSettingsPayload(body)) return body;
|
|
724
|
+
const raw = body;
|
|
725
|
+
const parsed = StorefrontSettingsLegacyFlatSchema.safeParse(raw);
|
|
726
|
+
if (!parsed.success) return body;
|
|
727
|
+
const l = parsed.data;
|
|
728
|
+
const currency = l.currency?.trim() ? l.currency : "PEN";
|
|
729
|
+
const language = l.language?.trim() ? l.language : "es";
|
|
730
|
+
const slug = l.slug?.trim() ? l.slug : l.id;
|
|
731
|
+
return {
|
|
732
|
+
schemaVersion: 0,
|
|
733
|
+
generatedAt: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
734
|
+
store: {
|
|
735
|
+
id: l.id,
|
|
736
|
+
tenantId: l.tenantId ?? void 0,
|
|
737
|
+
name: l.name,
|
|
738
|
+
slug,
|
|
739
|
+
description: l.description ?? null,
|
|
740
|
+
logo: l.logo ?? null,
|
|
741
|
+
icon: l.icon ?? null,
|
|
742
|
+
visibility: l.visibility ?? void 0,
|
|
743
|
+
currency,
|
|
744
|
+
language,
|
|
745
|
+
themeConfig: l.themeConfig ?? void 0,
|
|
746
|
+
featuresEnabled: l.featuresEnabled ?? void 0,
|
|
747
|
+
checkoutSettings: l.checkoutSettings ?? void 0
|
|
748
|
+
},
|
|
749
|
+
cms: {
|
|
750
|
+
settings: {
|
|
751
|
+
branding: {
|
|
752
|
+
faviconUrl: l.favicon ?? null,
|
|
753
|
+
logoUrl: l.logo ?? null,
|
|
754
|
+
logoDarkUrl: null,
|
|
755
|
+
socialImageUrl: null
|
|
756
|
+
}
|
|
757
|
+
},
|
|
758
|
+
pages: []
|
|
759
|
+
}
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
var StorefrontStoreSchema = z.object({
|
|
763
|
+
id: z.string(),
|
|
764
|
+
tenantId: z.string().optional(),
|
|
765
|
+
sellerId: z.string().optional(),
|
|
766
|
+
plan: z.string().optional(),
|
|
767
|
+
storageLimitBytes: z.number().optional(),
|
|
768
|
+
monthlyTransferLimitBytes: z.number().optional(),
|
|
769
|
+
maxUploadSizeBytes: z.number().optional(),
|
|
770
|
+
maxStores: z.number().optional(),
|
|
771
|
+
maxMembers: z.number().optional(),
|
|
772
|
+
maxProducts: z.number().optional(),
|
|
773
|
+
maxCategories: z.number().optional(),
|
|
774
|
+
maxBrands: z.number().optional(),
|
|
775
|
+
maxAttributes: z.number().optional(),
|
|
776
|
+
maxCollections: z.number().optional(),
|
|
777
|
+
enableApi: z.boolean().optional(),
|
|
778
|
+
isActive: z.boolean().optional(),
|
|
779
|
+
name: z.string(),
|
|
780
|
+
description: z.string().nullable().optional(),
|
|
781
|
+
avatarUrl: z.string().nullable().optional(),
|
|
782
|
+
logo: z.string().nullable().optional(),
|
|
783
|
+
icon: z.string().nullable().optional(),
|
|
784
|
+
slug: z.string(),
|
|
785
|
+
domain: z.string().nullable().optional(),
|
|
786
|
+
domains: z.array(z.string()).optional(),
|
|
787
|
+
timeZone: z.string().nullable().optional(),
|
|
788
|
+
currency: z.string(),
|
|
789
|
+
language: z.string(),
|
|
790
|
+
visibility: z.string().optional(),
|
|
791
|
+
privateAccessHash: z.string().nullable().optional(),
|
|
792
|
+
privateAccessVersion: z.number().optional(),
|
|
793
|
+
themeConfig: StorefrontThemeConfigSchema.optional(),
|
|
794
|
+
featuresEnabled: StorefrontFeaturesEnabledSchema.optional(),
|
|
795
|
+
checkoutSettings: StorefrontCheckoutSettingsSchema.optional().nullable()
|
|
796
|
+
}).passthrough();
|
|
797
|
+
var StorefrontSettingsEnvelopeSchema = z.object({
|
|
798
|
+
schemaVersion: z.number(),
|
|
799
|
+
generatedAt: z.string(),
|
|
800
|
+
store: StorefrontStoreSchema,
|
|
801
|
+
cms: z.object({
|
|
802
|
+
settings: StorefrontCmsSettingsSchema,
|
|
803
|
+
pages: z.array(StorefrontCmsPageSchema)
|
|
804
|
+
})
|
|
805
|
+
}).passthrough();
|
|
806
|
+
var StorefrontSettingsSchema = z.preprocess(
|
|
807
|
+
normalizeStorefrontSettingsPayload,
|
|
808
|
+
StorefrontSettingsEnvelopeSchema
|
|
809
|
+
);
|
|
810
|
+
function storefrontStoreRecord(settings) {
|
|
811
|
+
return settings?.store ?? null;
|
|
812
|
+
}
|
|
813
|
+
function storefrontFaviconUrl(settings) {
|
|
814
|
+
const b = settings?.cms?.settings?.branding;
|
|
815
|
+
return b?.faviconUrl ?? settings?.store?.logo ?? settings?.store?.icon ?? null;
|
|
816
|
+
}
|
|
817
|
+
function storefrontOgImageUrl(settings) {
|
|
818
|
+
const b = settings?.cms?.settings?.branding;
|
|
819
|
+
return b?.socialImageUrl ?? settings?.store?.logo ?? null;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// src/core/services/store.service.ts
|
|
823
|
+
var StoreService = class _StoreService {
|
|
824
|
+
static instance;
|
|
825
|
+
constructor() {
|
|
826
|
+
}
|
|
827
|
+
static getInstance() {
|
|
828
|
+
if (!_StoreService.instance) {
|
|
829
|
+
_StoreService.instance = new _StoreService();
|
|
830
|
+
}
|
|
831
|
+
return _StoreService.instance;
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* Obtiene la configuración de la tienda por subdominio (GET /v1/settings).
|
|
835
|
+
* Usa el header X-Store-Domain. Si se pasa domain, se configura antes de la petición.
|
|
836
|
+
*/
|
|
837
|
+
async getStorefrontSettings(domain) {
|
|
838
|
+
if (domain) {
|
|
839
|
+
apiClient.setStoreDomain(domain);
|
|
840
|
+
}
|
|
841
|
+
const response = await apiClient.get(`/${STOREFRONT_API_PATH_PREFIX}/settings`);
|
|
842
|
+
return StorefrontSettingsSchema.parse(response);
|
|
843
|
+
}
|
|
844
|
+
};
|
|
845
|
+
var storeService = StoreService.getInstance();
|
|
846
|
+
var CartBuyerRequestSchema = z.object({
|
|
847
|
+
email: z.string().email(),
|
|
848
|
+
firstName: z.string().min(1),
|
|
849
|
+
lastName: z.string().min(1),
|
|
850
|
+
phone: z.string().min(1)
|
|
851
|
+
});
|
|
852
|
+
var CartCreateRequestSchema = z.object({
|
|
853
|
+
currencyCode: z.string(),
|
|
854
|
+
salesChannelId: z.string(),
|
|
855
|
+
email: z.string().email()
|
|
856
|
+
});
|
|
857
|
+
var CartAddressSchema = z.object({
|
|
858
|
+
name: z.string().min(1),
|
|
859
|
+
address1: z.string().min(1),
|
|
860
|
+
city: z.string().min(1),
|
|
861
|
+
countryCode: z.string().min(2),
|
|
862
|
+
company: z.string().nullable().optional(),
|
|
863
|
+
address2: z.string().nullable().optional(),
|
|
864
|
+
province: z.string().nullable().optional(),
|
|
865
|
+
postalCode: z.string().nullable().optional(),
|
|
866
|
+
district: z.string().nullable().optional(),
|
|
867
|
+
phone: z.string().nullable().optional(),
|
|
868
|
+
latitude: z.number().nullable().optional(),
|
|
869
|
+
longitude: z.number().nullable().optional(),
|
|
870
|
+
geo: z.object({
|
|
871
|
+
departmentCode: z.string().nullable().optional(),
|
|
872
|
+
provinceCode: z.string().nullable().optional(),
|
|
873
|
+
districtCode: z.string().nullable().optional()
|
|
874
|
+
}).nullable().optional()
|
|
875
|
+
});
|
|
876
|
+
var CartAddressesRequestSchema = z.object({
|
|
877
|
+
shippingAddress: CartAddressSchema,
|
|
878
|
+
billingAddress: CartAddressSchema
|
|
879
|
+
});
|
|
880
|
+
var CartItemModifierRequestSchema = z.object({
|
|
881
|
+
modifierGroupId: z.coerce.string().min(1),
|
|
882
|
+
optionIds: z.array(z.coerce.string().min(1)).optional().default([])
|
|
883
|
+
});
|
|
884
|
+
var CartItemRequestSchema = z.object({
|
|
885
|
+
variantId: z.coerce.string().min(1),
|
|
886
|
+
quantity: z.number().int().positive(),
|
|
887
|
+
modifiers: z.array(CartItemModifierRequestSchema).optional()
|
|
888
|
+
});
|
|
889
|
+
var CartCouponRequestSchema = z.object({
|
|
890
|
+
code: z.string().min(1)
|
|
891
|
+
});
|
|
892
|
+
z.object({
|
|
893
|
+
subtotal: z.number(),
|
|
894
|
+
discount: z.number(),
|
|
895
|
+
tax: z.number(),
|
|
896
|
+
warranty: z.number().optional().default(0),
|
|
897
|
+
total: z.number()
|
|
898
|
+
});
|
|
899
|
+
z.object({
|
|
900
|
+
name: z.string().nullable().optional(),
|
|
901
|
+
address1: z.string(),
|
|
902
|
+
city: z.string(),
|
|
903
|
+
countryCode: z.string(),
|
|
904
|
+
company: z.string().nullable().optional(),
|
|
905
|
+
address2: z.string().nullable().optional(),
|
|
906
|
+
province: z.string().nullable().optional(),
|
|
907
|
+
postalCode: z.string().nullable().optional(),
|
|
908
|
+
district: z.string().nullable().optional(),
|
|
909
|
+
phone: z.string().nullable().optional(),
|
|
910
|
+
latitude: z.number().nullable().optional(),
|
|
911
|
+
longitude: z.number().nullable().optional(),
|
|
912
|
+
geo: z.object({
|
|
913
|
+
departmentCode: z.string().nullable().optional(),
|
|
914
|
+
provinceCode: z.string().nullable().optional(),
|
|
915
|
+
districtCode: z.string().nullable().optional()
|
|
916
|
+
}).nullable().optional()
|
|
917
|
+
});
|
|
918
|
+
var CartResponseBundleItemSchema = z.object({
|
|
919
|
+
productId: z.coerce.string(),
|
|
920
|
+
variantId: z.coerce.string(),
|
|
921
|
+
productName: z.string(),
|
|
922
|
+
variantName: z.string().nullable().optional(),
|
|
923
|
+
sku: z.string().nullable().optional(),
|
|
924
|
+
brand: z.string().nullable().optional(),
|
|
925
|
+
imageUrl: z.string().nullable().optional(),
|
|
926
|
+
quantity: z.number().int()
|
|
927
|
+
});
|
|
928
|
+
var CartResponseItemSchema = z.object({
|
|
929
|
+
id: z.string(),
|
|
930
|
+
title: z.string(),
|
|
931
|
+
variantLabel: z.string().nullable().optional(),
|
|
932
|
+
thumbnail: z.string().nullable().optional(),
|
|
933
|
+
quantity: z.number().int(),
|
|
934
|
+
variantId: z.coerce.string(),
|
|
935
|
+
variantSku: z.string().nullable().optional(),
|
|
936
|
+
unitPrice: z.number(),
|
|
937
|
+
bundleItems: z.array(CartResponseBundleItemSchema).optional().default([])
|
|
938
|
+
});
|
|
939
|
+
z.object({
|
|
940
|
+
id: z.string(),
|
|
941
|
+
name: z.string(),
|
|
942
|
+
description: z.string().nullable().optional(),
|
|
943
|
+
total: z.number(),
|
|
944
|
+
estimatedDays: z.number().int().nullable().optional(),
|
|
945
|
+
pickupPointId: z.string().nullable().optional(),
|
|
946
|
+
scheduledDate: z.string().nullable().optional(),
|
|
947
|
+
scheduledTime: z.string().nullable().optional()
|
|
948
|
+
});
|
|
949
|
+
var CartResponseSchema = z.object({
|
|
950
|
+
id: z.string(),
|
|
951
|
+
regionId: z.string().nullable().optional(),
|
|
952
|
+
salesChannelId: z.string().nullable().optional(),
|
|
953
|
+
email: z.string().email().nullable().optional(),
|
|
954
|
+
phone: z.string().nullable().optional(),
|
|
955
|
+
firstName: z.string().nullable().optional(),
|
|
956
|
+
lastName: z.string().nullable().optional(),
|
|
957
|
+
currencyCode: z.string(),
|
|
958
|
+
completedAt: z.string().nullable().optional(),
|
|
959
|
+
shippingAddress: z.unknown().nullable().optional(),
|
|
960
|
+
billingAddress: z.unknown().nullable().optional(),
|
|
961
|
+
metadata: z.record(z.string(), z.unknown()).optional().default({}),
|
|
962
|
+
promotionCodes: z.array(z.string()).optional().default([]),
|
|
963
|
+
items: z.array(CartResponseItemSchema).optional().default([]),
|
|
964
|
+
shippingMethods: z.array(z.unknown()).optional().default([]),
|
|
965
|
+
totals: z.object({
|
|
966
|
+
discountTotal: z.number(),
|
|
967
|
+
shippingTotal: z.number(),
|
|
968
|
+
subtotal: z.number(),
|
|
969
|
+
taxTotal: z.number(),
|
|
970
|
+
total: z.number(),
|
|
971
|
+
warrantyTotal: z.number()
|
|
972
|
+
})
|
|
973
|
+
});
|
|
974
|
+
var CartCheckoutRequestSchema = z.object({
|
|
975
|
+
paymentMethodCode: z.string().min(1),
|
|
976
|
+
externalRef: z.string().min(1),
|
|
977
|
+
receiptUrl: z.string().min(1).optional()
|
|
978
|
+
});
|
|
979
|
+
var CartCheckoutPaymentActionSchema = z.object({
|
|
980
|
+
publicConfiguration: z.object({
|
|
981
|
+
publishableKey: z.string().nullable().optional(),
|
|
982
|
+
checkoutMode: z.string().nullable().optional(),
|
|
983
|
+
phoneNumber: z.string().nullable().optional(),
|
|
984
|
+
accountHolder: z.string().nullable().optional(),
|
|
985
|
+
qrImageUrl: z.string().nullable().optional()
|
|
986
|
+
}).passthrough().nullable().optional(),
|
|
987
|
+
url: z.string().nullable().optional(),
|
|
988
|
+
html: z.string().nullable().optional(),
|
|
989
|
+
clientSecret: z.string().nullable().optional(),
|
|
990
|
+
qrCode: z.string().nullable().optional(),
|
|
991
|
+
expiresAt: z.string().nullable().optional()
|
|
992
|
+
}).passthrough();
|
|
993
|
+
var CartCheckoutPaymentSchema = z.object({
|
|
994
|
+
transactionId: z.string(),
|
|
995
|
+
paymentMethodCode: z.string(),
|
|
996
|
+
providerId: z.string().nullable().optional(),
|
|
997
|
+
status: z.string(),
|
|
998
|
+
amount: z.number(),
|
|
999
|
+
reference: z.string(),
|
|
1000
|
+
actionType: z.string(),
|
|
1001
|
+
receiptUrl: z.string().nullable().optional(),
|
|
1002
|
+
action: CartCheckoutPaymentActionSchema.nullable().optional()
|
|
1003
|
+
}).passthrough();
|
|
1004
|
+
var CartCheckoutResponseSchema = z.object({
|
|
1005
|
+
publicKey: z.string().optional(),
|
|
1006
|
+
publishableKey: z.string().optional(),
|
|
1007
|
+
stripePublicKey: z.string().optional(),
|
|
1008
|
+
clientSecret: z.string().optional(),
|
|
1009
|
+
intentClientSecret: z.string().optional(),
|
|
1010
|
+
orderId: z.coerce.string().optional(),
|
|
1011
|
+
orderGroup: z.string().optional(),
|
|
1012
|
+
orderIds: z.array(z.coerce.string()).optional(),
|
|
1013
|
+
/** Payload de pago (embedded, redirect, etc.) */
|
|
1014
|
+
payment: CartCheckoutPaymentSchema.optional(),
|
|
1015
|
+
cart: z.unknown().optional()
|
|
1016
|
+
}).passthrough();
|
|
1017
|
+
var CartPaymentReceiptResponseSchema = z.object({
|
|
1018
|
+
id: z.string(),
|
|
1019
|
+
url: z.string()
|
|
1020
|
+
});
|
|
1021
|
+
var CartPaymentMethodSchema = z.object({
|
|
1022
|
+
code: z.string(),
|
|
1023
|
+
name: z.string(),
|
|
1024
|
+
description: z.string().nullable().optional(),
|
|
1025
|
+
kind: z.string(),
|
|
1026
|
+
isActive: z.boolean(),
|
|
1027
|
+
isDefault: z.boolean(),
|
|
1028
|
+
isManual: z.boolean(),
|
|
1029
|
+
sortOrder: z.number(),
|
|
1030
|
+
phoneNumber: z.string().nullable().optional(),
|
|
1031
|
+
accountHolder: z.string().nullable().optional(),
|
|
1032
|
+
qrImageUrl: z.string().nullable().optional()
|
|
1033
|
+
});
|
|
1034
|
+
var CartPaymentMethodsResponseSchema = z.object({
|
|
1035
|
+
methods: z.array(CartPaymentMethodSchema)
|
|
1036
|
+
});
|
|
1037
|
+
var CartCheckoutReadResponseSchema = z.object({
|
|
1038
|
+
cart: CartResponseSchema,
|
|
1039
|
+
paymentMethods: CartPaymentMethodsResponseSchema
|
|
1040
|
+
});
|
|
1041
|
+
var ShippingRateSchema = z.object({
|
|
1042
|
+
shippingMethodId: z.string(),
|
|
1043
|
+
name: z.string(),
|
|
1044
|
+
displayName: z.string().optional(),
|
|
1045
|
+
type: z.string().optional(),
|
|
1046
|
+
price: z.number(),
|
|
1047
|
+
currency: z.string().optional(),
|
|
1048
|
+
sortOrder: z.number().optional(),
|
|
1049
|
+
rateId: z.string(),
|
|
1050
|
+
description: z.string().nullable().optional(),
|
|
1051
|
+
deliveryLocationId: z.string().nullable().optional(),
|
|
1052
|
+
deliveryLocationName: z.string().nullable().optional(),
|
|
1053
|
+
estimatedDeliveryDays: z.number().nullable().optional(),
|
|
1054
|
+
serviceCode: z.string().nullable().optional(),
|
|
1055
|
+
metadata: z.record(z.string(), z.unknown()).optional()
|
|
1056
|
+
}).passthrough();
|
|
1057
|
+
var ShippingOptionGroupSchema = z.object({
|
|
1058
|
+
sellerId: z.string(),
|
|
1059
|
+
shippingProfileId: z.string().nullable().optional(),
|
|
1060
|
+
orderAmount: z.number().optional(),
|
|
1061
|
+
totalWeight: z.number().optional(),
|
|
1062
|
+
itemIds: z.array(z.string()).optional(),
|
|
1063
|
+
rates: z.array(ShippingRateSchema)
|
|
1064
|
+
}).passthrough();
|
|
1065
|
+
var ShippingOptionsResponseSchema = z.object({
|
|
1066
|
+
groups: z.array(ShippingOptionGroupSchema)
|
|
1067
|
+
});
|
|
1068
|
+
var CartShippingMethodPutRequestSchema = z.object({
|
|
1069
|
+
rateId: z.string().min(1),
|
|
1070
|
+
shippingMethodId: z.string().min(1),
|
|
1071
|
+
serviceCode: z.string().nullable().optional(),
|
|
1072
|
+
sellerId: z.string().nullable().optional(),
|
|
1073
|
+
shippingProfileId: z.string().nullable().optional(),
|
|
1074
|
+
locationId: z.string().nullable().optional(),
|
|
1075
|
+
pickupPointId: z.string().nullable().optional(),
|
|
1076
|
+
scheduledDate: z.string().nullable().optional(),
|
|
1077
|
+
scheduledTime: z.string().nullable().optional()
|
|
1078
|
+
});
|
|
1079
|
+
|
|
1080
|
+
// src/core/services/cart.service.ts
|
|
1081
|
+
var CartService = class _CartService {
|
|
1082
|
+
static instance;
|
|
1083
|
+
constructor() {
|
|
1084
|
+
}
|
|
1085
|
+
static getInstance() {
|
|
1086
|
+
if (!_CartService.instance) {
|
|
1087
|
+
_CartService.instance = new _CartService();
|
|
1088
|
+
}
|
|
1089
|
+
return _CartService.instance;
|
|
1090
|
+
}
|
|
1091
|
+
/**
|
|
1092
|
+
* Obtiene el carrito actual (GET /v1/carts).
|
|
1093
|
+
*/
|
|
1094
|
+
async getCart() {
|
|
1095
|
+
const response = await apiClient.get(`/${STOREFRONT_API_PATH_PREFIX}/carts`);
|
|
1096
|
+
return CartResponseSchema.parse(response);
|
|
1097
|
+
}
|
|
1098
|
+
/**
|
|
1099
|
+
* Crea un carrito nuevo (POST /v1/carts).
|
|
1100
|
+
*/
|
|
1101
|
+
async createCart(data) {
|
|
1102
|
+
const payload = CartCreateRequestSchema.parse(data);
|
|
1103
|
+
const response = await apiClient.post(`/${STOREFRONT_API_PATH_PREFIX}/carts`, payload);
|
|
1104
|
+
return CartResponseSchema.parse(response);
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* Actualiza los datos del comprador del carrito actual (PATCH /v1/carts/buyer).
|
|
1108
|
+
* El carrito se resuelve en backend vía contexto (token/guest), por eso no requiere cartId.
|
|
1109
|
+
*/
|
|
1110
|
+
async updateBuyer(data) {
|
|
1111
|
+
const payload = CartBuyerRequestSchema.parse(data);
|
|
1112
|
+
const response = await apiClient.patch(`/${STOREFRONT_API_PATH_PREFIX}/carts/buyer`, payload);
|
|
1113
|
+
return CartResponseSchema.parse(response);
|
|
1114
|
+
}
|
|
1115
|
+
/**
|
|
1116
|
+
* Actualiza direcciones de envío y facturación del carrito (PATCH /v1/carts/addresses).
|
|
1117
|
+
*/
|
|
1118
|
+
async updateAddresses(data) {
|
|
1119
|
+
const payload = CartAddressesRequestSchema.parse(data);
|
|
1120
|
+
const response = await apiClient.patch(`/${STOREFRONT_API_PATH_PREFIX}/carts/addresses`, payload);
|
|
1121
|
+
return CartResponseSchema.parse(response);
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* Inicializa/obtiene detalles del método de pago para el checkout (POST /v1/carts/checkout).
|
|
1125
|
+
* Usado para providers como Stripe (public key, client secret, etc).
|
|
1126
|
+
*/
|
|
1127
|
+
async checkout(data) {
|
|
1128
|
+
const payload = CartCheckoutRequestSchema.parse(data);
|
|
1129
|
+
const response = await apiClient.post(`/${STOREFRONT_API_PATH_PREFIX}/carts/checkout`, payload);
|
|
1130
|
+
return CartCheckoutResponseSchema.parse(response);
|
|
1131
|
+
}
|
|
1132
|
+
};
|
|
1133
|
+
var cartService = CartService.getInstance();
|
|
1134
|
+
var defaultOptions = {
|
|
1135
|
+
queries: {
|
|
1136
|
+
staleTime: 60 * 1e3
|
|
1137
|
+
}
|
|
1138
|
+
};
|
|
1139
|
+
function QueryProvider({ children, dehydratedState }) {
|
|
1140
|
+
const queryClientRef = useRef(null);
|
|
1141
|
+
const hydratedRef = useRef(false);
|
|
1142
|
+
if (queryClientRef.current === null) {
|
|
1143
|
+
queryClientRef.current = new QueryClient({ defaultOptions });
|
|
1144
|
+
}
|
|
1145
|
+
const queryClient = queryClientRef.current;
|
|
1146
|
+
useEffect(() => {
|
|
1147
|
+
if (dehydratedState && !hydratedRef.current) {
|
|
1148
|
+
hydrate(queryClient, dehydratedState);
|
|
1149
|
+
hydratedRef.current = true;
|
|
1150
|
+
}
|
|
1151
|
+
}, [queryClient, dehydratedState]);
|
|
1152
|
+
return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children });
|
|
1153
|
+
}
|
|
1154
|
+
var StorefrontAuthContext = createContext(null);
|
|
1155
|
+
function StorefrontAuthProvider({
|
|
1156
|
+
authClient,
|
|
1157
|
+
children
|
|
1158
|
+
}) {
|
|
1159
|
+
return /* @__PURE__ */ jsx(StorefrontAuthContext.Provider, { value: authClient, children });
|
|
1160
|
+
}
|
|
1161
|
+
function useStorefrontAuthClient() {
|
|
1162
|
+
const client = useContext(StorefrontAuthContext);
|
|
1163
|
+
if (!client) {
|
|
1164
|
+
throw new Error(
|
|
1165
|
+
"useStorefrontAuthClient debe usarse dentro de StorefrontAuthProvider (o EcomiqProvider con authClient)."
|
|
1166
|
+
);
|
|
1167
|
+
}
|
|
1168
|
+
return client;
|
|
1169
|
+
}
|
|
1170
|
+
function storefrontSessionEndsSoon(expiresAt, skewMs = 12e4) {
|
|
1171
|
+
if (!expiresAt) return false;
|
|
1172
|
+
return Date.now() + skewMs >= expiresAt.getTime();
|
|
1173
|
+
}
|
|
1174
|
+
var storefrontAccessTokenNeedsRefresh = storefrontSessionEndsSoon;
|
|
1175
|
+
function parseStorefrontSessionExpires(at) {
|
|
1176
|
+
if (!at) return void 0;
|
|
1177
|
+
if (at instanceof Date) return Number.isNaN(at.getTime()) ? void 0 : at;
|
|
1178
|
+
if (typeof at === "string") {
|
|
1179
|
+
const d = new Date(at);
|
|
1180
|
+
return Number.isNaN(d.getTime()) ? void 0 : d;
|
|
1181
|
+
}
|
|
1182
|
+
return void 0;
|
|
1183
|
+
}
|
|
1184
|
+
function mapSessionUser(raw) {
|
|
1185
|
+
if (!raw || typeof raw !== "object") return null;
|
|
1186
|
+
const u = raw;
|
|
1187
|
+
const explicitFirst = typeof u.firstName === "string" ? u.firstName : typeof u.given_name === "string" ? u.given_name : "";
|
|
1188
|
+
const explicitLast = typeof u.lastName === "string" ? u.lastName : typeof u.family_name === "string" ? u.family_name : "";
|
|
1189
|
+
if (explicitFirst || explicitLast) {
|
|
1190
|
+
return {
|
|
1191
|
+
id: String(u.id ?? ""),
|
|
1192
|
+
email: String(u.email ?? ""),
|
|
1193
|
+
firstName: explicitFirst,
|
|
1194
|
+
lastName: explicitLast,
|
|
1195
|
+
name: typeof u.name === "string" ? u.name : void 0,
|
|
1196
|
+
phone: typeof u.phone === "string" ? u.phone : void 0
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
const emailLocal = String(u.email ?? "").split("@")[0] ?? "";
|
|
1200
|
+
const full = typeof u.name === "string" ? u.name.trim() : emailLocal.trim();
|
|
1201
|
+
const parts = full ? full.split(/\s+/) : [];
|
|
1202
|
+
return {
|
|
1203
|
+
id: String(u.id ?? ""),
|
|
1204
|
+
email: String(u.email ?? ""),
|
|
1205
|
+
firstName: parts[0] ?? "",
|
|
1206
|
+
lastName: parts.slice(1).join(" "),
|
|
1207
|
+
name: typeof u.name === "string" ? u.name : void 0,
|
|
1208
|
+
phone: typeof u.phone === "string" ? u.phone : void 0
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1211
|
+
function useStorefrontSession() {
|
|
1212
|
+
const authClient = useStorefrontAuthClient();
|
|
1213
|
+
const session = authClient.useSession();
|
|
1214
|
+
const user = mapSessionUser(session.data?.user);
|
|
1215
|
+
const storefrontSession = session.data?.session;
|
|
1216
|
+
const sessionExpiresAt = parseStorefrontSessionExpires(storefrontSession?.expiresAt);
|
|
1217
|
+
return {
|
|
1218
|
+
session,
|
|
1219
|
+
user,
|
|
1220
|
+
sessionExpiresAt,
|
|
1221
|
+
isAuthenticated: Boolean(session.data?.user),
|
|
1222
|
+
isPending: session.isPending,
|
|
1223
|
+
error: session.error,
|
|
1224
|
+
refetch: session.refetch,
|
|
1225
|
+
signOut: () => authClient.signOut()
|
|
1226
|
+
};
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
// src/react/hooks/use-user.ts
|
|
1230
|
+
function useUser() {
|
|
1231
|
+
return {};
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
// src/react/hooks/use-config.ts
|
|
1235
|
+
function useConfig() {
|
|
1236
|
+
return {};
|
|
1237
|
+
}
|
|
1238
|
+
var useProducts = (storeId) => {
|
|
1239
|
+
if (storeId) {
|
|
1240
|
+
apiClient.setStoreId(storeId);
|
|
1241
|
+
}
|
|
1242
|
+
const useProductsList = (filters) => {
|
|
1243
|
+
return useQuery({
|
|
1244
|
+
queryKey: ["products", filters],
|
|
1245
|
+
queryFn: () => productService.getProducts(filters),
|
|
1246
|
+
enabled: !!storeId
|
|
1247
|
+
});
|
|
1248
|
+
};
|
|
1249
|
+
const useInfiniteProducts = (filters) => {
|
|
1250
|
+
return useInfiniteQuery({
|
|
1251
|
+
queryKey: ["products", "infinite", filters],
|
|
1252
|
+
queryFn: ({ pageParam = 1 }) => productService.getProducts({ ...filters, page: pageParam }),
|
|
1253
|
+
getNextPageParam: (lastPage) => lastPage.meta.hasNextPage ? lastPage.meta.page + 1 : void 0,
|
|
1254
|
+
initialPageParam: 1,
|
|
1255
|
+
enabled: !!storeId
|
|
1256
|
+
});
|
|
1257
|
+
};
|
|
1258
|
+
const useProduct = (id) => {
|
|
1259
|
+
return useQuery({
|
|
1260
|
+
queryKey: ["product", id],
|
|
1261
|
+
queryFn: () => productService.getProduct(id),
|
|
1262
|
+
enabled: !!id && !!storeId
|
|
1263
|
+
});
|
|
1264
|
+
};
|
|
1265
|
+
const useProductBySlug = (slug) => {
|
|
1266
|
+
return useQuery({
|
|
1267
|
+
queryKey: ["product", "slug", slug],
|
|
1268
|
+
queryFn: () => productService.getProductBySlug(slug),
|
|
1269
|
+
enabled: !!slug && !!storeId
|
|
1270
|
+
});
|
|
1271
|
+
};
|
|
1272
|
+
const useSearchProducts = (query, filters) => {
|
|
1273
|
+
return useQuery({
|
|
1274
|
+
queryKey: ["products", "search", query, filters],
|
|
1275
|
+
queryFn: () => productService.searchProducts(query, filters),
|
|
1276
|
+
enabled: !!query && !!storeId
|
|
1277
|
+
});
|
|
1278
|
+
};
|
|
1279
|
+
const useProductsByCategory = (category, filters) => {
|
|
1280
|
+
return useQuery({
|
|
1281
|
+
queryKey: ["products", "category", category, filters],
|
|
1282
|
+
queryFn: () => productService.getProductsByCategory(category, filters),
|
|
1283
|
+
enabled: !!category && !!storeId
|
|
1284
|
+
});
|
|
1285
|
+
};
|
|
1286
|
+
const useProductsOnSale = (filters) => {
|
|
1287
|
+
return useQuery({
|
|
1288
|
+
queryKey: ["products", "sale", filters],
|
|
1289
|
+
queryFn: () => productService.getProductsOnSale(filters),
|
|
1290
|
+
enabled: !!storeId
|
|
1291
|
+
});
|
|
1292
|
+
};
|
|
1293
|
+
const useProductsInStock = (filters) => {
|
|
1294
|
+
return useQuery({
|
|
1295
|
+
queryKey: ["products", "stock", filters],
|
|
1296
|
+
queryFn: () => productService.getProductsInStock(filters),
|
|
1297
|
+
enabled: !!storeId
|
|
1298
|
+
});
|
|
1299
|
+
};
|
|
1300
|
+
const useRefreshProducts = () => {
|
|
1301
|
+
const queryClient = useQueryClient();
|
|
1302
|
+
return useMutation({
|
|
1303
|
+
mutationFn: () => productService.getProducts(),
|
|
1304
|
+
onSuccess: (data) => {
|
|
1305
|
+
queryClient.setQueryData(["products"], data);
|
|
1306
|
+
}
|
|
1307
|
+
});
|
|
1308
|
+
};
|
|
1309
|
+
const useStorefrontProductsList = (params) => {
|
|
1310
|
+
return useQuery({
|
|
1311
|
+
queryKey: ["storefront", "products", params],
|
|
1312
|
+
queryFn: () => productService.getStorefrontProducts(params),
|
|
1313
|
+
enabled: !!storeId
|
|
1314
|
+
});
|
|
1315
|
+
};
|
|
1316
|
+
const useStorefrontInfiniteProducts = (params) => {
|
|
1317
|
+
return useInfiniteQuery({
|
|
1318
|
+
queryKey: ["storefront", "products", "infinite", params],
|
|
1319
|
+
queryFn: ({ pageParam = 1 }) => productService.getStorefrontProducts({ ...params, page: pageParam }),
|
|
1320
|
+
getNextPageParam: (lastPage) => lastPage.pageIndex < lastPage.totalPages ? lastPage.pageIndex + 1 : void 0,
|
|
1321
|
+
initialPageParam: 1,
|
|
1322
|
+
enabled: !!storeId
|
|
1323
|
+
});
|
|
1324
|
+
};
|
|
1325
|
+
const useRefreshStorefrontProducts = () => {
|
|
1326
|
+
const queryClient = useQueryClient();
|
|
1327
|
+
return useMutation({
|
|
1328
|
+
mutationFn: (params) => productService.getStorefrontProducts(params),
|
|
1329
|
+
onSuccess: () => {
|
|
1330
|
+
queryClient.invalidateQueries({ queryKey: ["storefront", "products"] });
|
|
1331
|
+
}
|
|
1332
|
+
});
|
|
1333
|
+
};
|
|
1334
|
+
return {
|
|
1335
|
+
useProductsList,
|
|
1336
|
+
useInfiniteProducts,
|
|
1337
|
+
useProduct,
|
|
1338
|
+
useProductBySlug,
|
|
1339
|
+
useSearchProducts,
|
|
1340
|
+
useProductsByCategory,
|
|
1341
|
+
useProductsOnSale,
|
|
1342
|
+
useProductsInStock,
|
|
1343
|
+
useRefreshProducts,
|
|
1344
|
+
useStorefrontProductsList,
|
|
1345
|
+
useStorefrontInfiniteProducts,
|
|
1346
|
+
useRefreshStorefrontProducts
|
|
1347
|
+
};
|
|
1348
|
+
};
|
|
1349
|
+
var useCollections = (storeId) => {
|
|
1350
|
+
if (storeId) {
|
|
1351
|
+
apiClient.setStoreId(storeId);
|
|
1352
|
+
}
|
|
1353
|
+
const useStorefrontCollectionsList = () => {
|
|
1354
|
+
return useQuery({
|
|
1355
|
+
queryKey: ["storefront", "collections"],
|
|
1356
|
+
queryFn: () => collectionService.getStorefrontCollections(),
|
|
1357
|
+
enabled: !!storeId
|
|
1358
|
+
});
|
|
1359
|
+
};
|
|
1360
|
+
const useStorefrontCollectionBySlug = (slug) => {
|
|
1361
|
+
return useQuery({
|
|
1362
|
+
queryKey: ["storefront", "collection", "slug", slug],
|
|
1363
|
+
queryFn: () => collectionService.getStorefrontCollectionBySlug(slug),
|
|
1364
|
+
enabled: !!slug && !!storeId
|
|
1365
|
+
});
|
|
1366
|
+
};
|
|
1367
|
+
const useRefreshStorefrontCollections = () => {
|
|
1368
|
+
const queryClient = useQueryClient();
|
|
1369
|
+
return useMutation({
|
|
1370
|
+
mutationFn: () => collectionService.getStorefrontCollections(),
|
|
1371
|
+
onSuccess: () => {
|
|
1372
|
+
queryClient.invalidateQueries({ queryKey: ["storefront", "collections"] });
|
|
1373
|
+
}
|
|
1374
|
+
});
|
|
1375
|
+
};
|
|
1376
|
+
return {
|
|
1377
|
+
useStorefrontCollectionsList,
|
|
1378
|
+
useStorefrontCollectionBySlug,
|
|
1379
|
+
useRefreshStorefrontCollections
|
|
1380
|
+
};
|
|
1381
|
+
};
|
|
1382
|
+
var usePages = (storeId) => {
|
|
1383
|
+
if (storeId) {
|
|
1384
|
+
apiClient.setStoreId(storeId);
|
|
1385
|
+
}
|
|
1386
|
+
const usePagesList = () => {
|
|
1387
|
+
return useQuery({
|
|
1388
|
+
queryKey: ["storefront", "pages"],
|
|
1389
|
+
queryFn: () => pageService.getPages(),
|
|
1390
|
+
enabled: !!storeId
|
|
1391
|
+
});
|
|
1392
|
+
};
|
|
1393
|
+
const usePageBySlug = (slug) => {
|
|
1394
|
+
return useQuery({
|
|
1395
|
+
queryKey: ["storefront", "page", "slug", slug],
|
|
1396
|
+
queryFn: () => pageService.getPageBySlug(slug),
|
|
1397
|
+
enabled: !!slug && !!storeId
|
|
1398
|
+
});
|
|
1399
|
+
};
|
|
1400
|
+
const useRefreshPages = () => {
|
|
1401
|
+
const queryClient = useQueryClient();
|
|
1402
|
+
return useMutation({
|
|
1403
|
+
mutationFn: () => pageService.getPages(),
|
|
1404
|
+
onSuccess: () => {
|
|
1405
|
+
queryClient.invalidateQueries({ queryKey: ["storefront", "pages"] });
|
|
1406
|
+
}
|
|
1407
|
+
});
|
|
1408
|
+
};
|
|
1409
|
+
return {
|
|
1410
|
+
usePagesList,
|
|
1411
|
+
usePageBySlug,
|
|
1412
|
+
useRefreshPages
|
|
1413
|
+
};
|
|
1414
|
+
};
|
|
1415
|
+
var useCartAddresses = () => {
|
|
1416
|
+
return useMutation({
|
|
1417
|
+
mutationFn: (data) => cartService.updateAddresses(data)
|
|
1418
|
+
});
|
|
1419
|
+
};
|
|
1420
|
+
var useCartGet = () => {
|
|
1421
|
+
return useQuery({
|
|
1422
|
+
queryKey: ["cart"],
|
|
1423
|
+
queryFn: () => cartService.getCart()
|
|
1424
|
+
});
|
|
1425
|
+
};
|
|
1426
|
+
var useCartCreate = () => {
|
|
1427
|
+
return useMutation({
|
|
1428
|
+
mutationFn: (data) => cartService.createCart(data)
|
|
1429
|
+
});
|
|
1430
|
+
};
|
|
1431
|
+
function useStorefrontGeoInei(storeId, form) {
|
|
1432
|
+
const [departments, setDepartments] = useState([]);
|
|
1433
|
+
const [provinces, setProvinces] = useState([]);
|
|
1434
|
+
const [districts, setDistricts] = useState([]);
|
|
1435
|
+
const [loadingDepartments, setLoadingDepartments] = useState(false);
|
|
1436
|
+
const [loadingProvinces, setLoadingProvinces] = useState(false);
|
|
1437
|
+
const [loadingDistricts, setLoadingDistricts] = useState(false);
|
|
1438
|
+
const prevDepartmentCode = useRef(void 0);
|
|
1439
|
+
const prevProvinceCode = useRef(void 0);
|
|
1440
|
+
const countryCode = (form.watch("countryCode") || "PE").toUpperCase();
|
|
1441
|
+
const departmentCode = form.watch("departmentCode");
|
|
1442
|
+
const provinceCode = form.watch("provinceCode");
|
|
1443
|
+
const districtCode = form.watch("districtCode");
|
|
1444
|
+
const storeRequestHeaders = useMemo(() => {
|
|
1445
|
+
const id = storeId.trim();
|
|
1446
|
+
if (!id) return null;
|
|
1447
|
+
return { "X-Store-Id": id };
|
|
1448
|
+
}, [storeId]);
|
|
1449
|
+
const selectedDepartment = useMemo(
|
|
1450
|
+
() => departments.find((d) => d.code === departmentCode),
|
|
1451
|
+
[departments, departmentCode]
|
|
1452
|
+
);
|
|
1453
|
+
const selectedProvince = useMemo(
|
|
1454
|
+
() => provinces.find((p) => p.code === provinceCode),
|
|
1455
|
+
[provinces, provinceCode]
|
|
1456
|
+
);
|
|
1457
|
+
const selectedDistrict = useMemo(
|
|
1458
|
+
() => districts.find((d) => d.code === districtCode),
|
|
1459
|
+
[districts, districtCode]
|
|
1460
|
+
);
|
|
1461
|
+
useEffect(() => {
|
|
1462
|
+
let active = true;
|
|
1463
|
+
if (!storeRequestHeaders) {
|
|
1464
|
+
setDepartments([]);
|
|
1465
|
+
setLoadingDepartments(false);
|
|
1466
|
+
return () => {
|
|
1467
|
+
active = false;
|
|
1468
|
+
};
|
|
1469
|
+
}
|
|
1470
|
+
setLoadingDepartments(true);
|
|
1471
|
+
loadStorefrontGeoDepartments(storeRequestHeaders).then((items) => {
|
|
1472
|
+
if (!active) return;
|
|
1473
|
+
setDepartments(items);
|
|
1474
|
+
}).finally(() => {
|
|
1475
|
+
if (!active) return;
|
|
1476
|
+
setLoadingDepartments(false);
|
|
1477
|
+
});
|
|
1478
|
+
return () => {
|
|
1479
|
+
active = false;
|
|
1480
|
+
};
|
|
1481
|
+
}, [storeRequestHeaders]);
|
|
1482
|
+
useEffect(() => {
|
|
1483
|
+
const prev = prevDepartmentCode.current;
|
|
1484
|
+
const dept = departmentCode;
|
|
1485
|
+
const departmentChanged = prev !== void 0 && prev !== dept;
|
|
1486
|
+
prevDepartmentCode.current = dept;
|
|
1487
|
+
if (!dept) {
|
|
1488
|
+
setProvinces([]);
|
|
1489
|
+
setDistricts([]);
|
|
1490
|
+
prevProvinceCode.current = "";
|
|
1491
|
+
prevDepartmentCode.current = "";
|
|
1492
|
+
return;
|
|
1493
|
+
}
|
|
1494
|
+
if (!storeRequestHeaders) {
|
|
1495
|
+
setProvinces([]);
|
|
1496
|
+
return;
|
|
1497
|
+
}
|
|
1498
|
+
if (departmentChanged) {
|
|
1499
|
+
form.setValue("provinceCode", "", { shouldValidate: true });
|
|
1500
|
+
form.setValue("provinceName", "", { shouldValidate: true });
|
|
1501
|
+
form.setValue("districtCode", "", { shouldValidate: true });
|
|
1502
|
+
form.setValue("districtName", "", { shouldValidate: true });
|
|
1503
|
+
setDistricts([]);
|
|
1504
|
+
prevProvinceCode.current = "";
|
|
1505
|
+
}
|
|
1506
|
+
if (selectedDepartment?.name) {
|
|
1507
|
+
form.setValue("departmentName", selectedDepartment.name, {
|
|
1508
|
+
shouldValidate: true
|
|
1509
|
+
});
|
|
1510
|
+
}
|
|
1511
|
+
let active = true;
|
|
1512
|
+
setLoadingProvinces(true);
|
|
1513
|
+
fetchStorefrontGeoProvinces(storeRequestHeaders, countryCode, dept).then((items) => {
|
|
1514
|
+
if (!active) return;
|
|
1515
|
+
setProvinces(items);
|
|
1516
|
+
}).catch(() => {
|
|
1517
|
+
if (!active) return;
|
|
1518
|
+
setProvinces([]);
|
|
1519
|
+
}).finally(() => {
|
|
1520
|
+
if (!active) return;
|
|
1521
|
+
setLoadingProvinces(false);
|
|
1522
|
+
});
|
|
1523
|
+
return () => {
|
|
1524
|
+
active = false;
|
|
1525
|
+
};
|
|
1526
|
+
}, [departmentCode, countryCode, selectedDepartment?.name, form, storeRequestHeaders]);
|
|
1527
|
+
useEffect(() => {
|
|
1528
|
+
const prev = prevProvinceCode.current;
|
|
1529
|
+
const prov = provinceCode;
|
|
1530
|
+
const provinceChanged = prev !== void 0 && prev !== prov;
|
|
1531
|
+
prevProvinceCode.current = prov;
|
|
1532
|
+
if (!prov) {
|
|
1533
|
+
setDistricts([]);
|
|
1534
|
+
prevProvinceCode.current = "";
|
|
1535
|
+
return;
|
|
1536
|
+
}
|
|
1537
|
+
if (!storeRequestHeaders) {
|
|
1538
|
+
setDistricts([]);
|
|
1539
|
+
return;
|
|
1540
|
+
}
|
|
1541
|
+
if (provinceChanged) {
|
|
1542
|
+
form.setValue("districtCode", "", { shouldValidate: true });
|
|
1543
|
+
form.setValue("districtName", "", { shouldValidate: true });
|
|
1544
|
+
}
|
|
1545
|
+
if (selectedProvince?.name) {
|
|
1546
|
+
form.setValue("provinceName", selectedProvince.name, {
|
|
1547
|
+
shouldValidate: true
|
|
1548
|
+
});
|
|
1549
|
+
}
|
|
1550
|
+
let active = true;
|
|
1551
|
+
setLoadingDistricts(true);
|
|
1552
|
+
fetchStorefrontGeoDistricts(storeRequestHeaders, countryCode, prov).then((items) => {
|
|
1553
|
+
if (!active) return;
|
|
1554
|
+
setDistricts(items);
|
|
1555
|
+
}).catch(() => {
|
|
1556
|
+
if (!active) return;
|
|
1557
|
+
setDistricts([]);
|
|
1558
|
+
}).finally(() => {
|
|
1559
|
+
if (!active) return;
|
|
1560
|
+
setLoadingDistricts(false);
|
|
1561
|
+
});
|
|
1562
|
+
return () => {
|
|
1563
|
+
active = false;
|
|
1564
|
+
};
|
|
1565
|
+
}, [provinceCode, countryCode, selectedProvince?.name, form, storeRequestHeaders]);
|
|
1566
|
+
useEffect(() => {
|
|
1567
|
+
if (selectedDistrict?.name) {
|
|
1568
|
+
form.setValue("districtName", selectedDistrict.name, {
|
|
1569
|
+
shouldValidate: true
|
|
1570
|
+
});
|
|
1571
|
+
}
|
|
1572
|
+
}, [selectedDistrict?.name, form]);
|
|
1573
|
+
return {
|
|
1574
|
+
departments,
|
|
1575
|
+
provinces,
|
|
1576
|
+
districts,
|
|
1577
|
+
loadingDepartments,
|
|
1578
|
+
loadingProvinces,
|
|
1579
|
+
loadingDistricts,
|
|
1580
|
+
departmentCode,
|
|
1581
|
+
provinceCode,
|
|
1582
|
+
districtCode,
|
|
1583
|
+
selectedDepartment,
|
|
1584
|
+
selectedProvince,
|
|
1585
|
+
selectedDistrict,
|
|
1586
|
+
storeRequestHeaders
|
|
1587
|
+
};
|
|
1588
|
+
}
|
|
1589
|
+
var useStore = create()(
|
|
1590
|
+
(set) => ({
|
|
1591
|
+
data: null,
|
|
1592
|
+
drawers: {
|
|
1593
|
+
cart: false,
|
|
1594
|
+
search: false,
|
|
1595
|
+
menu: false,
|
|
1596
|
+
filter: false
|
|
1597
|
+
},
|
|
1598
|
+
openDrawer: (drawer) => set((state) => ({
|
|
1599
|
+
drawers: {
|
|
1600
|
+
...state.drawers,
|
|
1601
|
+
[drawer]: true
|
|
1602
|
+
}
|
|
1603
|
+
})),
|
|
1604
|
+
closeDrawer: (drawer) => set((state) => ({
|
|
1605
|
+
drawers: {
|
|
1606
|
+
...state.drawers,
|
|
1607
|
+
[drawer]: false
|
|
1608
|
+
}
|
|
1609
|
+
})),
|
|
1610
|
+
toggleDrawer: (drawer) => set((state) => ({
|
|
1611
|
+
drawers: {
|
|
1612
|
+
...state.drawers,
|
|
1613
|
+
[drawer]: !state.drawers[drawer]
|
|
1614
|
+
}
|
|
1615
|
+
})),
|
|
1616
|
+
closeAllDrawers: () => set((state) => ({
|
|
1617
|
+
drawers: Object.keys(state.drawers).reduce(
|
|
1618
|
+
(acc, key) => ({ ...acc, [key]: false }),
|
|
1619
|
+
{}
|
|
1620
|
+
)
|
|
1621
|
+
})),
|
|
1622
|
+
modals: {
|
|
1623
|
+
login: false,
|
|
1624
|
+
signup: false
|
|
1625
|
+
},
|
|
1626
|
+
openModal: (modal) => set((state) => ({
|
|
1627
|
+
modals: {
|
|
1628
|
+
...state.modals,
|
|
1629
|
+
login: false,
|
|
1630
|
+
signup: false,
|
|
1631
|
+
[modal]: true
|
|
1632
|
+
}
|
|
1633
|
+
})),
|
|
1634
|
+
closeModal: (modal) => set((state) => ({
|
|
1635
|
+
modals: {
|
|
1636
|
+
...state.modals,
|
|
1637
|
+
login: false,
|
|
1638
|
+
signup: false,
|
|
1639
|
+
[modal]: false
|
|
1640
|
+
}
|
|
1641
|
+
})),
|
|
1642
|
+
toggleModal: (modal) => set((state) => ({
|
|
1643
|
+
modals: {
|
|
1644
|
+
...state.modals,
|
|
1645
|
+
[modal]: !state.modals[modal]
|
|
1646
|
+
}
|
|
1647
|
+
})),
|
|
1648
|
+
closeAllModals: () => set((state) => ({
|
|
1649
|
+
modals: Object.keys(state.modals).reduce(
|
|
1650
|
+
(acc, key) => ({ ...acc, [key]: false }),
|
|
1651
|
+
{}
|
|
1652
|
+
)
|
|
1653
|
+
}))
|
|
1654
|
+
})
|
|
1655
|
+
);
|
|
1656
|
+
var useCart = create()(
|
|
1657
|
+
persist(
|
|
1658
|
+
(set) => ({
|
|
1659
|
+
count: 0,
|
|
1660
|
+
cart: [],
|
|
1661
|
+
cartTokenId: null,
|
|
1662
|
+
setCartTokenId: (token) => set((state) => ({ ...state, cartTokenId: token })),
|
|
1663
|
+
checkoutStep: null,
|
|
1664
|
+
setCheckoutStep: (step) => set((state) => ({ ...state, checkoutStep: step })),
|
|
1665
|
+
checkoutCustomerLocal: null,
|
|
1666
|
+
setCheckoutCustomerLocal: (customer) => set((state) => {
|
|
1667
|
+
if (!state.cartTokenId) return state;
|
|
1668
|
+
return {
|
|
1669
|
+
checkoutCustomerLocal: {
|
|
1670
|
+
cartTokenId: state.cartTokenId,
|
|
1671
|
+
customer
|
|
1672
|
+
}
|
|
1673
|
+
};
|
|
1674
|
+
}),
|
|
1675
|
+
clearCheckoutCustomerLocal: () => set(() => ({ checkoutCustomerLocal: null })),
|
|
1676
|
+
addCart: (item) => set((state) => {
|
|
1677
|
+
const existingItem = state.cart.find(
|
|
1678
|
+
(cartItem) => cartItem.id === item.id
|
|
1679
|
+
);
|
|
1680
|
+
if (existingItem) {
|
|
1681
|
+
const newQuantity = Math.max(0, existingItem.quantity) + 1;
|
|
1682
|
+
const cart2 = state.cart.map(
|
|
1683
|
+
(cartItem) => cartItem.id === item.id ? { ...cartItem, quantity: newQuantity } : cartItem
|
|
1684
|
+
);
|
|
1685
|
+
const count2 = cart2.reduce((sum, i) => sum + Math.max(0, i.quantity), 0);
|
|
1686
|
+
return { count: count2, cart: cart2 };
|
|
1687
|
+
}
|
|
1688
|
+
const newItem = {
|
|
1689
|
+
...item,
|
|
1690
|
+
quantity: Math.max(1, Math.max(0, item.quantity ?? 1))
|
|
1691
|
+
};
|
|
1692
|
+
const cart = [...state.cart, newItem];
|
|
1693
|
+
const count = cart.reduce((sum, i) => sum + Math.max(0, i.quantity), 0);
|
|
1694
|
+
return { count, cart };
|
|
1695
|
+
}),
|
|
1696
|
+
removeCart: (id) => set((state) => {
|
|
1697
|
+
const existingItem = state.cart.find((item) => item.id === id);
|
|
1698
|
+
if (!existingItem) return state;
|
|
1699
|
+
if (existingItem.quantity > 1) {
|
|
1700
|
+
const newQuantity = Math.max(0, existingItem.quantity - 1);
|
|
1701
|
+
const cart2 = state.cart.map(
|
|
1702
|
+
(cartItem) => cartItem.id === id ? { ...cartItem, quantity: newQuantity } : cartItem
|
|
1703
|
+
);
|
|
1704
|
+
const count2 = cart2.reduce((sum, i) => sum + Math.max(0, i.quantity), 0);
|
|
1705
|
+
return { count: count2, cart: cart2 };
|
|
1706
|
+
}
|
|
1707
|
+
const cart = state.cart.filter((item) => item.id !== id);
|
|
1708
|
+
const count = Math.max(0, cart.reduce((sum, i) => sum + Math.max(0, i.quantity), 0));
|
|
1709
|
+
return { count, cart };
|
|
1710
|
+
}),
|
|
1711
|
+
clearCartSession: () => set(() => ({
|
|
1712
|
+
count: 0,
|
|
1713
|
+
cart: [],
|
|
1714
|
+
cartTokenId: null,
|
|
1715
|
+
checkoutStep: null,
|
|
1716
|
+
checkoutCustomerLocal: null
|
|
1717
|
+
}))
|
|
1718
|
+
}),
|
|
1719
|
+
{ name: "cart-storage" }
|
|
1720
|
+
)
|
|
1721
|
+
);
|
|
1722
|
+
|
|
1723
|
+
// src/react/auth/ecomiq-oauth-password-constants.ts
|
|
1724
|
+
var PLUGIN_ID = "ecomiq-oauth-password";
|
|
1725
|
+
var ECOMIQ_OAUTH_TOKEN_URL = "https://auth.ecomiq.pe/connect/token";
|
|
1726
|
+
var ECOMIQ_OAUTH_USERINFO_URL = "https://auth.ecomiq.pe/connect/userinfo";
|
|
1727
|
+
var tokenResponseSchema = z.object({
|
|
1728
|
+
access_token: z.string().min(1),
|
|
1729
|
+
token_type: z.string().optional(),
|
|
1730
|
+
/** Segundos hasta expiración (Ecomiq envía ej. `86399`). Sincroniza la sesión Better Auth con el bearer. */
|
|
1731
|
+
expires_in: z.coerce.number().int().positive().optional()
|
|
1732
|
+
});
|
|
1733
|
+
var userInfoSchema = z.object({
|
|
1734
|
+
sub: z.string(),
|
|
1735
|
+
email: z.string().email().optional(),
|
|
1736
|
+
family_name: z.string().optional(),
|
|
1737
|
+
given_name: z.string().optional(),
|
|
1738
|
+
iss: z.string().optional(),
|
|
1739
|
+
aud: z.union([z.string(), z.array(z.string())]).optional()
|
|
1740
|
+
});
|
|
1741
|
+
var signInBody = z.object({
|
|
1742
|
+
email: z.string().email(),
|
|
1743
|
+
password: z.string().min(1),
|
|
1744
|
+
callbackURL: z.string().optional(),
|
|
1745
|
+
rememberMe: z.boolean().optional().default(true)
|
|
1746
|
+
});
|
|
1747
|
+
|
|
1748
|
+
// src/react/auth/ecomiq-oauth-password-plugin.ts
|
|
1749
|
+
function ecomiqOAuthPassword() {
|
|
1750
|
+
const secureCookie = true;
|
|
1751
|
+
const clearStorefrontOAuthCookieMiddleware = createAuthMiddleware(async (ctx) => {
|
|
1752
|
+
ctx.setCookie(STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME, "", {
|
|
1753
|
+
path: STOREFRONT_ECOMIQ_OAUTH_COOKIE_PATH,
|
|
1754
|
+
httpOnly: true,
|
|
1755
|
+
sameSite: "lax",
|
|
1756
|
+
secure: secureCookie,
|
|
1757
|
+
maxAge: 0
|
|
1758
|
+
});
|
|
1759
|
+
});
|
|
1760
|
+
return {
|
|
1761
|
+
id: PLUGIN_ID,
|
|
1762
|
+
schema: {
|
|
1763
|
+
user: {
|
|
1764
|
+
fields: {
|
|
1765
|
+
firstName: { type: "string", required: false },
|
|
1766
|
+
lastName: { type: "string", required: false },
|
|
1767
|
+
phone: { type: "string", required: false }
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
},
|
|
1771
|
+
hooks: {
|
|
1772
|
+
after: [
|
|
1773
|
+
{
|
|
1774
|
+
matcher: (hookCtx) => hookCtx.path === "/sign-out",
|
|
1775
|
+
handler: clearStorefrontOAuthCookieMiddleware
|
|
1776
|
+
}
|
|
1777
|
+
]
|
|
1778
|
+
},
|
|
1779
|
+
endpoints: {
|
|
1780
|
+
signIn: createAuthEndpoint(
|
|
1781
|
+
"/ecomiq-oauth/sign-in",
|
|
1782
|
+
{
|
|
1783
|
+
method: "POST",
|
|
1784
|
+
use: [formCsrfMiddleware],
|
|
1785
|
+
body: signInBody
|
|
1786
|
+
},
|
|
1787
|
+
async (ctx) => {
|
|
1788
|
+
const { email: loginEmail, password, callbackURL, rememberMe } = ctx.body;
|
|
1789
|
+
const tokens = await exchangePasswordGrant(loginEmail, password, {
|
|
1790
|
+
identityScope: ctx.getHeader("x-Identity-Scope"),
|
|
1791
|
+
tenantId: ctx.getHeader("x-Tenant-Id"),
|
|
1792
|
+
storeId: ctx.getHeader("x-Store-Id")
|
|
1793
|
+
});
|
|
1794
|
+
const profile = await fetchUserInfo(tokens.access_token);
|
|
1795
|
+
const profileEmail = profile.email?.toLowerCase().trim();
|
|
1796
|
+
const canonicalEmail = profileEmail ?? loginEmail.toLowerCase().trim();
|
|
1797
|
+
if (profileEmail && profileEmail !== loginEmail.toLowerCase().trim()) {
|
|
1798
|
+
throw APIError.from("UNAUTHORIZED", {
|
|
1799
|
+
code: "ECOMIQ_EMAIL_MISMATCH",
|
|
1800
|
+
message: "El correo del perfil OAuth no coincide con el inicio de sesi\xF3n"
|
|
1801
|
+
});
|
|
1802
|
+
}
|
|
1803
|
+
const displayName = displayNameFromUserInfo(profile, canonicalEmail);
|
|
1804
|
+
const existing = await ctx.context.internalAdapter.findUserByEmail(canonicalEmail);
|
|
1805
|
+
let user = existing?.user;
|
|
1806
|
+
if (!user) {
|
|
1807
|
+
user = await ctx.context.internalAdapter.createUser({
|
|
1808
|
+
email: canonicalEmail,
|
|
1809
|
+
name: displayName,
|
|
1810
|
+
emailVerified: true
|
|
1811
|
+
});
|
|
1812
|
+
} else if (user.name !== displayName) {
|
|
1813
|
+
await ctx.context.internalAdapter.updateUser(user.id, { name: displayName });
|
|
1814
|
+
user = { ...user, name: displayName };
|
|
1815
|
+
}
|
|
1816
|
+
const oauthSessionExpires = tokens.expires_in !== void 0 && tokens.expires_in > 0 ? new Date(Date.now() + tokens.expires_in * 1e3) : void 0;
|
|
1817
|
+
const session = await ctx.context.internalAdapter.createSession(
|
|
1818
|
+
user.id,
|
|
1819
|
+
rememberMe === false,
|
|
1820
|
+
oauthSessionExpires ? { expiresAt: oauthSessionExpires } : {},
|
|
1821
|
+
Boolean(oauthSessionExpires)
|
|
1822
|
+
);
|
|
1823
|
+
if (!session) {
|
|
1824
|
+
throw APIError.from("INTERNAL_SERVER_ERROR", {
|
|
1825
|
+
code: "ECOMIQ_SESSION_FAILED",
|
|
1826
|
+
message: "No se pudo crear la sesi\xF3n"
|
|
1827
|
+
});
|
|
1828
|
+
}
|
|
1829
|
+
await setSessionCookie(ctx, { session, user }, rememberMe === false);
|
|
1830
|
+
const oauthMaxAgeSec = oauthSessionExpires !== void 0 ? Math.max(60, Math.ceil((oauthSessionExpires.getTime() - Date.now()) / 1e3)) : tokens.expires_in !== void 0 && tokens.expires_in > 0 ? tokens.expires_in : 60 * 60 * 24;
|
|
1831
|
+
await ctx.setCookie(STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME, tokens.access_token, {
|
|
1832
|
+
path: STOREFRONT_ECOMIQ_OAUTH_COOKIE_PATH,
|
|
1833
|
+
httpOnly: true,
|
|
1834
|
+
sameSite: "lax",
|
|
1835
|
+
secure: secureCookie,
|
|
1836
|
+
maxAge: oauthMaxAgeSec
|
|
1837
|
+
});
|
|
1838
|
+
if (callbackURL) ctx.setHeader("Location", callbackURL);
|
|
1839
|
+
return ctx.json({
|
|
1840
|
+
redirect: !!callbackURL,
|
|
1841
|
+
token: session.token,
|
|
1842
|
+
url: callbackURL,
|
|
1843
|
+
user: parseUserOutput(ctx.context.options, user)
|
|
1844
|
+
});
|
|
1845
|
+
}
|
|
1846
|
+
)
|
|
1847
|
+
}
|
|
1848
|
+
};
|
|
1849
|
+
}
|
|
1850
|
+
function displayNameFromUserInfo(profile, fallbackEmail) {
|
|
1851
|
+
const parts = [profile.given_name?.trim(), profile.family_name?.trim()].filter(Boolean);
|
|
1852
|
+
const joined = parts.join(" ").trim();
|
|
1853
|
+
if (joined) return joined;
|
|
1854
|
+
return fallbackEmail.split("@")[0] || "Cliente";
|
|
1855
|
+
}
|
|
1856
|
+
async function fetchUserInfo(accessToken) {
|
|
1857
|
+
const res = await fetch(ECOMIQ_OAUTH_USERINFO_URL, {
|
|
1858
|
+
method: "GET",
|
|
1859
|
+
headers: {
|
|
1860
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1861
|
+
accept: "application/json"
|
|
1862
|
+
}
|
|
1863
|
+
});
|
|
1864
|
+
const text = await res.text();
|
|
1865
|
+
let json;
|
|
1866
|
+
try {
|
|
1867
|
+
json = text ? JSON.parse(text) : {};
|
|
1868
|
+
} catch {
|
|
1869
|
+
throw APIError.from("UNAUTHORIZED", {
|
|
1870
|
+
code: "ECOMIQ_USERINFO_INVALID_BODY",
|
|
1871
|
+
message: "Respuesta inv\xE1lida del endpoint userinfo"
|
|
1872
|
+
});
|
|
1873
|
+
}
|
|
1874
|
+
if (!res.ok) {
|
|
1875
|
+
const err = json;
|
|
1876
|
+
throw APIError.from("UNAUTHORIZED", {
|
|
1877
|
+
code: "ECOMIQ_USERINFO_REJECTED",
|
|
1878
|
+
message: err.error_description ?? err.error ?? "No se pudo obtener el perfil del usuario"
|
|
1879
|
+
});
|
|
1880
|
+
}
|
|
1881
|
+
const parsed = userInfoSchema.safeParse(json);
|
|
1882
|
+
if (!parsed.success) {
|
|
1883
|
+
throw APIError.from("UNAUTHORIZED", {
|
|
1884
|
+
code: "ECOMIQ_USERINFO_SHAPE",
|
|
1885
|
+
message: "Perfil OAuth con formato inv\xE1lido"
|
|
1886
|
+
});
|
|
1887
|
+
}
|
|
1888
|
+
return parsed.data;
|
|
1889
|
+
}
|
|
1890
|
+
async function exchangePasswordGrant(username, password, context) {
|
|
1891
|
+
const clientId = process.env.ECOMIQ_AUTH_CLIENT_ID ?? "";
|
|
1892
|
+
const clientSecret = process.env.ECOMIQ_AUTH_CLIENT_SECRET ?? "";
|
|
1893
|
+
const scope = process.env.ECOMIQ_AUTH_SCOPE ?? "";
|
|
1894
|
+
if (!clientId || !clientSecret) {
|
|
1895
|
+
throw APIError.from("INTERNAL_SERVER_ERROR", {
|
|
1896
|
+
code: "ECOMIQ_AUTH_NOT_CONFIGURED",
|
|
1897
|
+
message: "OAuth Ecomiq no configurado: ECOMIQ_AUTH_CLIENT_ID y ECOMIQ_AUTH_CLIENT_SECRET."
|
|
1898
|
+
});
|
|
1899
|
+
}
|
|
1900
|
+
const body = new URLSearchParams({
|
|
1901
|
+
grant_type: "password",
|
|
1902
|
+
username,
|
|
1903
|
+
password,
|
|
1904
|
+
scope,
|
|
1905
|
+
client_id: clientId,
|
|
1906
|
+
client_secret: clientSecret
|
|
1907
|
+
});
|
|
1908
|
+
const identityScope = context.identityScope;
|
|
1909
|
+
const tenantId = context.tenantId;
|
|
1910
|
+
const storeId = context.storeId;
|
|
1911
|
+
const headers = new Headers({
|
|
1912
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
1913
|
+
accept: "application/json"
|
|
1914
|
+
});
|
|
1915
|
+
if (identityScope?.trim()) {
|
|
1916
|
+
headers.set("x-Identity-Scope", identityScope.trim());
|
|
1917
|
+
}
|
|
1918
|
+
if (tenantId?.trim()) {
|
|
1919
|
+
headers.set("x-Tenant-Id", tenantId.trim());
|
|
1920
|
+
}
|
|
1921
|
+
if (storeId?.trim()) {
|
|
1922
|
+
headers.set("x-Store-Id", storeId.trim());
|
|
1923
|
+
}
|
|
1924
|
+
let res;
|
|
1925
|
+
let text;
|
|
1926
|
+
try {
|
|
1927
|
+
res = await fetch(ECOMIQ_OAUTH_TOKEN_URL, {
|
|
1928
|
+
method: "POST",
|
|
1929
|
+
headers,
|
|
1930
|
+
body
|
|
1931
|
+
});
|
|
1932
|
+
text = await res.text();
|
|
1933
|
+
} catch (e) {
|
|
1934
|
+
throw mapTokenEndpointFetchFailure(e);
|
|
1935
|
+
}
|
|
1936
|
+
const json = safeParseJson(text);
|
|
1937
|
+
if (!res.ok) {
|
|
1938
|
+
throwBadRequestFromOAuth(json, res.statusText || text || `HTTP ${res.status}`);
|
|
1939
|
+
}
|
|
1940
|
+
const parsed = tokenResponseSchema.safeParse(json);
|
|
1941
|
+
if (!parsed.success) {
|
|
1942
|
+
throwBadRequestFromOAuth(json, "Token de acceso no recibido");
|
|
1943
|
+
}
|
|
1944
|
+
return parsed.data;
|
|
1945
|
+
}
|
|
1946
|
+
function safeParseJson(text) {
|
|
1947
|
+
try {
|
|
1948
|
+
return text ? JSON.parse(text) : {};
|
|
1949
|
+
} catch {
|
|
1950
|
+
return {};
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
function throwBadRequestFromOAuth(payload, fallbackMessage) {
|
|
1954
|
+
const err = payload;
|
|
1955
|
+
const errorCode = typeof err.error === "string" && err.error.trim() ? err.error.trim() : "invalid_grant";
|
|
1956
|
+
const errorMessage = typeof err.error_description === "string" && err.error_description.trim() ? err.error_description.trim() : typeof err.error === "string" && err.error.trim() ? err.error.trim() : fallbackMessage.trim() || "Credenciales invalidas.";
|
|
1957
|
+
throw APIError.from("BAD_REQUEST", {
|
|
1958
|
+
code: errorCode,
|
|
1959
|
+
message: errorMessage.slice(0, 500)
|
|
1960
|
+
});
|
|
1961
|
+
}
|
|
1962
|
+
function mapTokenEndpointFetchFailure(e) {
|
|
1963
|
+
const codes = collectNetworkErrorCodes(e);
|
|
1964
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1965
|
+
const isDnsError = codes.some((c) => c === "ENOTFOUND" || c === "EAI_AGAIN");
|
|
1966
|
+
if (isDnsError) {
|
|
1967
|
+
throw APIError.from("BAD_GATEWAY", {
|
|
1968
|
+
code: "ECOMIQ_AUTH_DNS",
|
|
1969
|
+
message: "No se pudo resolver el servidor de autenticacion."
|
|
1970
|
+
});
|
|
1971
|
+
}
|
|
1972
|
+
const isConnectionRefused = codes.includes("ECONNREFUSED");
|
|
1973
|
+
if (isConnectionRefused) {
|
|
1974
|
+
throw APIError.from("BAD_GATEWAY", {
|
|
1975
|
+
code: "ECOMIQ_AUTH_REFUSED",
|
|
1976
|
+
message: "Conexion rechazada al servidor de autenticacion."
|
|
1977
|
+
});
|
|
1978
|
+
}
|
|
1979
|
+
const looksLikeAbortOrSocketClose = codes.some(
|
|
1980
|
+
(c) => ["UND_ERR_SOCKET", "ECONNRESET", "EPIPE", "ECONNABORTED"].includes(c)
|
|
1981
|
+
) || /terminated|abort|closed|FIN|socket/i.test(msg);
|
|
1982
|
+
if (looksLikeAbortOrSocketClose) {
|
|
1983
|
+
throwBadRequestFromOAuth({}, "Credenciales invalidas o conexion cerrada por el servidor.");
|
|
1984
|
+
}
|
|
1985
|
+
throw APIError.from("INTERNAL_SERVER_ERROR", {
|
|
1986
|
+
code: "ECOMIQ_AUTH_REQUEST_FAILED",
|
|
1987
|
+
message: msg.slice(0, 280) || "Error al contactar el servidor de autenticacion."
|
|
1988
|
+
});
|
|
1989
|
+
}
|
|
1990
|
+
function collectNetworkErrorCodes(e) {
|
|
1991
|
+
const out = [];
|
|
1992
|
+
const visit = (x) => {
|
|
1993
|
+
if (!x || typeof x !== "object") return;
|
|
1994
|
+
const code = "code" in x && typeof x.code === "string" ? x.code : void 0;
|
|
1995
|
+
if (code) out.push(code);
|
|
1996
|
+
if ("cause" in x && x.cause) {
|
|
1997
|
+
visit(x.cause);
|
|
1998
|
+
}
|
|
1999
|
+
};
|
|
2000
|
+
visit(e);
|
|
2001
|
+
return out;
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
// src/react/auth/ecomiq-oauth-password-client.ts
|
|
2005
|
+
function ecomiqOAuthPasswordClient() {
|
|
2006
|
+
return {
|
|
2007
|
+
id: PLUGIN_ID,
|
|
2008
|
+
pathMethods: {
|
|
2009
|
+
"/ecomiq-oauth/sign-in": "POST"
|
|
2010
|
+
},
|
|
2011
|
+
atomListeners: [
|
|
2012
|
+
{
|
|
2013
|
+
matcher: (path) => path === "/ecomiq-oauth/sign-in",
|
|
2014
|
+
signal: "$sessionSignal"
|
|
2015
|
+
}
|
|
2016
|
+
]
|
|
2017
|
+
};
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
// src/react/components/cms-sections/utils.ts
|
|
2021
|
+
var PRODUCT_SORTS = /* @__PURE__ */ new Set([
|
|
2022
|
+
"price_asc",
|
|
2023
|
+
"price_desc",
|
|
2024
|
+
"name_asc",
|
|
2025
|
+
"name_desc",
|
|
2026
|
+
"newest"
|
|
2027
|
+
]);
|
|
2028
|
+
function orderedBlocks(blocks) {
|
|
2029
|
+
return [...blocks ?? []].sort((a, b) => a.order - b.order);
|
|
2030
|
+
}
|
|
2031
|
+
function getCmsSectionKey(section, index) {
|
|
2032
|
+
return section.id ?? `${canonicalSectionType(section.type)}-${section.order}-${index}`;
|
|
2033
|
+
}
|
|
2034
|
+
function getCmsBlockKey(block, index) {
|
|
2035
|
+
return block.id ?? `${block.type}-${block.order}-${index}`;
|
|
2036
|
+
}
|
|
2037
|
+
function canonicalSectionType(type) {
|
|
2038
|
+
if (type === "page-hero") {
|
|
2039
|
+
return "hero";
|
|
2040
|
+
}
|
|
2041
|
+
if (type === "featured-products") {
|
|
2042
|
+
return "product-list";
|
|
2043
|
+
}
|
|
2044
|
+
return type;
|
|
2045
|
+
}
|
|
2046
|
+
function storefrontHref(value) {
|
|
2047
|
+
const href = value.trim();
|
|
2048
|
+
if (!href) {
|
|
2049
|
+
return "#";
|
|
2050
|
+
}
|
|
2051
|
+
if (href === "#" || href.startsWith("http://") || href.startsWith("https://") || href.startsWith("mailto:") || href.startsWith("tel:")) {
|
|
2052
|
+
return href;
|
|
2053
|
+
}
|
|
2054
|
+
if (href === "/") {
|
|
2055
|
+
return "/store";
|
|
2056
|
+
}
|
|
2057
|
+
if (href.startsWith("/store") || href.startsWith("/product")) {
|
|
2058
|
+
return href;
|
|
2059
|
+
}
|
|
2060
|
+
if (href.startsWith("/collections") || href.startsWith("/pages") || href.startsWith("/account")) {
|
|
2061
|
+
return `/store${href}`;
|
|
2062
|
+
}
|
|
2063
|
+
return href;
|
|
2064
|
+
}
|
|
2065
|
+
function sectionTitleContent(section) {
|
|
2066
|
+
return settingContent(section.settings, "title") || settingContent(section.settings, "name");
|
|
2067
|
+
}
|
|
2068
|
+
function settingString(settings, key) {
|
|
2069
|
+
const value = settings?.[key];
|
|
2070
|
+
return typeof value === "string" ? value : "";
|
|
2071
|
+
}
|
|
2072
|
+
function settingContent(settings, key) {
|
|
2073
|
+
const value = settings?.[key];
|
|
2074
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
2075
|
+
return value;
|
|
2076
|
+
}
|
|
2077
|
+
if (value == null || typeof value === "boolean") {
|
|
2078
|
+
return "";
|
|
2079
|
+
}
|
|
2080
|
+
return value;
|
|
2081
|
+
}
|
|
2082
|
+
function settingNumber(settings, key, fallback) {
|
|
2083
|
+
const value = settings?.[key];
|
|
2084
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
2085
|
+
return value;
|
|
2086
|
+
}
|
|
2087
|
+
if (typeof value === "string") {
|
|
2088
|
+
const parsed = Number(value);
|
|
2089
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
2090
|
+
}
|
|
2091
|
+
return fallback;
|
|
2092
|
+
}
|
|
2093
|
+
function layoutChildren(settings, key) {
|
|
2094
|
+
const children = settings.children;
|
|
2095
|
+
if (typeof children !== "object" || children === null || Array.isArray(children)) {
|
|
2096
|
+
return [];
|
|
2097
|
+
}
|
|
2098
|
+
const value = children[key];
|
|
2099
|
+
return Array.isArray(value) ? value : [];
|
|
2100
|
+
}
|
|
2101
|
+
function layoutPadding(value) {
|
|
2102
|
+
switch (value) {
|
|
2103
|
+
case "none":
|
|
2104
|
+
return "py-0";
|
|
2105
|
+
case "small":
|
|
2106
|
+
return "py-6";
|
|
2107
|
+
case "large":
|
|
2108
|
+
return "py-16";
|
|
2109
|
+
default:
|
|
2110
|
+
return "py-10";
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
function layoutMaxWidth(value) {
|
|
2114
|
+
switch (value) {
|
|
2115
|
+
case "full":
|
|
2116
|
+
return "max-w-none";
|
|
2117
|
+
case "narrow":
|
|
2118
|
+
return "max-w-3xl";
|
|
2119
|
+
default:
|
|
2120
|
+
return "max-w-7xl";
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
2123
|
+
function layoutBackground(value) {
|
|
2124
|
+
switch (value) {
|
|
2125
|
+
case "muted":
|
|
2126
|
+
return "bg-neutral-50";
|
|
2127
|
+
case "dark":
|
|
2128
|
+
return "bg-neutral-950 text-white";
|
|
2129
|
+
default:
|
|
2130
|
+
return "bg-white";
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
2133
|
+
function layoutGap(value) {
|
|
2134
|
+
switch (value) {
|
|
2135
|
+
case "none":
|
|
2136
|
+
return "gap-0";
|
|
2137
|
+
case "small":
|
|
2138
|
+
return "gap-3";
|
|
2139
|
+
case "large":
|
|
2140
|
+
return "gap-8";
|
|
2141
|
+
default:
|
|
2142
|
+
return "gap-5";
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
function layoutAlign(value) {
|
|
2146
|
+
switch (value) {
|
|
2147
|
+
case "start":
|
|
2148
|
+
return "items-start";
|
|
2149
|
+
case "center":
|
|
2150
|
+
return "items-center";
|
|
2151
|
+
case "end":
|
|
2152
|
+
return "items-end";
|
|
2153
|
+
default:
|
|
2154
|
+
return "items-stretch";
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
function layoutJustify(value) {
|
|
2158
|
+
switch (value) {
|
|
2159
|
+
case "center":
|
|
2160
|
+
return "justify-center";
|
|
2161
|
+
case "end":
|
|
2162
|
+
return "justify-end";
|
|
2163
|
+
case "between":
|
|
2164
|
+
return "justify-between";
|
|
2165
|
+
default:
|
|
2166
|
+
return "justify-start";
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
function productSortValue(value) {
|
|
2170
|
+
return PRODUCT_SORTS.has(value) ? value : "newest";
|
|
2171
|
+
}
|
|
2172
|
+
function sanitizeHtml(html) {
|
|
2173
|
+
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, "");
|
|
2174
|
+
}
|
|
2175
|
+
var DEFAULT_CMS_IMAGE_URL = "data:image/svg+xml;charset=UTF-8," + encodeURIComponent(`
|
|
2176
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="360" viewBox="0 0 640 360">
|
|
2177
|
+
<rect width="640" height="360" fill="#f4f4f5"/>
|
|
2178
|
+
<rect x="40" y="36" width="560" height="288" rx="20" fill="#ffffff" stroke="#d4d4d8"/>
|
|
2179
|
+
<path d="M148 246l102-102 78 78 48-48 120 120H148z" fill="#d4d4d8"/>
|
|
2180
|
+
<circle cx="456" cy="118" r="32" fill="#e4e4e7"/>
|
|
2181
|
+
</svg>
|
|
2182
|
+
`);
|
|
2183
|
+
function SectionHeading({ section }) {
|
|
2184
|
+
const title = sectionTitleContent(section);
|
|
2185
|
+
const subtitle = settingContent(section.settings, "subtitle");
|
|
2186
|
+
if (!title && !subtitle) {
|
|
2187
|
+
return null;
|
|
2188
|
+
}
|
|
2189
|
+
return /* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
|
|
2190
|
+
title ? /* @__PURE__ */ jsx("h2", { className: "text-2xl font-semibold tracking-tight text-neutral-950", children: title }) : null,
|
|
2191
|
+
subtitle ? /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-neutral-600", children: subtitle }) : null
|
|
2192
|
+
] });
|
|
2193
|
+
}
|
|
2194
|
+
function EmptyState({ children }) {
|
|
2195
|
+
return /* @__PURE__ */ jsx("p", { className: "rounded-lg border border-dashed p-6 text-center text-sm text-neutral-500", children });
|
|
2196
|
+
}
|
|
2197
|
+
function DefaultLink({ href, className, children }) {
|
|
2198
|
+
return /* @__PURE__ */ jsx("a", { href, className, children });
|
|
2199
|
+
}
|
|
2200
|
+
function CmsImage({
|
|
2201
|
+
src,
|
|
2202
|
+
fallbackSrc = DEFAULT_CMS_IMAGE_URL,
|
|
2203
|
+
onError,
|
|
2204
|
+
...props
|
|
2205
|
+
}) {
|
|
2206
|
+
const imageSrc = src?.trim() || fallbackSrc;
|
|
2207
|
+
return /* @__PURE__ */ jsx(
|
|
2208
|
+
"img",
|
|
2209
|
+
{
|
|
2210
|
+
src: imageSrc,
|
|
2211
|
+
onError: (event) => {
|
|
2212
|
+
onError?.(event);
|
|
2213
|
+
const image = event.currentTarget;
|
|
2214
|
+
if (image.dataset.cmsFallback === "true") {
|
|
2215
|
+
return;
|
|
2216
|
+
}
|
|
2217
|
+
image.dataset.cmsFallback = "true";
|
|
2218
|
+
image.src = fallbackSrc;
|
|
2219
|
+
},
|
|
2220
|
+
...props
|
|
2221
|
+
}
|
|
2222
|
+
);
|
|
2223
|
+
}
|
|
2224
|
+
function RichTextSection({ section }) {
|
|
2225
|
+
const html = settingString(section.settings, "html") || settingString(section.settings, "content") || settingString(section.settings, "richText");
|
|
2226
|
+
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-10", children: [
|
|
2227
|
+
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2228
|
+
html ? /* @__PURE__ */ jsx(
|
|
2229
|
+
"div",
|
|
2230
|
+
{
|
|
2231
|
+
className: "prose prose-neutral max-w-none",
|
|
2232
|
+
dangerouslySetInnerHTML: { __html: sanitizeHtml(html) }
|
|
2233
|
+
}
|
|
2234
|
+
) : null
|
|
2235
|
+
] });
|
|
2236
|
+
}
|
|
2237
|
+
function CustomHtmlSection({ section }) {
|
|
2238
|
+
const html = settingString(section.settings, "html") || settingString(section.settings, "content");
|
|
2239
|
+
if (!html) {
|
|
2240
|
+
return null;
|
|
2241
|
+
}
|
|
2242
|
+
return /* @__PURE__ */ jsx(
|
|
2243
|
+
"section",
|
|
2244
|
+
{
|
|
2245
|
+
className: "cms-custom-html",
|
|
2246
|
+
dangerouslySetInnerHTML: { __html: sanitizeHtml(html) }
|
|
2247
|
+
}
|
|
2248
|
+
);
|
|
2249
|
+
}
|
|
2250
|
+
function FloatingBlockSection({
|
|
2251
|
+
section,
|
|
2252
|
+
linkComponent: LinkComponent
|
|
2253
|
+
}) {
|
|
2254
|
+
const settings = section.settings ?? {};
|
|
2255
|
+
const title = settingContent(settings, "title");
|
|
2256
|
+
const text = settingContent(settings, "text");
|
|
2257
|
+
const imageUrl = settingString(settings, "imageUrl");
|
|
2258
|
+
const linkText = settingContent(settings, "linkText");
|
|
2259
|
+
const linkUrl = storefrontHref(settingString(settings, "linkUrl"));
|
|
2260
|
+
const x = boundedPercent(settingNumber(settings, "x", 8));
|
|
2261
|
+
const y = boundedPercent(settingNumber(settings, "y", 12));
|
|
2262
|
+
const width = Math.min(
|
|
2263
|
+
Math.max(boundedPercent(settingNumber(settings, "width", 28)), 12),
|
|
2264
|
+
90
|
|
2265
|
+
);
|
|
2266
|
+
const zIndex = Math.max(Math.round(settingNumber(settings, "zIndex", 20)), 1);
|
|
2267
|
+
if (!title && !text && !imageUrl) {
|
|
2268
|
+
return null;
|
|
2269
|
+
}
|
|
2270
|
+
const content = /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-lg border border-black/10 bg-white text-neutral-950 shadow-lg", children: [
|
|
2271
|
+
imageUrl ? /* @__PURE__ */ jsx("div", { className: "aspect-[16/9] bg-neutral-100", children: /* @__PURE__ */ jsx(
|
|
2272
|
+
CmsImage,
|
|
2273
|
+
{
|
|
2274
|
+
src: imageUrl,
|
|
2275
|
+
alt: "",
|
|
2276
|
+
className: "h-full w-full object-cover",
|
|
2277
|
+
loading: "lazy"
|
|
2278
|
+
}
|
|
2279
|
+
) }) : null,
|
|
2280
|
+
/* @__PURE__ */ jsxs("div", { className: "p-4", children: [
|
|
2281
|
+
title ? /* @__PURE__ */ jsx("p", { className: "text-base font-semibold leading-6", children: title }) : null,
|
|
2282
|
+
text ? /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm leading-5 text-neutral-600", children: text }) : null,
|
|
2283
|
+
linkText && linkUrl !== "#" ? /* @__PURE__ */ jsx("span", { className: "mt-3 inline-flex text-sm font-medium underline underline-offset-4", children: linkText }) : null
|
|
2284
|
+
] })
|
|
2285
|
+
] });
|
|
2286
|
+
return /* @__PURE__ */ jsx(
|
|
2287
|
+
"div",
|
|
2288
|
+
{
|
|
2289
|
+
className: "absolute",
|
|
2290
|
+
style: {
|
|
2291
|
+
left: `${x}%`,
|
|
2292
|
+
top: `${y}%`,
|
|
2293
|
+
width: `${width}%`,
|
|
2294
|
+
zIndex
|
|
2295
|
+
},
|
|
2296
|
+
children: linkText && linkUrl !== "#" ? /* @__PURE__ */ jsx(LinkComponent, { href: linkUrl, children: content }) : content
|
|
2297
|
+
}
|
|
2298
|
+
);
|
|
2299
|
+
}
|
|
2300
|
+
function FaqSection({ section }) {
|
|
2301
|
+
const items = orderedBlocks(section.blocks);
|
|
2302
|
+
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
|
|
2303
|
+
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2304
|
+
/* @__PURE__ */ jsx("div", { className: "divide-y rounded-lg border bg-white", children: items.map((item, index) => /* @__PURE__ */ jsxs("details", { className: "group p-4", children: [
|
|
2305
|
+
/* @__PURE__ */ jsx("summary", { className: "cursor-pointer text-sm font-medium text-neutral-950", children: settingContent(item.settings, "question") || settingContent(item.settings, "title") }),
|
|
2306
|
+
/* @__PURE__ */ jsx("p", { className: "mt-2 text-sm leading-6 text-neutral-600", children: settingContent(item.settings, "answer") || settingContent(item.settings, "content") })
|
|
2307
|
+
] }, getCmsBlockKey(item, index))) })
|
|
2308
|
+
] });
|
|
2309
|
+
}
|
|
2310
|
+
function boundedPercent(value) {
|
|
2311
|
+
if (!Number.isFinite(value)) {
|
|
2312
|
+
return 0;
|
|
2313
|
+
}
|
|
2314
|
+
return Math.min(Math.max(value, 0), 100);
|
|
2315
|
+
}
|
|
2316
|
+
function NewsletterSection({ section }) {
|
|
2317
|
+
const title = sectionTitleContent(section) || "Recibe novedades";
|
|
2318
|
+
const subtitle = settingContent(section.settings, "subtitle");
|
|
2319
|
+
const placeholder = settingString(section.settings, "placeholder") || "tu@email.com";
|
|
2320
|
+
const buttonText = settingContent(section.settings, "buttonText") || "Suscribirme";
|
|
2321
|
+
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: [
|
|
2322
|
+
/* @__PURE__ */ jsx("h2", { className: "text-3xl font-semibold", children: title }),
|
|
2323
|
+
subtitle ? /* @__PURE__ */ jsx("p", { className: "mt-3 text-white/70", children: subtitle }) : null,
|
|
2324
|
+
/* @__PURE__ */ jsxs("form", { className: "mt-6 flex flex-col gap-2 sm:flex-row", children: [
|
|
2325
|
+
/* @__PURE__ */ jsx(
|
|
2326
|
+
"input",
|
|
2327
|
+
{
|
|
2328
|
+
type: "email",
|
|
2329
|
+
placeholder,
|
|
2330
|
+
className: "h-10 flex-1 rounded-md border border-white/20 bg-white px-3 text-sm text-neutral-950 outline-none"
|
|
2331
|
+
}
|
|
2332
|
+
),
|
|
2333
|
+
/* @__PURE__ */ jsx(
|
|
2334
|
+
"button",
|
|
2335
|
+
{
|
|
2336
|
+
type: "submit",
|
|
2337
|
+
className: "h-10 rounded-md bg-white px-5 text-sm font-medium text-neutral-950",
|
|
2338
|
+
children: buttonText
|
|
2339
|
+
}
|
|
2340
|
+
)
|
|
2341
|
+
] })
|
|
2342
|
+
] }) });
|
|
2343
|
+
}
|
|
2344
|
+
function IconRowSection({
|
|
2345
|
+
section,
|
|
2346
|
+
linkComponent: LinkComponent
|
|
2347
|
+
}) {
|
|
2348
|
+
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-10", children: [
|
|
2349
|
+
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2350
|
+
/* @__PURE__ */ jsx("div", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-4", children: orderedBlocks(section.blocks).map((block, index) => {
|
|
2351
|
+
const settings = block.settings ?? {};
|
|
2352
|
+
const href = storefrontHref(settingString(settings, "linkUrl"));
|
|
2353
|
+
const content = /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-white p-4", children: [
|
|
2354
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-neutral-950", children: settingContent(settings, "title") || settingContent(settings, "label") }),
|
|
2355
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-neutral-600", children: settingContent(settings, "subtitle") || settingContent(settings, "description") })
|
|
2356
|
+
] });
|
|
2357
|
+
return href === "#" ? /* @__PURE__ */ jsx("div", { children: content }, getCmsBlockKey(block, index)) : /* @__PURE__ */ jsx(LinkComponent, { href, children: content }, getCmsBlockKey(block, index));
|
|
2358
|
+
}) })
|
|
2359
|
+
] });
|
|
2360
|
+
}
|
|
2361
|
+
function TestimonialsSection({
|
|
2362
|
+
section
|
|
2363
|
+
}) {
|
|
2364
|
+
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
|
|
2365
|
+
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2366
|
+
/* @__PURE__ */ jsx("div", { className: "grid gap-4 md:grid-cols-3", children: orderedBlocks(section.blocks).map((block, index) => /* @__PURE__ */ jsxs(
|
|
2367
|
+
"blockquote",
|
|
2368
|
+
{
|
|
2369
|
+
className: "rounded-lg border bg-white p-5",
|
|
2370
|
+
children: [
|
|
2371
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm leading-6 text-neutral-700", children: settingString(block.settings, "quote") || settingContent(block.settings, "content") || settingContent(block.settings, "text") }),
|
|
2372
|
+
/* @__PURE__ */ jsx("footer", { className: "mt-4 text-sm font-medium text-neutral-950", children: settingContent(block.settings, "author") || settingContent(block.settings, "name") })
|
|
2373
|
+
]
|
|
2374
|
+
},
|
|
2375
|
+
getCmsBlockKey(block, index)
|
|
2376
|
+
)) })
|
|
2377
|
+
] });
|
|
2378
|
+
}
|
|
2379
|
+
function StatsSection({ section }) {
|
|
2380
|
+
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
|
|
2381
|
+
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2382
|
+
/* @__PURE__ */ jsx("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4", children: orderedBlocks(section.blocks).map((block, index) => /* @__PURE__ */ jsxs(
|
|
2383
|
+
"div",
|
|
2384
|
+
{
|
|
2385
|
+
className: "rounded-lg border bg-white p-5",
|
|
2386
|
+
children: [
|
|
2387
|
+
/* @__PURE__ */ jsx("p", { className: "text-3xl font-semibold text-neutral-950", children: settingContent(block.settings, "value") }),
|
|
2388
|
+
/* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-neutral-600", children: settingContent(block.settings, "label") || settingContent(block.settings, "title") })
|
|
2389
|
+
]
|
|
2390
|
+
},
|
|
2391
|
+
getCmsBlockKey(block, index)
|
|
2392
|
+
)) })
|
|
2393
|
+
] });
|
|
2394
|
+
}
|
|
2395
|
+
function TimelineSection({ section }) {
|
|
2396
|
+
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
|
|
2397
|
+
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2398
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-4 border-l pl-5", children: orderedBlocks(section.blocks).map((block, index) => /* @__PURE__ */ jsxs("article", { className: "relative", children: [
|
|
2399
|
+
/* @__PURE__ */ jsx("span", { className: "absolute -left-[27px] top-1 size-3 rounded-full bg-neutral-950" }),
|
|
2400
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-neutral-950", children: settingContent(block.settings, "title") }),
|
|
2401
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-neutral-600", children: settingContent(block.settings, "description") || settingContent(block.settings, "content") })
|
|
2402
|
+
] }, getCmsBlockKey(block, index))) })
|
|
2403
|
+
] });
|
|
2404
|
+
}
|
|
2405
|
+
function ContactFormSection({ section }) {
|
|
2406
|
+
const fields = orderedBlocks(section.blocks);
|
|
2407
|
+
const submitText = settingString(section.settings, "submitText") || "Enviar";
|
|
2408
|
+
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
|
|
2409
|
+
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2410
|
+
/* @__PURE__ */ jsxs("form", { className: "mx-auto grid max-w-2xl gap-3", children: [
|
|
2411
|
+
(fields.length > 0 ? fields : defaultContactFields()).map(
|
|
2412
|
+
(field, index) => /* @__PURE__ */ jsx(ContactField, { field }, getCmsBlockKey(field, index))
|
|
2413
|
+
),
|
|
2414
|
+
/* @__PURE__ */ jsx("button", { className: "h-10 rounded-md bg-neutral-950 px-4 text-sm font-medium text-white", children: submitText })
|
|
2415
|
+
] })
|
|
2416
|
+
] });
|
|
2417
|
+
}
|
|
2418
|
+
function ContactField({ field }) {
|
|
2419
|
+
const type = settingString(field.settings, "type") || "text";
|
|
2420
|
+
const label = settingString(field.settings, "label");
|
|
2421
|
+
const placeholder = settingString(field.settings, "placeholder");
|
|
2422
|
+
const name = settingString(field.settings, "name");
|
|
2423
|
+
const className = "h-10 rounded-md border px-3 text-sm";
|
|
2424
|
+
if (type === "textarea") {
|
|
2425
|
+
return /* @__PURE__ */ jsx(
|
|
2426
|
+
"textarea",
|
|
2427
|
+
{
|
|
2428
|
+
name,
|
|
2429
|
+
"aria-label": label || placeholder,
|
|
2430
|
+
className: "min-h-32 rounded-md border px-3 py-2 text-sm",
|
|
2431
|
+
placeholder: placeholder || label
|
|
2432
|
+
}
|
|
2433
|
+
);
|
|
2434
|
+
}
|
|
2435
|
+
if (type === "select") {
|
|
2436
|
+
const rawOptions = field.settings?.options;
|
|
2437
|
+
const options = Array.isArray(rawOptions) ? rawOptions.filter((item) => typeof item === "string") : settingString(field.settings, "options").split("\n").map((item) => item.trim()).filter(Boolean);
|
|
2438
|
+
return /* @__PURE__ */ jsxs("select", { name, "aria-label": label, className, children: [
|
|
2439
|
+
/* @__PURE__ */ jsx("option", { value: "", children: placeholder || label }),
|
|
2440
|
+
options.map((option) => /* @__PURE__ */ jsx("option", { value: option, children: option }, option))
|
|
2441
|
+
] });
|
|
2442
|
+
}
|
|
2443
|
+
return /* @__PURE__ */ jsx(
|
|
2444
|
+
"input",
|
|
2445
|
+
{
|
|
2446
|
+
name,
|
|
2447
|
+
type,
|
|
2448
|
+
"aria-label": label || placeholder,
|
|
2449
|
+
className,
|
|
2450
|
+
placeholder: placeholder || label
|
|
2451
|
+
}
|
|
2452
|
+
);
|
|
2453
|
+
}
|
|
2454
|
+
function defaultContactFields() {
|
|
2455
|
+
return [
|
|
2456
|
+
{
|
|
2457
|
+
type: "field",
|
|
2458
|
+
order: 1,
|
|
2459
|
+
settings: { name: "fullName", type: "text", label: "Nombre" }
|
|
2460
|
+
},
|
|
2461
|
+
{
|
|
2462
|
+
type: "field",
|
|
2463
|
+
order: 2,
|
|
2464
|
+
settings: { name: "email", type: "email", label: "Email" }
|
|
2465
|
+
},
|
|
2466
|
+
{
|
|
2467
|
+
type: "field",
|
|
2468
|
+
order: 3,
|
|
2469
|
+
settings: { name: "message", type: "textarea", label: "Mensaje" }
|
|
2470
|
+
}
|
|
2471
|
+
];
|
|
2472
|
+
}
|
|
2473
|
+
function UnknownSection({ section }) {
|
|
2474
|
+
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: [
|
|
2475
|
+
'Seccion tipo "',
|
|
2476
|
+
section.type,
|
|
2477
|
+
'" pendiente de renderer.'
|
|
2478
|
+
] }) });
|
|
2479
|
+
}
|
|
2480
|
+
function AnnouncementBarSection({
|
|
2481
|
+
section,
|
|
2482
|
+
linkComponent: LinkComponent
|
|
2483
|
+
}) {
|
|
2484
|
+
const text = settingContent(section.settings, "text") || sectionTitleContent(section);
|
|
2485
|
+
const linkText = settingContent(section.settings, "linkText");
|
|
2486
|
+
const href = storefrontHref(settingString(section.settings, "linkUrl"));
|
|
2487
|
+
if (!text) {
|
|
2488
|
+
return null;
|
|
2489
|
+
}
|
|
2490
|
+
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: [
|
|
2491
|
+
/* @__PURE__ */ jsx("span", { children: text }),
|
|
2492
|
+
linkText && href !== "#" ? /* @__PURE__ */ jsx(
|
|
2493
|
+
LinkComponent,
|
|
2494
|
+
{
|
|
2495
|
+
href,
|
|
2496
|
+
className: "font-medium underline underline-offset-4",
|
|
2497
|
+
children: linkText
|
|
2498
|
+
}
|
|
2499
|
+
) : null
|
|
2500
|
+
] }) });
|
|
2501
|
+
}
|
|
2502
|
+
function HeroSection({
|
|
2503
|
+
section,
|
|
2504
|
+
linkComponent: LinkComponent
|
|
2505
|
+
}) {
|
|
2506
|
+
const slides = orderedBlocks(section.blocks);
|
|
2507
|
+
const fallbackSlide = {
|
|
2508
|
+
id: `${section.id ?? "section"}-fallback`,
|
|
2509
|
+
type: "slide",
|
|
2510
|
+
order: 1,
|
|
2511
|
+
settings: section.settings ?? {}
|
|
2512
|
+
};
|
|
2513
|
+
const visibleSlides = slides.length > 0 ? slides : [fallbackSlide];
|
|
2514
|
+
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) => {
|
|
2515
|
+
const settings = slide.settings ?? {};
|
|
2516
|
+
const imageUrl = settingString(settings, "imageUrl") || settingString(section.settings, "imageUrl") || DEFAULT_CMS_IMAGE_URL;
|
|
2517
|
+
const title = settingContent(settings, "title") || settingContent(section.settings, "title") || sectionTitleContent(section);
|
|
2518
|
+
const subtitle = settingContent(settings, "subtitle") || settingContent(section.settings, "subtitle");
|
|
2519
|
+
const ctaText = settingContent(settings, "ctaText") || settingContent(section.settings, "ctaText");
|
|
2520
|
+
const ctaUrl = settingString(settings, "ctaUrl") || settingString(section.settings, "ctaUrl");
|
|
2521
|
+
const href = storefrontHref(ctaUrl);
|
|
2522
|
+
return /* @__PURE__ */ jsxs(
|
|
2523
|
+
"article",
|
|
2524
|
+
{
|
|
2525
|
+
className: "relative min-h-[520px] w-full shrink-0 snap-start overflow-hidden",
|
|
2526
|
+
children: [
|
|
2527
|
+
/* @__PURE__ */ jsx(
|
|
2528
|
+
CmsImage,
|
|
2529
|
+
{
|
|
2530
|
+
src: imageUrl,
|
|
2531
|
+
alt: "",
|
|
2532
|
+
className: "absolute inset-0 h-full w-full object-cover opacity-75"
|
|
2533
|
+
}
|
|
2534
|
+
),
|
|
2535
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-r from-black/70 via-black/35 to-transparent" }),
|
|
2536
|
+
/* @__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: [
|
|
2537
|
+
/* @__PURE__ */ jsx("h1", { className: "text-4xl font-semibold tracking-tight md:text-6xl", children: title }),
|
|
2538
|
+
subtitle ? /* @__PURE__ */ jsx("p", { className: "mt-4 max-w-xl text-base text-white/85 md:text-lg", children: subtitle }) : null,
|
|
2539
|
+
ctaText && href !== "#" ? /* @__PURE__ */ jsx(
|
|
2540
|
+
LinkComponent,
|
|
2541
|
+
{
|
|
2542
|
+
href,
|
|
2543
|
+
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",
|
|
2544
|
+
children: ctaText
|
|
2545
|
+
}
|
|
2546
|
+
) : null
|
|
2547
|
+
] }) })
|
|
2548
|
+
]
|
|
2549
|
+
},
|
|
2550
|
+
getCmsBlockKey(slide, index)
|
|
2551
|
+
);
|
|
2552
|
+
}) }) });
|
|
2553
|
+
}
|
|
2554
|
+
function ProductsSection({
|
|
2555
|
+
section,
|
|
2556
|
+
products,
|
|
2557
|
+
carousel,
|
|
2558
|
+
linkComponent,
|
|
2559
|
+
currency,
|
|
2560
|
+
preview
|
|
2561
|
+
}) {
|
|
2562
|
+
const placeholders = preview && products.length === 0;
|
|
2563
|
+
const count = Math.min(
|
|
2564
|
+
productPreviewCount(section, carousel),
|
|
2565
|
+
carousel ? 5 : 8
|
|
2566
|
+
);
|
|
2567
|
+
return /* @__PURE__ */ jsxs("section", { className: carousel ? "py-12" : "container mx-auto px-4 py-12", children: [
|
|
2568
|
+
carousel ? /* @__PURE__ */ jsx("div", { className: "container mx-auto px-4", children: /* @__PURE__ */ jsx(SectionHeading, { section }) }) : /* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2569
|
+
/* @__PURE__ */ jsx("div", { className: carousel ? "container mx-auto overflow-x-auto px-4" : "", children: /* @__PURE__ */ jsx(
|
|
2570
|
+
"div",
|
|
2571
|
+
{
|
|
2572
|
+
className: carousel ? "flex min-w-full gap-4 pb-2" : "grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4",
|
|
2573
|
+
children: placeholders ? Array.from({ length: count }).map((_, index) => /* @__PURE__ */ jsx(ProductPlaceholder, { carousel }, index)) : products.map((product) => /* @__PURE__ */ jsx(
|
|
2574
|
+
ProductCard,
|
|
2575
|
+
{
|
|
2576
|
+
product,
|
|
2577
|
+
carousel,
|
|
2578
|
+
linkComponent,
|
|
2579
|
+
currency
|
|
2580
|
+
},
|
|
2581
|
+
product.id
|
|
2582
|
+
))
|
|
2583
|
+
}
|
|
2584
|
+
) }),
|
|
2585
|
+
!placeholders && products.length === 0 ? /* @__PURE__ */ jsx(EmptyState, { children: "No hay productos para mostrar." }) : null
|
|
2586
|
+
] });
|
|
2587
|
+
}
|
|
2588
|
+
function CategoryGridSection({
|
|
2589
|
+
section,
|
|
2590
|
+
collections,
|
|
2591
|
+
linkComponent: LinkComponent,
|
|
2592
|
+
preview
|
|
2593
|
+
}) {
|
|
2594
|
+
const blockItems = orderedBlocks(section.blocks).map((block) => {
|
|
2595
|
+
const settings = block.settings ?? {};
|
|
2596
|
+
const name = settingContent(settings, "name") || settingContent(settings, "title");
|
|
2597
|
+
const url = settingString(settings, "url") || settingString(settings, "linkUrl");
|
|
2598
|
+
const imageUrl = settingString(settings, "imageUrl");
|
|
2599
|
+
if (!name) {
|
|
2600
|
+
return null;
|
|
2601
|
+
}
|
|
2602
|
+
return {
|
|
2603
|
+
id: getCmsBlockKey(block, block.order),
|
|
2604
|
+
name,
|
|
2605
|
+
href: storefrontHref(url || "/collections"),
|
|
2606
|
+
imageUrl: imageUrl || DEFAULT_CMS_IMAGE_URL
|
|
2607
|
+
};
|
|
2608
|
+
}).filter(Boolean);
|
|
2609
|
+
const collectionItems = collections.map((collection) => ({
|
|
2610
|
+
id: collection.id,
|
|
2611
|
+
name: collection.name,
|
|
2612
|
+
href: `/store/collections/${collection.slug}`,
|
|
2613
|
+
imageUrl: collection.imageUrl || DEFAULT_CMS_IMAGE_URL
|
|
2614
|
+
}));
|
|
2615
|
+
const previewItems = preview ? createPreviewCollections(section) : [];
|
|
2616
|
+
const items = blockItems.length > 0 ? blockItems : collectionItems.length > 0 ? collectionItems : previewItems;
|
|
2617
|
+
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
|
|
2618
|
+
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2619
|
+
items.length > 0 ? /* @__PURE__ */ jsx("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3", children: items.map((item) => /* @__PURE__ */ jsxs(
|
|
2620
|
+
LinkComponent,
|
|
2621
|
+
{
|
|
2622
|
+
href: item.href,
|
|
2623
|
+
className: "group overflow-hidden rounded-lg border bg-white",
|
|
2624
|
+
children: [
|
|
2625
|
+
/* @__PURE__ */ jsx("div", { className: "aspect-[4/3] overflow-hidden bg-neutral-100", children: /* @__PURE__ */ jsx(
|
|
2626
|
+
CmsImage,
|
|
2627
|
+
{
|
|
2628
|
+
src: item.imageUrl,
|
|
2629
|
+
alt: "",
|
|
2630
|
+
className: "h-full w-full object-cover transition duration-300 group-hover:scale-105"
|
|
2631
|
+
}
|
|
2632
|
+
) }),
|
|
2633
|
+
/* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx("h3", { className: "text-base font-medium text-neutral-950", children: item.name }) })
|
|
2634
|
+
]
|
|
2635
|
+
},
|
|
2636
|
+
item.id
|
|
2637
|
+
)) }) : /* @__PURE__ */ jsx(EmptyState, { children: "No hay categorias para mostrar." })
|
|
2638
|
+
] });
|
|
2639
|
+
}
|
|
2640
|
+
function PromoCardsSection({
|
|
2641
|
+
section,
|
|
2642
|
+
linkComponent: LinkComponent
|
|
2643
|
+
}) {
|
|
2644
|
+
const cards = orderedBlocks(section.blocks);
|
|
2645
|
+
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
|
|
2646
|
+
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2647
|
+
/* @__PURE__ */ jsx("div", { className: "grid gap-4 md:grid-cols-2", children: cards.map((card, index) => {
|
|
2648
|
+
const settings = card.settings ?? {};
|
|
2649
|
+
const title = settingContent(settings, "title");
|
|
2650
|
+
const subtitle = settingContent(settings, "subtitle");
|
|
2651
|
+
const imageUrl = settingString(settings, "imageUrl") || DEFAULT_CMS_IMAGE_URL;
|
|
2652
|
+
const ctaText = settingContent(settings, "ctaText");
|
|
2653
|
+
const ctaUrl = storefrontHref(
|
|
2654
|
+
settingString(settings, "ctaUrl") || settingString(settings, "url")
|
|
2655
|
+
);
|
|
2656
|
+
return /* @__PURE__ */ jsxs(
|
|
2657
|
+
LinkComponent,
|
|
2658
|
+
{
|
|
2659
|
+
href: ctaUrl,
|
|
2660
|
+
className: "group relative min-h-[260px] overflow-hidden rounded-lg bg-neutral-900 text-white",
|
|
2661
|
+
children: [
|
|
2662
|
+
/* @__PURE__ */ jsx(
|
|
2663
|
+
CmsImage,
|
|
2664
|
+
{
|
|
2665
|
+
src: imageUrl,
|
|
2666
|
+
alt: "",
|
|
2667
|
+
className: "absolute inset-0 h-full w-full object-cover opacity-75 transition duration-300 group-hover:scale-105"
|
|
2668
|
+
}
|
|
2669
|
+
),
|
|
2670
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/35" }),
|
|
2671
|
+
/* @__PURE__ */ jsxs("div", { className: "relative z-10 flex min-h-[260px] flex-col justify-end p-6", children: [
|
|
2672
|
+
/* @__PURE__ */ jsx("h3", { className: "text-2xl font-semibold", children: title }),
|
|
2673
|
+
subtitle ? /* @__PURE__ */ jsx("p", { className: "mt-2 text-white/85", children: subtitle }) : null,
|
|
2674
|
+
ctaText ? /* @__PURE__ */ jsx("span", { className: "mt-4 text-sm font-medium", children: ctaText }) : null
|
|
2675
|
+
] })
|
|
2676
|
+
]
|
|
2677
|
+
},
|
|
2678
|
+
getCmsBlockKey(card, index)
|
|
2679
|
+
);
|
|
2680
|
+
}) })
|
|
2681
|
+
] });
|
|
2682
|
+
}
|
|
2683
|
+
function LogoSliderSection({
|
|
2684
|
+
section,
|
|
2685
|
+
linkComponent: LinkComponent
|
|
2686
|
+
}) {
|
|
2687
|
+
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-10", children: [
|
|
2688
|
+
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2689
|
+
/* @__PURE__ */ jsx("div", { className: "flex gap-4 overflow-x-auto", children: orderedBlocks(section.blocks).map((block, index) => {
|
|
2690
|
+
const settings = block.settings ?? {};
|
|
2691
|
+
const imageUrl = settingString(settings, "imageUrl") || DEFAULT_CMS_IMAGE_URL;
|
|
2692
|
+
const alt = settingString(settings, "alt") || "Logo";
|
|
2693
|
+
const href = storefrontHref(settingString(settings, "linkUrl"));
|
|
2694
|
+
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(
|
|
2695
|
+
CmsImage,
|
|
2696
|
+
{
|
|
2697
|
+
src: imageUrl,
|
|
2698
|
+
alt,
|
|
2699
|
+
className: "max-h-full max-w-full object-contain"
|
|
2700
|
+
}
|
|
2701
|
+
) });
|
|
2702
|
+
return href !== "#" ? /* @__PURE__ */ jsx(LinkComponent, { href, children: logo }, getCmsBlockKey(block, index)) : /* @__PURE__ */ jsx("div", { children: logo }, getCmsBlockKey(block, index));
|
|
2703
|
+
}) })
|
|
2704
|
+
] });
|
|
2705
|
+
}
|
|
2706
|
+
function ProductCard({
|
|
2707
|
+
product,
|
|
2708
|
+
carousel,
|
|
2709
|
+
linkComponent: LinkComponent,
|
|
2710
|
+
currency
|
|
2711
|
+
}) {
|
|
2712
|
+
const onSale = product.compareAtPrice != null && product.compareAtPrice > product.price;
|
|
2713
|
+
return /* @__PURE__ */ jsxs(
|
|
2714
|
+
LinkComponent,
|
|
2715
|
+
{
|
|
2716
|
+
href: `/product/${product.slug}`,
|
|
2717
|
+
className: carousel ? "group w-[220px] shrink-0 sm:w-[250px] md:w-[280px]" : "group",
|
|
2718
|
+
children: [
|
|
2719
|
+
/* @__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(
|
|
2720
|
+
CmsImage,
|
|
2721
|
+
{
|
|
2722
|
+
src: product.imageUrl || DEFAULT_CMS_IMAGE_URL,
|
|
2723
|
+
alt: product.name,
|
|
2724
|
+
className: "h-full w-full object-cover object-center transition-transform duration-500 group-hover:scale-105"
|
|
2725
|
+
}
|
|
2726
|
+
) }),
|
|
2727
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-4 flex flex-col", children: [
|
|
2728
|
+
/* @__PURE__ */ jsx("h3", { className: "line-clamp-2 text-sm font-medium text-neutral-950", children: product.name }),
|
|
2729
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-2", children: [
|
|
2730
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-neutral-950", children: formatCurrency(product.price, currency) }),
|
|
2731
|
+
onSale ? /* @__PURE__ */ jsx("span", { className: "text-sm text-neutral-500 line-through", children: formatCurrency(product.compareAtPrice ?? 0, currency) }) : null
|
|
2732
|
+
] })
|
|
2733
|
+
] })
|
|
2734
|
+
]
|
|
2735
|
+
}
|
|
2736
|
+
);
|
|
2737
|
+
}
|
|
2738
|
+
function ProductPlaceholder({ carousel }) {
|
|
2739
|
+
return /* @__PURE__ */ jsxs(
|
|
2740
|
+
"div",
|
|
2741
|
+
{
|
|
2742
|
+
className: carousel ? "w-[220px] shrink-0 sm:w-[250px] md:w-[280px]" : "",
|
|
2743
|
+
children: [
|
|
2744
|
+
/* @__PURE__ */ jsx("div", { className: "aspect-square rounded-lg bg-neutral-100" }),
|
|
2745
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4 h-3 w-3/4 rounded bg-neutral-200" }),
|
|
2746
|
+
/* @__PURE__ */ jsx("div", { className: "mt-2 h-3 w-1/2 rounded bg-neutral-100" })
|
|
2747
|
+
]
|
|
2748
|
+
}
|
|
2749
|
+
);
|
|
2750
|
+
}
|
|
2751
|
+
function productPreviewCount(section, carousel) {
|
|
2752
|
+
const configuredBlocks = orderedBlocks(section.blocks).length;
|
|
2753
|
+
if (configuredBlocks > 0) {
|
|
2754
|
+
return configuredBlocks;
|
|
2755
|
+
}
|
|
2756
|
+
return settingNumber(section.settings, "limit", carousel ? 5 : 8);
|
|
2757
|
+
}
|
|
2758
|
+
function createPreviewCollections(section) {
|
|
2759
|
+
const count = Math.min(settingNumber(section.settings, "limit", 6), 6);
|
|
2760
|
+
return Array.from({ length: count }, (_, index) => ({
|
|
2761
|
+
id: `preview-collection-${index + 1}`,
|
|
2762
|
+
name: `Categoria ${index + 1}`,
|
|
2763
|
+
href: "/store/collections/all",
|
|
2764
|
+
imageUrl: DEFAULT_CMS_IMAGE_URL
|
|
2765
|
+
}));
|
|
2766
|
+
}
|
|
2767
|
+
function LayoutSection({ section, renderSections }) {
|
|
2768
|
+
const settings = section.settings ?? {};
|
|
2769
|
+
const paddingY = settingString(settings, "paddingY") || "medium";
|
|
2770
|
+
const maxWidth = settingString(settings, "maxWidth") || "container";
|
|
2771
|
+
const background = settingString(settings, "background") || "default";
|
|
2772
|
+
return /* @__PURE__ */ jsx(
|
|
2773
|
+
"section",
|
|
2774
|
+
{
|
|
2775
|
+
className: `${layoutBackground(background)} ${layoutPadding(paddingY)}`,
|
|
2776
|
+
children: /* @__PURE__ */ jsx("div", { className: `mx-auto px-4 ${layoutMaxWidth(maxWidth)}`, children: renderSections(layoutChildren(settings, "content")) })
|
|
2777
|
+
}
|
|
2778
|
+
);
|
|
2779
|
+
}
|
|
2780
|
+
function LayoutGrid({ section, renderSections }) {
|
|
2781
|
+
const settings = section.settings ?? {};
|
|
2782
|
+
const columnCount = Math.min(
|
|
2783
|
+
Math.max(Math.round(settingNumber(settings, "columnCount", 2)), 1),
|
|
2784
|
+
6
|
|
2785
|
+
);
|
|
2786
|
+
return /* @__PURE__ */ jsx(
|
|
2787
|
+
"div",
|
|
2788
|
+
{
|
|
2789
|
+
className: `grid ${layoutGap(settingString(settings, "gap"))}`,
|
|
2790
|
+
style: {
|
|
2791
|
+
gridTemplateColumns: `repeat(${columnCount}, minmax(0, 1fr))`
|
|
2792
|
+
},
|
|
2793
|
+
children: renderSections(layoutChildren(settings, "content"))
|
|
2794
|
+
}
|
|
2795
|
+
);
|
|
2796
|
+
}
|
|
2797
|
+
function LayoutFlex({ section, renderSections }) {
|
|
2798
|
+
const settings = section.settings ?? {};
|
|
2799
|
+
return /* @__PURE__ */ jsx(
|
|
2800
|
+
"div",
|
|
2801
|
+
{
|
|
2802
|
+
className: [
|
|
2803
|
+
"flex",
|
|
2804
|
+
settingString(settings, "direction") === "column" ? "flex-col" : "flex-col md:flex-row",
|
|
2805
|
+
settingString(settings, "wrap") === "nowrap" ? "flex-nowrap" : "flex-wrap",
|
|
2806
|
+
layoutGap(settingString(settings, "gap")),
|
|
2807
|
+
layoutAlign(settingString(settings, "align")),
|
|
2808
|
+
layoutJustify(settingString(settings, "justify"))
|
|
2809
|
+
].join(" "),
|
|
2810
|
+
children: renderSections(layoutChildren(settings, "content"))
|
|
2811
|
+
}
|
|
2812
|
+
);
|
|
2813
|
+
}
|
|
2814
|
+
function LayoutSpace({ section }) {
|
|
2815
|
+
const settings = section.settings ?? {};
|
|
2816
|
+
const size = settingString(settings, "size") || "24px";
|
|
2817
|
+
const direction = settingString(settings, "direction") || "vertical";
|
|
2818
|
+
const isHorizontal = direction === "horizontal";
|
|
2819
|
+
const isBoth = direction === "both";
|
|
2820
|
+
return /* @__PURE__ */ jsx(
|
|
2821
|
+
"div",
|
|
2822
|
+
{
|
|
2823
|
+
"aria-hidden": "true",
|
|
2824
|
+
style: {
|
|
2825
|
+
display: "block",
|
|
2826
|
+
width: isHorizontal || isBoth ? size : "100%",
|
|
2827
|
+
height: isHorizontal ? "100%" : size
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
);
|
|
2831
|
+
}
|
|
2832
|
+
function CmsSectionsRenderer({
|
|
2833
|
+
sections,
|
|
2834
|
+
sectionData,
|
|
2835
|
+
linkComponent,
|
|
2836
|
+
currency = "PEN",
|
|
2837
|
+
preview = false,
|
|
2838
|
+
wrap = true
|
|
2839
|
+
}) {
|
|
2840
|
+
const LinkComponent = linkComponent ?? DefaultLink;
|
|
2841
|
+
const sortedSections = [...sections].sort((a, b) => a.order - b.order);
|
|
2842
|
+
const content = /* @__PURE__ */ jsx(Fragment, { children: sortedSections.map((section, index) => {
|
|
2843
|
+
const sectionKey = getCmsSectionKey(section, index);
|
|
2844
|
+
return /* @__PURE__ */ jsx(
|
|
2845
|
+
CmsSection,
|
|
2846
|
+
{
|
|
2847
|
+
section,
|
|
2848
|
+
data: sectionData?.[sectionKey],
|
|
2849
|
+
linkComponent: LinkComponent,
|
|
2850
|
+
currency,
|
|
2851
|
+
preview
|
|
2852
|
+
},
|
|
2853
|
+
sectionKey
|
|
2854
|
+
);
|
|
2855
|
+
}) });
|
|
2856
|
+
return wrap ? /* @__PURE__ */ jsx("div", { className: "relative", children: content }) : content;
|
|
2857
|
+
}
|
|
2858
|
+
function CmsSection({
|
|
2859
|
+
section,
|
|
2860
|
+
data,
|
|
2861
|
+
linkComponent,
|
|
2862
|
+
currency,
|
|
2863
|
+
preview
|
|
2864
|
+
}) {
|
|
2865
|
+
const type = canonicalSectionType(section.type);
|
|
2866
|
+
const renderSections = (sections) => /* @__PURE__ */ jsx(
|
|
2867
|
+
CmsSectionsRenderer,
|
|
2868
|
+
{
|
|
2869
|
+
sections,
|
|
2870
|
+
linkComponent,
|
|
2871
|
+
currency,
|
|
2872
|
+
preview,
|
|
2873
|
+
wrap: false
|
|
2874
|
+
}
|
|
2875
|
+
);
|
|
2876
|
+
if (type === "layout-section") {
|
|
2877
|
+
return /* @__PURE__ */ jsx(
|
|
2878
|
+
LayoutSection,
|
|
2879
|
+
{
|
|
2880
|
+
section,
|
|
2881
|
+
linkComponent,
|
|
2882
|
+
currency,
|
|
2883
|
+
preview,
|
|
2884
|
+
renderSections
|
|
2885
|
+
}
|
|
2886
|
+
);
|
|
2887
|
+
}
|
|
2888
|
+
if (type === "layout-grid") {
|
|
2889
|
+
return /* @__PURE__ */ jsx(
|
|
2890
|
+
LayoutGrid,
|
|
2891
|
+
{
|
|
2892
|
+
section,
|
|
2893
|
+
linkComponent,
|
|
2894
|
+
currency,
|
|
2895
|
+
preview,
|
|
2896
|
+
renderSections
|
|
2897
|
+
}
|
|
2898
|
+
);
|
|
2899
|
+
}
|
|
2900
|
+
if (type === "layout-flex") {
|
|
2901
|
+
return /* @__PURE__ */ jsx(
|
|
2902
|
+
LayoutFlex,
|
|
2903
|
+
{
|
|
2904
|
+
section,
|
|
2905
|
+
linkComponent,
|
|
2906
|
+
currency,
|
|
2907
|
+
preview,
|
|
2908
|
+
renderSections
|
|
2909
|
+
}
|
|
2910
|
+
);
|
|
2911
|
+
}
|
|
2912
|
+
if (type === "layout-space") {
|
|
2913
|
+
return /* @__PURE__ */ jsx(
|
|
2914
|
+
LayoutSpace,
|
|
2915
|
+
{
|
|
2916
|
+
section,
|
|
2917
|
+
linkComponent,
|
|
2918
|
+
currency,
|
|
2919
|
+
preview,
|
|
2920
|
+
renderSections
|
|
2921
|
+
}
|
|
2922
|
+
);
|
|
2923
|
+
}
|
|
2924
|
+
if (type === "hero") {
|
|
2925
|
+
return /* @__PURE__ */ jsx(HeroSection, { section, linkComponent });
|
|
2926
|
+
}
|
|
2927
|
+
if (type === "announcement-bar") {
|
|
2928
|
+
return /* @__PURE__ */ jsx(AnnouncementBarSection, { section, linkComponent });
|
|
2929
|
+
}
|
|
2930
|
+
if (type === "product-list" || type === "product-carousel") {
|
|
2931
|
+
return /* @__PURE__ */ jsx(
|
|
2932
|
+
ProductsSection,
|
|
2933
|
+
{
|
|
2934
|
+
section,
|
|
2935
|
+
products: data?.products ?? [],
|
|
2936
|
+
carousel: type === "product-carousel",
|
|
2937
|
+
linkComponent,
|
|
2938
|
+
currency,
|
|
2939
|
+
preview
|
|
2940
|
+
}
|
|
2941
|
+
);
|
|
2942
|
+
}
|
|
2943
|
+
if (type === "category-grid" || type === "collection-list") {
|
|
2944
|
+
return /* @__PURE__ */ jsx(
|
|
2945
|
+
CategoryGridSection,
|
|
2946
|
+
{
|
|
2947
|
+
section,
|
|
2948
|
+
collections: data?.collections ?? [],
|
|
2949
|
+
linkComponent,
|
|
2950
|
+
preview
|
|
2951
|
+
}
|
|
2952
|
+
);
|
|
2953
|
+
}
|
|
2954
|
+
if (type === "promo-cards") {
|
|
2955
|
+
return /* @__PURE__ */ jsx(PromoCardsSection, { section, linkComponent });
|
|
2956
|
+
}
|
|
2957
|
+
if (type === "rich-text" || type === "seo-text") {
|
|
2958
|
+
return /* @__PURE__ */ jsx(RichTextSection, { section });
|
|
2959
|
+
}
|
|
2960
|
+
if (type === "custom-html") {
|
|
2961
|
+
return /* @__PURE__ */ jsx(CustomHtmlSection, { section });
|
|
2962
|
+
}
|
|
2963
|
+
if (type === "floating-block") {
|
|
2964
|
+
return /* @__PURE__ */ jsx(FloatingBlockSection, { section, linkComponent });
|
|
2965
|
+
}
|
|
2966
|
+
if (type === "faq") {
|
|
2967
|
+
return /* @__PURE__ */ jsx(FaqSection, { section });
|
|
2968
|
+
}
|
|
2969
|
+
if (type === "newsletter") {
|
|
2970
|
+
return /* @__PURE__ */ jsx(NewsletterSection, { section });
|
|
2971
|
+
}
|
|
2972
|
+
if (type === "trust-badges" || type === "widget-row") {
|
|
2973
|
+
return /* @__PURE__ */ jsx(IconRowSection, { section, linkComponent });
|
|
2974
|
+
}
|
|
2975
|
+
if (type === "logo-slider") {
|
|
2976
|
+
return /* @__PURE__ */ jsx(LogoSliderSection, { section, linkComponent });
|
|
2977
|
+
}
|
|
2978
|
+
if (type === "testimonials") {
|
|
2979
|
+
return /* @__PURE__ */ jsx(TestimonialsSection, { section });
|
|
2980
|
+
}
|
|
2981
|
+
if (type === "stats") {
|
|
2982
|
+
return /* @__PURE__ */ jsx(StatsSection, { section });
|
|
2983
|
+
}
|
|
2984
|
+
if (type === "timeline") {
|
|
2985
|
+
return /* @__PURE__ */ jsx(TimelineSection, { section });
|
|
2986
|
+
}
|
|
2987
|
+
if (type === "contact-form") {
|
|
2988
|
+
return /* @__PURE__ */ jsx(ContactFormSection, { section });
|
|
2989
|
+
}
|
|
2990
|
+
return /* @__PURE__ */ jsx(UnknownSection, { section });
|
|
2991
|
+
}
|
|
2992
|
+
function buildOptionGroups(variants) {
|
|
2993
|
+
const map = /* @__PURE__ */ new Map();
|
|
2994
|
+
for (const v of variants) {
|
|
2995
|
+
for (const opt of v.options ?? []) {
|
|
2996
|
+
const key = opt.key;
|
|
2997
|
+
const name = opt.name ?? key;
|
|
2998
|
+
if (!map.has(key)) map.set(key, /* @__PURE__ */ new Map());
|
|
2999
|
+
map.get(key).set(opt.value, name);
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
return Array.from(map.entries()).map(([key, valueMap]) => ({
|
|
3003
|
+
key,
|
|
3004
|
+
name: Array.from(valueMap.values())[0] ?? key,
|
|
3005
|
+
values: Array.from(valueMap.keys())
|
|
3006
|
+
}));
|
|
3007
|
+
}
|
|
3008
|
+
function findVariant(variants, selected, hasConfigurableOptions) {
|
|
3009
|
+
if (!hasConfigurableOptions && variants.length > 0) {
|
|
3010
|
+
return variants[0] ?? null;
|
|
3011
|
+
}
|
|
3012
|
+
if (Object.keys(selected).length === 0) return null;
|
|
3013
|
+
for (const v of variants) {
|
|
3014
|
+
const opts = v.options ?? [];
|
|
3015
|
+
const match = opts.length > 0 && opts.every((o) => selected[o.key] === o.value);
|
|
3016
|
+
if (match) return v;
|
|
3017
|
+
}
|
|
3018
|
+
return null;
|
|
3019
|
+
}
|
|
3020
|
+
function getInitialOptions(variants, optionGroups) {
|
|
3021
|
+
const first = variants[0];
|
|
3022
|
+
if (!first) return {};
|
|
3023
|
+
const opts = first.options ?? [];
|
|
3024
|
+
const selected = {};
|
|
3025
|
+
for (const g of optionGroups) {
|
|
3026
|
+
const o = opts.find((x) => x.key === g.key);
|
|
3027
|
+
if (o) selected[g.key] = o.value;
|
|
3028
|
+
}
|
|
3029
|
+
return selected;
|
|
3030
|
+
}
|
|
3031
|
+
function ProductVariantSelector({
|
|
3032
|
+
product,
|
|
3033
|
+
currency = "USD",
|
|
3034
|
+
features = [],
|
|
3035
|
+
onVariantChange,
|
|
3036
|
+
children
|
|
3037
|
+
}) {
|
|
3038
|
+
const variants = useMemo(() => product.variants ?? [], [product.variants]);
|
|
3039
|
+
const optionGroups = useMemo(() => buildOptionGroups(variants), [variants]);
|
|
3040
|
+
const hasConfigurableOptions = optionGroups.length > 0;
|
|
3041
|
+
const [selectedOptions, setSelectedOptions] = useState(
|
|
3042
|
+
() => getInitialOptions(variants, optionGroups)
|
|
3043
|
+
);
|
|
3044
|
+
const selectedVariant = useMemo(
|
|
3045
|
+
() => findVariant(variants, selectedOptions, hasConfigurableOptions),
|
|
3046
|
+
[variants, selectedOptions, hasConfigurableOptions]
|
|
3047
|
+
);
|
|
3048
|
+
const displayPrice = selectedVariant?.price ?? product.price ?? 0;
|
|
3049
|
+
const compareAtPrice = selectedVariant?.compareAtPrice ?? product.compareAtPrice;
|
|
3050
|
+
const isAvailable = (selectedVariant ? (selectedVariant.quantity ?? 0) > 0 : product.isAvailable) ?? true;
|
|
3051
|
+
useEffect(() => {
|
|
3052
|
+
onVariantChange?.(selectedVariant, displayPrice);
|
|
3053
|
+
}, [selectedVariant, displayPrice, onVariantChange]);
|
|
3054
|
+
const setOption = useCallback((key, value) => {
|
|
3055
|
+
setSelectedOptions((prev) => ({ ...prev, [key]: value }));
|
|
3056
|
+
}, []);
|
|
3057
|
+
const hasVariants = hasConfigurableOptions;
|
|
3058
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
|
|
3059
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2 flex-wrap", children: [
|
|
3060
|
+
/* @__PURE__ */ jsx(
|
|
3061
|
+
"span",
|
|
3062
|
+
{
|
|
3063
|
+
className: "inline-flex items-center rounded-md bg-primary/10 px-2.5 py-0.5 text-base font-semibold text-primary",
|
|
3064
|
+
"data-testid": "product-display-price",
|
|
3065
|
+
children: formatCurrency$1(displayPrice, currency)
|
|
3066
|
+
}
|
|
3067
|
+
),
|
|
3068
|
+
compareAtPrice != null && compareAtPrice > displayPrice && /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground line-through", children: formatCurrency$1(compareAtPrice, currency) })
|
|
3069
|
+
] }),
|
|
3070
|
+
hasVariants && optionGroups.map((group) => /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
3071
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: group.name }),
|
|
3072
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: group.values.map((value) => {
|
|
3073
|
+
const isSelected = selectedOptions[group.key] === value;
|
|
3074
|
+
const isColorLike = group.key.toLowerCase().includes("color") || group.key.toLowerCase().includes("colour");
|
|
3075
|
+
return /* @__PURE__ */ jsx(
|
|
3076
|
+
"button",
|
|
3077
|
+
{
|
|
3078
|
+
type: "button",
|
|
3079
|
+
onClick: () => setOption(group.key, value),
|
|
3080
|
+
className: isColorLike ? `min-w-[72px] rounded-md border-2 px-3 py-2 text-sm font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 ${isSelected ? "border-primary bg-primary text-foreground" : "border-border bg-muted/30 text-foreground hover:border-muted-foreground/50"}` : `rounded-md border px-3 py-2 text-sm font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 ${isSelected ? "border-primary bg-muted ring-1 ring-primary" : "border-border bg-transparent text-muted-foreground hover:border-muted-foreground/50 hover:text-foreground"}`,
|
|
3081
|
+
style: isColorLike && isSelected && value.toLowerCase() === "black" ? { backgroundColor: "#1a1a1a", borderColor: "#1a1a1a", color: "#fff" } : isColorLike && value.toLowerCase() === "white" ? { backgroundColor: "#fafafa", color: "#1a1a1a", borderColor: "#e5e5e5" } : void 0,
|
|
3082
|
+
"data-testid": `variant-option-${group.key}-${value}`,
|
|
3083
|
+
children: value
|
|
3084
|
+
},
|
|
3085
|
+
value
|
|
3086
|
+
);
|
|
3087
|
+
}) })
|
|
3088
|
+
] }, group.key)),
|
|
3089
|
+
features.length > 0 && /* @__PURE__ */ jsx("ul", { className: "list-disc list-inside space-y-1 text-sm text-muted-foreground", children: features.map((f, i) => /* @__PURE__ */ jsx("li", { children: f }, i)) }),
|
|
3090
|
+
children?.({
|
|
3091
|
+
product,
|
|
3092
|
+
selectedVariant,
|
|
3093
|
+
displayPrice,
|
|
3094
|
+
compareAtPrice,
|
|
3095
|
+
isAvailable,
|
|
3096
|
+
selectedOptions
|
|
3097
|
+
})
|
|
3098
|
+
] });
|
|
3099
|
+
}
|
|
3100
|
+
function SafeThemeInjector({ theme, className }) {
|
|
3101
|
+
try {
|
|
3102
|
+
if (!theme || typeof theme !== "object") {
|
|
3103
|
+
console.warn("ThemeInjector: Invalid theme provided");
|
|
3104
|
+
return null;
|
|
3105
|
+
}
|
|
3106
|
+
if (!theme.colors || typeof theme.colors !== "object") {
|
|
3107
|
+
console.warn("ThemeInjector: Theme colors are required");
|
|
3108
|
+
return null;
|
|
3109
|
+
}
|
|
3110
|
+
const generateSafeCSSVariables = () => {
|
|
3111
|
+
const cssRules = [":root {"];
|
|
3112
|
+
const toKebabCase = (input) => input.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/_/g, "-").toLowerCase();
|
|
3113
|
+
const sanitizeCSSValue = (value) => {
|
|
3114
|
+
if (typeof value !== "string") return null;
|
|
3115
|
+
const trimmed = value.trim();
|
|
3116
|
+
if (!trimmed) return null;
|
|
3117
|
+
const isValidCSSValue = /^[a-zA-Z0-9\s,()#.-]+$/.test(trimmed);
|
|
3118
|
+
return isValidCSSValue ? trimmed : null;
|
|
3119
|
+
};
|
|
3120
|
+
if (theme.colors && typeof theme.colors === "object") {
|
|
3121
|
+
Object.entries(theme.colors).forEach(([key, value]) => {
|
|
3122
|
+
const sanitizedValue = sanitizeCSSValue(value);
|
|
3123
|
+
if (sanitizedValue) {
|
|
3124
|
+
cssRules.push(` --color-${key}: ${sanitizedValue};`);
|
|
3125
|
+
cssRules.push(` --theme-${key}: ${sanitizedValue};`);
|
|
3126
|
+
cssRules.push(` --${key}: ${sanitizedValue};`);
|
|
3127
|
+
cssRules.push(` --${toKebabCase(key)}: ${sanitizedValue};`);
|
|
3128
|
+
}
|
|
3129
|
+
});
|
|
3130
|
+
}
|
|
3131
|
+
if (theme.fonts && typeof theme.fonts === "object") {
|
|
3132
|
+
Object.entries(theme.fonts).forEach(([key, value]) => {
|
|
3133
|
+
const sanitizedValue = sanitizeCSSValue(value);
|
|
3134
|
+
if (sanitizedValue) {
|
|
3135
|
+
cssRules.push(` --font-${key}: ${sanitizedValue};`);
|
|
3136
|
+
}
|
|
3137
|
+
});
|
|
3138
|
+
}
|
|
3139
|
+
if (theme.spacing && typeof theme.spacing === "object") {
|
|
3140
|
+
Object.entries(theme.spacing).forEach(([key, value]) => {
|
|
3141
|
+
const sanitizedValue = sanitizeCSSValue(value);
|
|
3142
|
+
if (sanitizedValue) {
|
|
3143
|
+
cssRules.push(` --spacing-${key}: ${sanitizedValue};`);
|
|
3144
|
+
}
|
|
3145
|
+
});
|
|
3146
|
+
}
|
|
3147
|
+
if (theme.borderRadius && typeof theme.borderRadius === "object") {
|
|
3148
|
+
Object.entries(theme.borderRadius).forEach(([key, value]) => {
|
|
3149
|
+
const sanitizedValue = sanitizeCSSValue(value);
|
|
3150
|
+
if (sanitizedValue) {
|
|
3151
|
+
cssRules.push(` --radius-${key}: ${sanitizedValue};`);
|
|
3152
|
+
}
|
|
3153
|
+
});
|
|
3154
|
+
}
|
|
3155
|
+
if (theme.shadows && typeof theme.shadows === "object") {
|
|
3156
|
+
Object.entries(theme.shadows).forEach(([key, value]) => {
|
|
3157
|
+
const sanitizedValue = sanitizeCSSValue(value);
|
|
3158
|
+
if (sanitizedValue) {
|
|
3159
|
+
cssRules.push(` --shadow-${key}: ${sanitizedValue};`);
|
|
3160
|
+
}
|
|
3161
|
+
});
|
|
3162
|
+
}
|
|
3163
|
+
cssRules.push("}");
|
|
3164
|
+
return cssRules.join("\n");
|
|
3165
|
+
};
|
|
3166
|
+
const cssVariables = generateSafeCSSVariables();
|
|
3167
|
+
return /* @__PURE__ */ jsx(
|
|
3168
|
+
"style",
|
|
3169
|
+
{
|
|
3170
|
+
dangerouslySetInnerHTML: { __html: cssVariables },
|
|
3171
|
+
"data-theme-injector": theme.id,
|
|
3172
|
+
"data-theme-name": theme.name,
|
|
3173
|
+
className,
|
|
3174
|
+
suppressHydrationWarning: true
|
|
3175
|
+
}
|
|
3176
|
+
);
|
|
3177
|
+
} catch (error) {
|
|
3178
|
+
console.error("ThemeInjector: Error generating theme styles", error);
|
|
3179
|
+
return null;
|
|
3180
|
+
}
|
|
3181
|
+
}
|
|
3182
|
+
function isRenderableCmsPage(p) {
|
|
3183
|
+
if (!p.status) return true;
|
|
3184
|
+
return p.status === "published";
|
|
3185
|
+
}
|
|
3186
|
+
function findStorefrontCmsPageBySlug(settings, slug) {
|
|
3187
|
+
const pages = settings?.cms?.pages;
|
|
3188
|
+
if (!pages?.length) return null;
|
|
3189
|
+
const raw = pages.find(
|
|
3190
|
+
(p) => p.slug === slug && isRenderableCmsPage(p)
|
|
3191
|
+
);
|
|
3192
|
+
if (!raw) return null;
|
|
3193
|
+
const parsed = StorefrontPageDetailSchema$1.safeParse(raw);
|
|
3194
|
+
return parsed.success ? parsed.data : null;
|
|
3195
|
+
}
|
|
3196
|
+
|
|
3197
|
+
export { CartAddressesRequestSchema, CartBuyerRequestSchema, CartCheckoutPaymentActionSchema, CartCheckoutPaymentSchema, CartCheckoutReadResponseSchema, CartCheckoutRequestSchema, CartCheckoutResponseSchema, CartCouponRequestSchema, CartCreateRequestSchema, CartItemModifierRequestSchema, CartItemRequestSchema, CartPaymentMethodSchema, CartPaymentMethodsResponseSchema, CartPaymentReceiptResponseSchema, CartResponseBundleItemSchema, CartResponseItemSchema, CartResponseSchema, CartShippingMethodPutRequestSchema, CmsSectionsRenderer, DEFAULT_CMS_IMAGE_URL, ProductSchema, ProductVariantSchema, ProductVariantSelector, ProductsFiltersSchema, ProductsResponseSchema, QueryProvider, STOREFRONT_API_PATH_PREFIX, STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME, STOREFRONT_ECOMIQ_OAUTH_COOKIE_PATH, SafeThemeInjector, ShippingOptionGroupSchema, ShippingOptionsResponseSchema, ShippingRateSchema, StorefrontAuthProvider, StorefrontBundleItemSchema, StorefrontCheckoutSettingsSchema, StorefrontCollectionDetailSchema, StorefrontCollectionSchema, StorefrontCollectionsResponseSchema, StorefrontPageDetailSchema, StorefrontPageListItemSchema, StorefrontPriceTierSchema, StorefrontProductDetailSchema, StorefrontProductSchema, StorefrontProductsParamsSchema, StorefrontProductsResponseSchema, StorefrontSettingsLegacyFlatSchema, StorefrontSettingsSchema, StorefrontStoreSchema, apiClient, canonicalSectionType, cartService, collectionService, countryCurrency, customerOrderStatusTone, ecomiqOAuthPassword, ecomiqOAuthPasswordClient, fetchStorefrontGeoDistricts, fetchStorefrontGeoProvinces, findStorefrontCmsPageBySlug, formatCurrency, formatCustomerOrderStatus, formatOrderDate, formatOrderDateTime, getCmsSectionKey, loadStorefrontGeoDepartments, normalizeStorefrontSettingsPayload, pageService, productService, productSortValue, resolveIneiCodesFromLabels, sanitizeHtml, storeService, storefrontAccessTokenNeedsRefresh, storefrontFaviconUrl, storefrontHref, storefrontOgImageUrl, storefrontSessionEndsSoon, storefrontStoreRecord, toGeoItems, useCart, useCartAddresses, useCartCreate, useCartGet, useCollections, useConfig, usePages, useProducts, useStore, useStorefrontAuthClient, useStorefrontGeoInei, useStorefrontSession, useUser };
|
|
3198
|
+
//# sourceMappingURL=react.js.map
|
|
3199
|
+
//# sourceMappingURL=react.js.map
|