ng-easycommerce-v18 0.2.29 → 0.3.1-9.beta-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -0
- package/assets/ec-i18n/ct.json +1 -0
- package/assets/ec-i18n/en.json +88 -83
- package/assets/ec-i18n/es.json +6 -1
- package/assets/ec-i18n/fr.json +1 -0
- package/assets/ec-i18n/gl.json +1 -0
- package/assets/ec-i18n/pr.json +1 -0
- package/esm2022/lib/classes/component-helper.mjs +11 -2
- package/esm2022/lib/constants/core.constants.service.mjs +107 -2
- package/esm2022/lib/ec-components/abstractions-components/menu-ec.component.mjs +9 -1
- package/esm2022/lib/ec-components/auth-ec/login-form-ec/login-form-ec.component.mjs +5 -1
- package/esm2022/lib/ec-components/auth-ec/register-form-ec/register-form-ec.component.mjs +5 -1
- package/esm2022/lib/ec-components/blocks-ec/block-newsletter-ec/block-newsletter-ec.component.mjs +9 -3
- package/esm2022/lib/ec-components/cart-ec/cart-ec.component.mjs +8 -2
- package/esm2022/lib/ec-components/cart-ec/cart-item-ec/cart-item-ec.component.mjs +42 -10
- package/esm2022/lib/ec-components/checkout-ec/payment-ec/payment-methods/mp-redirect-ec/mp-redirect-ec.component.mjs +141 -75
- package/esm2022/lib/ec-components/filters-ec/filters-ec.component.mjs +9 -1
- package/esm2022/lib/ec-components/header-ec/header-ec.component.mjs +53 -2
- package/esm2022/lib/ec-components/product-detail-ec/product-detail-ec.component.mjs +23 -15
- package/esm2022/lib/ec-components/product-ec/product-ec.component.mjs +143 -5
- package/esm2022/lib/ec-components/widgets-ec/decidir-ec/decidir-ec.component.mjs +3 -3
- package/esm2022/lib/ec-components/widgets-ec/index.mjs +2 -1
- package/esm2022/lib/ec-components/widgets-ec/redsys-catch-ec/redsys-catch-ec.component.mjs +193 -0
- package/esm2022/lib/ec-services/cart.service.mjs +23 -5
- package/esm2022/lib/ec-services/checkout.service.mjs +46 -21
- package/esm2022/lib/ec-services/form.service.mjs +13 -1
- package/esm2022/lib/ec-services/order-utility.service.mjs +12 -6
- package/esm2022/lib/ec-services/product-detail.service.mjs +11 -1
- package/esm2022/lib/interfaces/environment.mjs +1 -1
- package/esm2022/lib/interfaces/product.mjs +1 -1
- package/fesm2022/ng-easycommerce-v18.mjs +843 -147
- package/fesm2022/ng-easycommerce-v18.mjs.map +1 -1
- package/lib/classes/component-helper.d.ts +1 -1
- package/lib/constants/core.constants.service.d.ts +24 -0
- package/lib/ec-components/abstractions-components/menu-ec.component.d.ts +6 -0
- package/lib/ec-components/auth-ec/login-form-ec/login-form-ec.component.d.ts +2 -0
- package/lib/ec-components/auth-ec/register-form-ec/register-form-ec.component.d.ts +2 -0
- package/lib/ec-components/cart-ec/cart-ec.component.d.ts +3 -0
- package/lib/ec-components/cart-ec/cart-item-ec/cart-item-ec.component.d.ts +6 -1
- package/lib/ec-components/checkout-ec/payment-ec/payment-methods/mp-redirect-ec/mp-redirect-ec.component.d.ts +38 -16
- package/lib/ec-components/filters-ec/filters-ec.component.d.ts +6 -0
- package/lib/ec-components/header-ec/header-ec.component.d.ts +16 -2
- package/lib/ec-components/product-detail-ec/product-detail-ec.component.d.ts +2 -1
- package/lib/ec-components/product-ec/product-ec.component.d.ts +14 -1
- package/lib/ec-components/widgets-ec/index.d.ts +1 -0
- package/lib/ec-components/widgets-ec/redsys-catch-ec/redsys-catch-ec.component.d.ts +47 -0
- package/lib/ec-services/cart.service.d.ts +1 -1
- package/lib/ec-services/form.service.d.ts +6 -0
- package/lib/interfaces/environment.d.ts +1 -0
- package/lib/interfaces/product.d.ts +6 -0
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, makeEnvironmentProviders, inject, Injectable, PLATFORM_ID, RendererFactory2, afterNextRender, signal, EnvironmentInjector, runInInjectionContext, Component, ChangeDetectorRef, HostListener, CUSTOM_ELEMENTS_SCHEMA, Input, Pipe, Injector, EventEmitter, Output, forwardRef, afterRender, ViewChild, computed, Renderer2, ChangeDetectionStrategy, Directive
|
|
2
|
+
import { InjectionToken, makeEnvironmentProviders, inject, Injectable, PLATFORM_ID, RendererFactory2, afterNextRender, signal, EnvironmentInjector, runInInjectionContext, Component, ChangeDetectorRef, HostListener, CUSTOM_ELEMENTS_SCHEMA, Input, Pipe, Injector, EventEmitter, Output, forwardRef, afterRender, ViewChild, Inject, computed, Renderer2, ChangeDetectionStrategy, Directive } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/common';
|
|
4
|
-
import {
|
|
4
|
+
import { DOCUMENT, isPlatformBrowser, AsyncPipe, CommonModule, TitleCasePipe, JsonPipe, UpperCasePipe, Location } from '@angular/common';
|
|
5
5
|
import { take, BehaviorSubject, shareReplay, map, catchError, of, filter, ReplaySubject, firstValueFrom, concatMap, throwError, switchMap, combineLatest } from 'rxjs';
|
|
6
6
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
|
7
7
|
import * as i1$1 from '@ngx-translate/core';
|
|
@@ -14,7 +14,7 @@ import { ToastrService } from 'ngx-toastr';
|
|
|
14
14
|
import moment from 'moment';
|
|
15
15
|
import { StorageMap } from '@ngx-pwa/local-storage';
|
|
16
16
|
import * as i1$3 from '@angular/forms';
|
|
17
|
-
import { Validators, FormBuilder, NG_VALUE_ACCESSOR, ReactiveFormsModule
|
|
17
|
+
import { Validators, FormsModule, FormBuilder, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
|
|
18
18
|
import { register } from 'swiper/element/bundle';
|
|
19
19
|
import { register as register$1 } from 'swiper/element';
|
|
20
20
|
import * as i1$4 from '@angular/platform-browser';
|
|
@@ -225,6 +225,14 @@ class CoreConstantsService {
|
|
|
225
225
|
* Provee el ID de la plataforma en donde se esta ejecutando el codigo, esto sirve para poder diferenciar si es de un servidor o un navegador web.
|
|
226
226
|
*/
|
|
227
227
|
platformId = inject(PLATFORM_ID);
|
|
228
|
+
/**
|
|
229
|
+
* Document token para acceso SSR-compatible al documento
|
|
230
|
+
*/
|
|
231
|
+
document = inject(DOCUMENT);
|
|
232
|
+
/**
|
|
233
|
+
* Contiene los datos provisto por el frontend en el archivo environment.ts
|
|
234
|
+
*/
|
|
235
|
+
environment = inject(ENVIRONMENT_TOKEN);
|
|
228
236
|
/**
|
|
229
237
|
* Guarda la variable window del web browser.
|
|
230
238
|
*/
|
|
@@ -264,6 +272,102 @@ class CoreConstantsService {
|
|
|
264
272
|
* @returns
|
|
265
273
|
*/
|
|
266
274
|
url = () => this.apiConstants.API_URL.replace(/\/$/, ''); // remove last slash
|
|
275
|
+
/**
|
|
276
|
+
* URL del sitio frontend - Compatible con Angular SSR
|
|
277
|
+
*/
|
|
278
|
+
get FRONTEND_URL() {
|
|
279
|
+
// Verificar si estamos en el navegador
|
|
280
|
+
if (isPlatformBrowser(this.platformId)) {
|
|
281
|
+
// Primero intenta leer de window.__env (configurado por Docker/CI)
|
|
282
|
+
const windowEnv = this.window?.__env;
|
|
283
|
+
if (windowEnv?.frontendUrl) {
|
|
284
|
+
// Log para debugging en desarrollo
|
|
285
|
+
if (!windowEnv.frontendUrl.startsWith('http')) {
|
|
286
|
+
console.warn('[FRONTEND_URL] Invalid frontendUrl format:', windowEnv.frontendUrl);
|
|
287
|
+
}
|
|
288
|
+
return windowEnv.frontendUrl;
|
|
289
|
+
}
|
|
290
|
+
// Si no hay configuración específica, construir desde window.location
|
|
291
|
+
if (this.window?.location) {
|
|
292
|
+
const url = `${this.window.location.protocol}//${this.window.location.host}`;
|
|
293
|
+
// Verificar que no sea localhost o 127.0.0.1 en producción
|
|
294
|
+
if (url.includes('127.0.0.1') || url.includes('localhost')) {
|
|
295
|
+
console.warn('[FRONTEND_URL] Using localhost URL in production, consider setting window.__env.frontendUrl');
|
|
296
|
+
}
|
|
297
|
+
return url;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
// Para SSR, intentar construir desde el document si está disponible
|
|
301
|
+
if (this.document?.location) {
|
|
302
|
+
return `${this.document.location.protocol}//${this.document.location.host}`;
|
|
303
|
+
}
|
|
304
|
+
// Intentar obtener desde environment
|
|
305
|
+
if (this.environment.frontendUrl) {
|
|
306
|
+
return this.environment.frontendUrl;
|
|
307
|
+
}
|
|
308
|
+
// Último fallback - usar la URL del API si está configurada y es absoluta
|
|
309
|
+
const apiUrl = this.apiConstants.API_URL;
|
|
310
|
+
if (apiUrl && (apiUrl.startsWith('http://') || apiUrl.startsWith('https://'))) {
|
|
311
|
+
try {
|
|
312
|
+
const url = new URL(apiUrl);
|
|
313
|
+
return `${url.protocol}//${url.host}`;
|
|
314
|
+
}
|
|
315
|
+
catch (e) {
|
|
316
|
+
console.warn('[FRONTEND_URL] Could not parse API URL as fallback:', apiUrl);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
// Fallback final - retornar URL vacía
|
|
320
|
+
console.warn('[FRONTEND_URL] No valid frontend URL found, this may cause issues with meta tags');
|
|
321
|
+
return '';
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Retorna la URL completa del frontend con una ruta opcional
|
|
325
|
+
* @param path - Ruta opcional para agregar a la URL base
|
|
326
|
+
* @returns {string} URL completa del frontend
|
|
327
|
+
*/
|
|
328
|
+
getFrontendUrl = (path) => {
|
|
329
|
+
const baseUrl = this.FRONTEND_URL;
|
|
330
|
+
if (!path) {
|
|
331
|
+
return baseUrl;
|
|
332
|
+
}
|
|
333
|
+
// Asegurar que la ruta comience con '/' y no tenga doble slash
|
|
334
|
+
const cleanPath = path.startsWith('/') ? path : `/${path}`;
|
|
335
|
+
const cleanBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
|
|
336
|
+
return `${cleanBaseUrl}${cleanPath}`;
|
|
337
|
+
};
|
|
338
|
+
/**
|
|
339
|
+
* Retorna la URL absoluta de una imagen para meta tags (compatible con SSR)
|
|
340
|
+
* @param postMedia - Ruta de la imagen
|
|
341
|
+
* @returns {string} URL absoluta de la imagen
|
|
342
|
+
*/
|
|
343
|
+
getAbsoluteImageUrl = (postMedia) => {
|
|
344
|
+
// Si la URL ya es absoluta, devolverla tal como está
|
|
345
|
+
if (postMedia && (postMedia.startsWith('http://') || postMedia.startsWith('https://'))) {
|
|
346
|
+
return postMedia;
|
|
347
|
+
}
|
|
348
|
+
// Construir la URL de la imagen usando la URL del API
|
|
349
|
+
const imageUrl = this.mediaImageUrl(postMedia);
|
|
350
|
+
// Si la URL de la imagen ya es absoluta, devolverla
|
|
351
|
+
if (imageUrl.startsWith('http://') || imageUrl.startsWith('https://')) {
|
|
352
|
+
return imageUrl;
|
|
353
|
+
}
|
|
354
|
+
// Si es una URL relativa, convertirla a absoluta usando la URL base del API
|
|
355
|
+
const apiBaseUrl = this.apiConstants.API_URL;
|
|
356
|
+
if (apiBaseUrl.startsWith('http://') || apiBaseUrl.startsWith('https://')) {
|
|
357
|
+
// API_URL ya es absoluta
|
|
358
|
+
return imageUrl;
|
|
359
|
+
}
|
|
360
|
+
// Si API_URL es relativa, usar la URL del frontend como base
|
|
361
|
+
const frontendUrl = this.FRONTEND_URL;
|
|
362
|
+
if (!frontendUrl) {
|
|
363
|
+
return imageUrl; // Fallback si no podemos determinar la URL del frontend
|
|
364
|
+
}
|
|
365
|
+
// Construir URL absoluta
|
|
366
|
+
const cleanApiUrl = apiBaseUrl.startsWith('/') ? apiBaseUrl.substring(1) : apiBaseUrl;
|
|
367
|
+
const cleanFrontendUrl = frontendUrl.endsWith('/') ? frontendUrl.slice(0, -1) : frontendUrl;
|
|
368
|
+
const cleanImageUrl = imageUrl.startsWith('/') ? imageUrl.substring(1) : imageUrl;
|
|
369
|
+
return `${cleanFrontendUrl}/${cleanApiUrl}${cleanImageUrl}`;
|
|
370
|
+
};
|
|
267
371
|
/**
|
|
268
372
|
* Retorna la url de las imagenes de los banners
|
|
269
373
|
* @returns
|
|
@@ -2426,6 +2530,12 @@ class FormService {
|
|
|
2426
2530
|
sendResponse(response_obj) {
|
|
2427
2531
|
return this.connection.post(this.contactFormResponseAPI(), this.prepareData(response_obj));
|
|
2428
2532
|
}
|
|
2533
|
+
/**
|
|
2534
|
+
* @description contiene un arreglo de string cuyo contenido son los codigos de los paises a excluir.
|
|
2535
|
+
* @example ['GB']
|
|
2536
|
+
*/
|
|
2537
|
+
excludedCountries = [];
|
|
2538
|
+
allowedCountries = [];
|
|
2429
2539
|
/**
|
|
2430
2540
|
* Obtiene los paises y los guarda en un observable.
|
|
2431
2541
|
* @returns
|
|
@@ -2441,6 +2551,12 @@ class FormService {
|
|
|
2441
2551
|
const documentTypesData = documentTypesLocale['documentTypes'];
|
|
2442
2552
|
this.documentTypesSubject.next(documentTypesData);
|
|
2443
2553
|
})).subscribe();
|
|
2554
|
+
if (this.excludedCountries.length > 0) {
|
|
2555
|
+
this.countries$ = this.countries$.pipe(map(countries => countries.filter(country => !this.excludedCountries.includes(country.code))));
|
|
2556
|
+
}
|
|
2557
|
+
if (this.allowedCountries.length > 0) {
|
|
2558
|
+
this.countries$ = this.countries$.pipe(map(countries => countries.filter(country => this.allowedCountries.includes(country.code))));
|
|
2559
|
+
}
|
|
2444
2560
|
return this.countries$;
|
|
2445
2561
|
}
|
|
2446
2562
|
/**
|
|
@@ -4377,8 +4493,15 @@ class CartService {
|
|
|
4377
4493
|
* @param quantity la cantidad nueva.
|
|
4378
4494
|
*/
|
|
4379
4495
|
updateItemQuantity(item, quantity) {
|
|
4496
|
+
// Validar antes de proceder
|
|
4380
4497
|
if (this.validateQuantity(item, quantity) && (this.validatePriceAndCredits(item, quantity))) {
|
|
4381
|
-
|
|
4498
|
+
// Si pasa las validaciones, hacer la petición HTTP
|
|
4499
|
+
firstValueFrom(this._connection.put(this.updateItemQuantityApi(this.findItemByIdVariant(item.variant_id)), { 'quantity': Number(quantity) }))
|
|
4500
|
+
.then(res => this.updateCartObj(res) && this.updateCartItemQuantity(item.variant_id, Number(quantity)), err => this.handleError(err));
|
|
4501
|
+
return true; // Validaciones pasaron, operación iniciada
|
|
4502
|
+
}
|
|
4503
|
+
else {
|
|
4504
|
+
return false; // Validaciones fallaron
|
|
4382
4505
|
}
|
|
4383
4506
|
}
|
|
4384
4507
|
/**
|
|
@@ -4459,14 +4582,25 @@ class CartService {
|
|
|
4459
4582
|
* @returns
|
|
4460
4583
|
*/
|
|
4461
4584
|
validateQuantity(item, quantity) {
|
|
4462
|
-
|
|
4585
|
+
const actualQuantity = Number(this.getCountFromItemInCart(item.productCode)); // <-- Forzar a número
|
|
4586
|
+
const newQuantity = Number(quantity); // <-- Forzar a número
|
|
4587
|
+
if ((actualQuantity + newQuantity) > item.product.variants[0].maximumItemsQuantity) {
|
|
4463
4588
|
this._toastService.show('maximum-items-quantity', { quantity: item.product.variants[0].maximumItemsQuantity });
|
|
4464
4589
|
return false;
|
|
4465
4590
|
}
|
|
4466
|
-
if ((
|
|
4591
|
+
if ((actualQuantity + newQuantity) < item.product.variants[0].minimumItemsQuantity) {
|
|
4467
4592
|
this._toastService.show('minimum-items-quantity', { quantity: item.product.variants[0].minimumItemsQuantity });
|
|
4468
4593
|
return false;
|
|
4469
4594
|
}
|
|
4595
|
+
if (item.product.variants[0].multipleQuantity && item.product.variants[0].multipleQuantity > 1) {
|
|
4596
|
+
if ((actualQuantity + newQuantity) % item.product.variants[0].multipleQuantity !== 0) {
|
|
4597
|
+
this._toastService.show('multiple-quantity-required', {
|
|
4598
|
+
multiple: item.product.variants[0].multipleQuantity,
|
|
4599
|
+
current: actualQuantity + newQuantity // <-- Ahora suma correctamente
|
|
4600
|
+
});
|
|
4601
|
+
return false;
|
|
4602
|
+
}
|
|
4603
|
+
}
|
|
4470
4604
|
return true;
|
|
4471
4605
|
}
|
|
4472
4606
|
/**
|
|
@@ -4538,7 +4672,7 @@ class CartService {
|
|
|
4538
4672
|
* @returns
|
|
4539
4673
|
*/
|
|
4540
4674
|
getSubTotalAmount() {
|
|
4541
|
-
return this.cart$.pipe(map((cart) => cart?.totals?.
|
|
4675
|
+
return this.cart$.pipe(map((cart) => cart?.totals?.subtotal));
|
|
4542
4676
|
}
|
|
4543
4677
|
/**
|
|
4544
4678
|
* Retorna un observable con el total del monto de las promociones aplicadas.
|
|
@@ -4814,6 +4948,7 @@ class ProductDetailService {
|
|
|
4814
4948
|
associated.minimumItemsQuantity = v.stock > 0 && 'minimumItemsQuantity' in v && v.minimumItemsQuantity > 0
|
|
4815
4949
|
? v.minimumItemsQuantity
|
|
4816
4950
|
: (v.multipleQuantity ?? 1);
|
|
4951
|
+
associated.multipleQuantity = v.multipleQuantity ?? 1;
|
|
4817
4952
|
// Precios al consumidor final
|
|
4818
4953
|
associated.finalConsumer = {
|
|
4819
4954
|
finalConsumerPrice: v.final_consumer_price,
|
|
@@ -5016,6 +5151,15 @@ class ProductDetailService {
|
|
|
5016
5151
|
this._toastService.show('minimum-items-quantity', { quantity: asociatedData.minimumItemsQuantity });
|
|
5017
5152
|
return false;
|
|
5018
5153
|
}
|
|
5154
|
+
if (asociatedData.multipleQuantity && asociatedData.multipleQuantity > 1) {
|
|
5155
|
+
if ((actualQuantity + quantity) % asociatedData.multipleQuantity !== 0) {
|
|
5156
|
+
this._toastService.show('multiple-quantity-required', {
|
|
5157
|
+
multiple: asociatedData.multipleQuantity,
|
|
5158
|
+
current: actualQuantity + quantity
|
|
5159
|
+
});
|
|
5160
|
+
return false;
|
|
5161
|
+
}
|
|
5162
|
+
}
|
|
5019
5163
|
return true;
|
|
5020
5164
|
};
|
|
5021
5165
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProductDetailService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
@@ -5039,15 +5183,21 @@ class OrderUtilityService {
|
|
|
5039
5183
|
if (cart.checkoutState && cart.checkoutState == "completed")
|
|
5040
5184
|
return;
|
|
5041
5185
|
let new_state = [];
|
|
5042
|
-
let subtotal = { type: 'subtotal', name: 'subtotal', amount: cart.totals.
|
|
5186
|
+
let subtotal = { type: 'subtotal', name: 'subtotal', amount: cart.totals.subtotal };
|
|
5043
5187
|
let total = { type: 'total', name: 'total', amount: cart.totals.total };
|
|
5044
5188
|
!forCart && new_state.push(subtotal);
|
|
5189
|
+
0;
|
|
5045
5190
|
for (let index = 0; index < cart.cartDiscounts.length; index++) {
|
|
5046
|
-
|
|
5191
|
+
const disc = cart.cartDiscounts[index];
|
|
5192
|
+
disc.type = this.formatType(disc.type);
|
|
5193
|
+
let amount = this.getAmount(disc, cart);
|
|
5194
|
+
if (disc.type === 'discount') {
|
|
5195
|
+
amount = cart.totals.promotion;
|
|
5196
|
+
}
|
|
5047
5197
|
new_state.push({
|
|
5048
|
-
type:
|
|
5049
|
-
name: (
|
|
5050
|
-
amount:
|
|
5198
|
+
type: disc.type,
|
|
5199
|
+
name: (disc.type != 'coupon') ? disc.name : 'coupon',
|
|
5200
|
+
amount: amount
|
|
5051
5201
|
});
|
|
5052
5202
|
}
|
|
5053
5203
|
!forCart && new_state.push(total);
|
|
@@ -5208,33 +5358,58 @@ class CheckoutService {
|
|
|
5208
5358
|
return { ok: false, require_login: false, message: 'An error occurred' };
|
|
5209
5359
|
}
|
|
5210
5360
|
};
|
|
5361
|
+
// updateAsociatedData = (cart: any) => {
|
|
5362
|
+
// let result = this._orderUtilityService.getPromotions(cart);
|
|
5363
|
+
// const userProfile: User = User.fromJson(this._authService.getUserProfileAsUser());
|
|
5364
|
+
// if (result) {
|
|
5365
|
+
// if (userProfile.isWholesaler() && cart.totals.taxes != 0) {
|
|
5366
|
+
// let total = { ...result[result.length - 1] };
|
|
5367
|
+
// result[result.length - 1] = {
|
|
5368
|
+
// type: 'taxes',
|
|
5369
|
+
// name: 'taxes',
|
|
5370
|
+
// amount: cart.totals.taxes
|
|
5371
|
+
// }
|
|
5372
|
+
// result.push(total);
|
|
5373
|
+
// }
|
|
5374
|
+
// let shipment = result?.find((promotion: any) => promotion.type == "shipment");
|
|
5375
|
+
// if (!shipment && cart.totals.shipping != 0) {
|
|
5376
|
+
// if (result?.length && !result.find((item: any) => item.type === "shipment")) {
|
|
5377
|
+
// let total = { ...result[result.length - 1] };
|
|
5378
|
+
// result[result.length - 1] = {
|
|
5379
|
+
// type: 'shipment',
|
|
5380
|
+
// name: 'shipment',
|
|
5381
|
+
// amount: cart.totals.shipping
|
|
5382
|
+
// }
|
|
5383
|
+
// result.push(total);
|
|
5384
|
+
// }
|
|
5385
|
+
// }
|
|
5386
|
+
// this._associatedDataSubject.next(result);
|
|
5387
|
+
// }
|
|
5388
|
+
// }
|
|
5211
5389
|
updateAsociatedData = (cart) => {
|
|
5212
5390
|
let result = this._orderUtilityService.getPromotions(cart);
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5391
|
+
if (cart.totals.taxes != 0 && result && result.length > 0) {
|
|
5392
|
+
let total = { ...result[result.length - 1] };
|
|
5393
|
+
result[result.length - 1] = {
|
|
5394
|
+
type: 'taxes',
|
|
5395
|
+
name: 'taxes',
|
|
5396
|
+
amount: cart.totals.taxes
|
|
5397
|
+
};
|
|
5398
|
+
result.push(total);
|
|
5399
|
+
}
|
|
5400
|
+
let shipment = result?.find(promotion => promotion.type == "shipment");
|
|
5401
|
+
if (!shipment && cart.totals.shipping != 0) {
|
|
5402
|
+
if (result?.length && !result.find(item => item.type === "shipment")) {
|
|
5216
5403
|
let total = { ...result[result.length - 1] };
|
|
5217
5404
|
result[result.length - 1] = {
|
|
5218
|
-
type: '
|
|
5219
|
-
name: '
|
|
5220
|
-
amount: cart.totals.
|
|
5405
|
+
type: 'shipment',
|
|
5406
|
+
name: 'shipment',
|
|
5407
|
+
amount: cart.totals.shipping
|
|
5221
5408
|
};
|
|
5222
5409
|
result.push(total);
|
|
5223
5410
|
}
|
|
5224
|
-
let shipment = result?.find((promotion) => promotion.type == "shipment");
|
|
5225
|
-
if (!shipment && cart.totals.shipping != 0) {
|
|
5226
|
-
if (result?.length && !result.find((item) => item.type === "shipment")) {
|
|
5227
|
-
let total = { ...result[result.length - 1] };
|
|
5228
|
-
result[result.length - 1] = {
|
|
5229
|
-
type: 'shipment',
|
|
5230
|
-
name: 'shipment',
|
|
5231
|
-
amount: cart.totals.shipping
|
|
5232
|
-
};
|
|
5233
|
-
result.push(total);
|
|
5234
|
-
}
|
|
5235
|
-
}
|
|
5236
|
-
this._associatedDataSubject.next(result);
|
|
5237
5411
|
}
|
|
5412
|
+
this._associatedDataSubject.next(result ?? null);
|
|
5238
5413
|
};
|
|
5239
5414
|
getStepData = (step_name) => {
|
|
5240
5415
|
let step_result = this._stateSubject.getValue().find(step => step.name == step_name);
|
|
@@ -5859,6 +6034,14 @@ class MenuEcComponent {
|
|
|
5859
6034
|
});
|
|
5860
6035
|
}));
|
|
5861
6036
|
}
|
|
6037
|
+
/**
|
|
6038
|
+
* Verifica si una categoría tiene la propiedad isVisible y está marcada como visible
|
|
6039
|
+
* @param category - La categoría a verificar
|
|
6040
|
+
* @returns true si la categoría es visible, false en caso contrario
|
|
6041
|
+
*/
|
|
6042
|
+
hasVisibleProperty(category) {
|
|
6043
|
+
return category.isVisible === true;
|
|
6044
|
+
}
|
|
5862
6045
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MenuEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5863
6046
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: MenuEcComponent, isStandalone: true, selector: "lib-footer-ec", ngImport: i0, template: '<p>Menu and Footer Helper Component</p>', isInline: true });
|
|
5864
6047
|
}
|
|
@@ -6005,6 +6188,13 @@ class HeaderEcComponent extends MenuEcComponent {
|
|
|
6005
6188
|
hidePrices = false;
|
|
6006
6189
|
__authService = inject(AuthService);
|
|
6007
6190
|
_channelService = inject(ChannelService);
|
|
6191
|
+
changeDetector = inject(ChangeDetectorRef);
|
|
6192
|
+
appRouter = inject(Router);
|
|
6193
|
+
platformId = inject(PLATFORM_ID);
|
|
6194
|
+
mobileDropdownOpen = signal(false);
|
|
6195
|
+
isMenuOpen = signal(false);
|
|
6196
|
+
// Observable del estado de autenticación
|
|
6197
|
+
logged$;
|
|
6008
6198
|
isAuthenticated$ = this.__authService.isAuthenticated();
|
|
6009
6199
|
constructor() {
|
|
6010
6200
|
super();
|
|
@@ -6022,6 +6212,22 @@ class HeaderEcComponent extends MenuEcComponent {
|
|
|
6022
6212
|
this.channel = this.coreConstantsService.getChannel();
|
|
6023
6213
|
this.onWindowScroll();
|
|
6024
6214
|
this.detectRouteChange(); // Llamamos a la función que detecta el cambio de ruta
|
|
6215
|
+
// Usar el Observable del AuthService
|
|
6216
|
+
this.logged$ = this.__authService.loggedIn$;
|
|
6217
|
+
// Suscribirse al Observable y forzar detección de cambios cuando sea necesario
|
|
6218
|
+
this.logged$.subscribe(isLoggedIn => {
|
|
6219
|
+
this.changeDetector.detectChanges();
|
|
6220
|
+
});
|
|
6221
|
+
if (isPlatformBrowser(this.platformId)) {
|
|
6222
|
+
this.appRouter.events.subscribe(evt => {
|
|
6223
|
+
if (evt instanceof NavigationEnd) {
|
|
6224
|
+
// Forzar detección de cambios después de navegación
|
|
6225
|
+
setTimeout(() => {
|
|
6226
|
+
this.changeDetector.detectChanges();
|
|
6227
|
+
}, 100);
|
|
6228
|
+
}
|
|
6229
|
+
});
|
|
6230
|
+
}
|
|
6025
6231
|
}
|
|
6026
6232
|
ngAfterViewInit() {
|
|
6027
6233
|
this.setupMobileMenu(); // Inicializamos el menú móvil
|
|
@@ -6158,6 +6364,33 @@ class HeaderEcComponent extends MenuEcComponent {
|
|
|
6158
6364
|
});
|
|
6159
6365
|
});
|
|
6160
6366
|
}
|
|
6367
|
+
togglePanel(id) {
|
|
6368
|
+
// Solo ejecutar en el navegador para evitar problemas con SSR
|
|
6369
|
+
if (isPlatformBrowser(this.platformId)) {
|
|
6370
|
+
this.openPanels.update(panels => ({
|
|
6371
|
+
...panels,
|
|
6372
|
+
[id]: !panels[id]
|
|
6373
|
+
}));
|
|
6374
|
+
}
|
|
6375
|
+
}
|
|
6376
|
+
openPanels = signal({
|
|
6377
|
+
collapseUno: false,
|
|
6378
|
+
collapseDos: true // Productos abierto por defecto
|
|
6379
|
+
});
|
|
6380
|
+
collapseAllMenus() {
|
|
6381
|
+
// Solo ejecutar en el navegador para evitar problemas con SSR
|
|
6382
|
+
if (isPlatformBrowser(this.platformId)) {
|
|
6383
|
+
this.openPanels.update(panels => {
|
|
6384
|
+
const newPanels = { ...panels };
|
|
6385
|
+
Object.keys(newPanels).forEach(key => {
|
|
6386
|
+
if (key !== 'collapseDos') {
|
|
6387
|
+
newPanels[key] = false;
|
|
6388
|
+
}
|
|
6389
|
+
});
|
|
6390
|
+
return newPanels;
|
|
6391
|
+
});
|
|
6392
|
+
}
|
|
6393
|
+
}
|
|
6161
6394
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: HeaderEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6162
6395
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: HeaderEcComponent, isStandalone: true, selector: "lib-header-ec", host: { listeners: { "window:scroll": "onWindowScroll()" } }, usesInheritance: true, ngImport: i0, template: "<p>header-ec works!</p>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
6163
6396
|
}
|
|
@@ -6725,6 +6958,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
6725
6958
|
class ProductEcComponent {
|
|
6726
6959
|
injector = inject(Injector);
|
|
6727
6960
|
routerService = inject(Router);
|
|
6961
|
+
_cartService = inject(CartService);
|
|
6962
|
+
_toastService = inject(ToastService);
|
|
6963
|
+
isAddingToCart = signal(false);
|
|
6964
|
+
quantity = signal(1);
|
|
6728
6965
|
/**
|
|
6729
6966
|
* Navega al detalle del producto y sube al inicio de la página
|
|
6730
6967
|
* @param productId ID del producto
|
|
@@ -6797,12 +7034,145 @@ class ProductEcComponent {
|
|
|
6797
7034
|
const discount = ((originalPrice - salePrice) / originalPrice) * 100;
|
|
6798
7035
|
return Math.round(discount);
|
|
6799
7036
|
}
|
|
7037
|
+
plus(stock, multipleQuantity) {
|
|
7038
|
+
const current = Number(this.quantity()); // <-- fuerza a número
|
|
7039
|
+
if (multipleQuantity && multipleQuantity > 0) {
|
|
7040
|
+
stock
|
|
7041
|
+
? (current < stock
|
|
7042
|
+
? this.quantity.set(current + multipleQuantity)
|
|
7043
|
+
: this._toastService.show('out-of-stock-actually'))
|
|
7044
|
+
: this.quantity.set(current + multipleQuantity);
|
|
7045
|
+
}
|
|
7046
|
+
else {
|
|
7047
|
+
stock
|
|
7048
|
+
? (current < stock
|
|
7049
|
+
? this.quantity.set(current + 1)
|
|
7050
|
+
: this._toastService.show('out-of-stock-actually'))
|
|
7051
|
+
: this.quantity.set(current + 1);
|
|
7052
|
+
}
|
|
7053
|
+
}
|
|
7054
|
+
less(multipleQuantity) {
|
|
7055
|
+
const current = Number(this.quantity()); // <-- fuerza a número
|
|
7056
|
+
if (multipleQuantity && multipleQuantity > 0) {
|
|
7057
|
+
current > multipleQuantity
|
|
7058
|
+
? this.quantity.set(current - multipleQuantity)
|
|
7059
|
+
: null;
|
|
7060
|
+
}
|
|
7061
|
+
else {
|
|
7062
|
+
current > 1 ? this.quantity.set(current - 1) : null;
|
|
7063
|
+
}
|
|
7064
|
+
}
|
|
7065
|
+
addToCart() {
|
|
7066
|
+
if (this.isAddingToCart() || this.quantity() <= 0)
|
|
7067
|
+
return;
|
|
7068
|
+
// Verificar que tenemos el producto y sus variantes
|
|
7069
|
+
if (!this.product || !this.product.variants || this.product.variants.length === 0) {
|
|
7070
|
+
this._toastService.show('cant-buy');
|
|
7071
|
+
return;
|
|
7072
|
+
}
|
|
7073
|
+
// Verificar stock
|
|
7074
|
+
const firstVariant = this.product.variants[0];
|
|
7075
|
+
if (!firstVariant.stock || firstVariant.stock <= 0) {
|
|
7076
|
+
this._toastService.show('out-of-stock');
|
|
7077
|
+
return;
|
|
7078
|
+
}
|
|
7079
|
+
// Verificar que no se supere el stock disponible
|
|
7080
|
+
if (this.quantity() > firstVariant.stock) {
|
|
7081
|
+
this._toastService.show('out-of-stock-actually');
|
|
7082
|
+
return;
|
|
7083
|
+
}
|
|
7084
|
+
// NUEVAS VALIDACIONES: Verificar restricciones del producto
|
|
7085
|
+
if (!this.validateQuantity(this.quantity())) {
|
|
7086
|
+
return; // La validación ya mostró el toast correspondiente
|
|
7087
|
+
}
|
|
7088
|
+
this.isAddingToCart.set(true);
|
|
7089
|
+
try {
|
|
7090
|
+
// Agregar al carrito usando CartService directamente
|
|
7091
|
+
this._cartService.addToCart(this.product, this.quantity(), firstVariant.code);
|
|
7092
|
+
// Resetear cantidad a 1 después de agregar al carrito
|
|
7093
|
+
this.quantity.set(1);
|
|
7094
|
+
}
|
|
7095
|
+
catch (error) {
|
|
7096
|
+
this._toastService.show('cant-buy');
|
|
7097
|
+
}
|
|
7098
|
+
setTimeout(() => {
|
|
7099
|
+
this.isAddingToCart.set(false);
|
|
7100
|
+
}, 2000);
|
|
7101
|
+
}
|
|
7102
|
+
/**
|
|
7103
|
+
* Valida las restricciones de cantidad del producto
|
|
7104
|
+
*/
|
|
7105
|
+
validateQuantity(quantity) {
|
|
7106
|
+
if (!this.product.variants || this.product.variants.length === 0) {
|
|
7107
|
+
this._toastService.show('cant-buy');
|
|
7108
|
+
return false;
|
|
7109
|
+
}
|
|
7110
|
+
const variant = this.product.variants[0];
|
|
7111
|
+
// Obtener cantidad actual en el carrito
|
|
7112
|
+
const actualQuantity = this._cartService.getCountFromItemInCart(variant.code);
|
|
7113
|
+
const totalQuantity = Number(actualQuantity) + Number(quantity);
|
|
7114
|
+
// Obtener restricciones del producto/variante (con valores por defecto)
|
|
7115
|
+
const maximumItemsQuantity = this.product.maximumItemsQuantity ||
|
|
7116
|
+
variant.maximumItemsQuantity ||
|
|
7117
|
+
999999;
|
|
7118
|
+
const minimumItemsQuantity = this.product.minimumItemsQuantity ||
|
|
7119
|
+
variant.minimumItemsQuantity ||
|
|
7120
|
+
1;
|
|
7121
|
+
const multipleQuantity = this.product.multipleQuantity ||
|
|
7122
|
+
variant.multipleQuantity ||
|
|
7123
|
+
1;
|
|
7124
|
+
// Validar cantidad máxima
|
|
7125
|
+
if (totalQuantity > maximumItemsQuantity) {
|
|
7126
|
+
this._toastService.show('maximum-items-quantity', { quantity: maximumItemsQuantity });
|
|
7127
|
+
return false;
|
|
7128
|
+
}
|
|
7129
|
+
// Validar cantidad mínima
|
|
7130
|
+
if (totalQuantity < minimumItemsQuantity) {
|
|
7131
|
+
this._toastService.show('minimum-items-quantity', { quantity: minimumItemsQuantity });
|
|
7132
|
+
return false;
|
|
7133
|
+
}
|
|
7134
|
+
// Validar múltiplo de cantidad
|
|
7135
|
+
if (multipleQuantity && multipleQuantity > 1) {
|
|
7136
|
+
if (totalQuantity % multipleQuantity !== 0) {
|
|
7137
|
+
this._toastService.show('multiple-quantity-required', {
|
|
7138
|
+
multiple: multipleQuantity,
|
|
7139
|
+
current: totalQuantity
|
|
7140
|
+
});
|
|
7141
|
+
return false;
|
|
7142
|
+
}
|
|
7143
|
+
}
|
|
7144
|
+
// Validar que no exceda el stock total
|
|
7145
|
+
if (totalQuantity > variant.stock) {
|
|
7146
|
+
this._toastService.show('out-of-stock-actually');
|
|
7147
|
+
return false;
|
|
7148
|
+
}
|
|
7149
|
+
return true; // Todas las validaciones pasaron
|
|
7150
|
+
}
|
|
7151
|
+
checkStock(stock) {
|
|
7152
|
+
if (this.quantity() >= stock)
|
|
7153
|
+
this.quantity.set(stock);
|
|
7154
|
+
}
|
|
7155
|
+
onQuantityChange(event) {
|
|
7156
|
+
const target = event.target;
|
|
7157
|
+
const value = +target.value;
|
|
7158
|
+
// Validar que el valor sea mayor a 0
|
|
7159
|
+
if (value > 0) {
|
|
7160
|
+
this.quantity.set(value);
|
|
7161
|
+
// Validar contra el stock disponible
|
|
7162
|
+
const maxStock = this.product?.variants?.[0]?.stock || this.product?.stock || 0;
|
|
7163
|
+
this.checkStock(maxStock);
|
|
7164
|
+
}
|
|
7165
|
+
else {
|
|
7166
|
+
// Si el valor es 0 o negativo, resetear a 1
|
|
7167
|
+
this.quantity.set(1);
|
|
7168
|
+
}
|
|
7169
|
+
}
|
|
6800
7170
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProductEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6801
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: ProductEcComponent, isStandalone: true, selector: "app-product-ec", inputs: { product: "product", isProductBox: "isProductBox", isCollection: "isCollection" }, outputs: { loaded: "loaded" }, ngImport: i0, template: "<a [routerLink]=\"['/product', product.id]\" class=\"text-decoration-none producto\">\r\n <!-- Marca especial y descuento -->\r\n <!-- <div *ngIf=\"product.saleprice || (product.special_mark && product.special_mark !== null && product.special_mark !== undefined && product.special_mark.length >0)\"\r\n class=\"marcas\">\r\n <div *ecProductStock=\"product\" [ecProductMini]=\"product.special_mark\"></div>\r\n <ng-container *ngIf=\"shouldShowPrice\">\r\n <div *ecProductStock=\"product\" [ngClass]=\"{'tag-dsc float-right': product.saleprice}\"\r\n [ecProductOff]=\"product\">\r\n </div>\r\n </ng-container>\r\n </div> -->\r\n\r\n <!-- Imagen del producto -->\r\n <div class=\"foto\">\r\n @if(product.picturesdefault){\r\n @if (product.picturesdefault && product.picturesdefault.length > 1 ) {\r\n <img [src]=\"mediaUrl + product.picturesdefault[0]\" alt=\"Imagen principal\" class=\"w-100 pic01\" />\r\n <img [src]=\"mediaUrl + product.picturesdefault[1]\" alt=\"Imagen secundaria\" class=\"w-100 pic02\" />\r\n } @else {\r\n <img [src]=\"mediaUrl + product.picturesdefault[0]\" alt=\"Imagen principal\" class=\"w-100 pic01\" />\r\n }\r\n }\r\n </div>\r\n <!-- Precio -->\r\n\r\n\r\n <!-- Nombre del producto -->\r\n <h6 class=\"title\">{{ product.name | titlecase }}</h6>\r\n\r\n <div class=\"sku\" [innerHTML]=\"product.shortdetails\"></div>\r\n\r\n @if (shouldShowPrice) {\r\n <app-price-ec [price]=\"product.price\" [saleprice]=\"product.saleprice\" class=\"\" />\r\n }\r\n @if(!hidePrices){\r\n @if(!showPricesOnlyToLoggedUsers || isAuthenticated$){\r\n\r\n <div class=\"fixBottom\">\r\n\r\n <!-- Bot\u00F3n de acciones -->\r\n <!-- <ng-container *ecProductStock=\"product; else noStock\"> -->\r\n <!-- Cuando no tiene marca especial o es de tipo 'standard' -->\r\n @if (!product.special_mark || product.special_mark.length === 0 || product.special_mark[0]?.type ===\r\n 'standard') {\r\n <button class=\"btn standard\" [ngClass]=\"isCollection ? 'px-2 w-100 d-sm-block' : 'py-2 px-4'\">\r\n <ng-container *ngIf=\"isCollection; else normalText\">\r\n <span> {{(\"buy\" | translate) | uppercase}} </span>\r\n </ng-container>\r\n <ng-template #normalText>\r\n {{(\"buy\" | translate) | uppercase}}\r\n </ng-template>\r\n </button>\r\n }@else {\r\n <!-- Caso 1: Agotado o Disponible muy pronto -->\r\n @if (product.special_mark[0]?.type === 'out_of_stock' || product.special_mark[0]?.type === 'coming_soon') {\r\n <button class=\"btn\" [ngClass]=\"isCollection ? 'px-2 w-100 d-sm-block' : 'py-2 px-4'\">\r\n @if(isCollection){\r\n <span>{{ product.special_mark[0].name | uppercase }} </span>\r\n }@else {\r\n {{ product.special_mark[0]?.name | uppercase }}\r\n }\r\n </button>}\r\n <!-- Caso 2: Contacto por WhatsApp -->\r\n @if (product.special_mark[0].type === 'whatsapp_contact') {\r\n <button class=\"btn\" [ngClass]=\"isCollection ? 'px-2 w-100 d-sm-block' : 'py-2 px-4'\"\r\n (click)=\"openWhatsApp(product.special_mark[0]?.whatsappContact)\">\r\n @if(isCollection){\r\n <span>{{ product.special_mark[0]?.name | uppercase }}</span>\r\n }@else {\r\n {{ product.special_mark[0]?.name | uppercase }}\r\n }\r\n\r\n </button>\r\n }\r\n <!-- Caso 3: Solicitar m\u00E1s informaci\u00F3n -->\r\n @if (product.special_mark[0]?.type === 'more_info') {\r\n <button class=\"btn\" [ngClass]=\"isCollection ? 'px-2 w-100 d-sm-block' : 'py-2 px-4'\">\r\n @if(isCollection){\r\n <span>{{ product.special_mark[0]?.name | uppercase }}</span>\r\n }@else {\r\n {{ product.special_mark[0]?.name | uppercase }}\r\n }\r\n </button>\r\n }\r\n }\r\n </div>\r\n }}\r\n</a>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.UpperCasePipe, name: "uppercase" }, { kind: "pipe", type: i1.TitleCasePipe, name: "titlecase" }, { kind: "component", type: PriceEcComponent, selector: "app-price-ec", inputs: ["price", "saleprice", "basePrice", "taxeAmount", "taxes", "priceSize", "showTaxLegendOnly", "disableTaxInfo", "customPriceTemplate", "customSalePriceTemplate", "customSimplePriceTemplate", "customSimpleSalePriceTemplate", "customTaxTemplate", "customOnlyTaxLabelTemplate"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
7171
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: ProductEcComponent, isStandalone: true, selector: "app-product-ec", inputs: { product: "product", isProductBox: "isProductBox", isCollection: "isCollection" }, outputs: { loaded: "loaded" }, ngImport: i0, template: "<a [routerLink]=\"['/product', product.id]\" class=\"text-decoration-none producto\">\r\n <!-- Marca especial y descuento -->\r\n <!-- <div *ngIf=\"product.saleprice || (product.special_mark && product.special_mark !== null && product.special_mark !== undefined && product.special_mark.length >0)\"\r\n class=\"marcas\">\r\n <div *ecProductStock=\"product\" [ecProductMini]=\"product.special_mark\"></div>\r\n <ng-container *ngIf=\"shouldShowPrice\">\r\n <div *ecProductStock=\"product\" [ngClass]=\"{'tag-dsc float-right': product.saleprice}\"\r\n [ecProductOff]=\"product\">\r\n </div>\r\n </ng-container>\r\n </div> -->\r\n\r\n <!-- Imagen del producto -->\r\n <div class=\"foto\">\r\n @if(product.picturesdefault){\r\n @if (product.picturesdefault && product.picturesdefault.length > 1 ) {\r\n <img [src]=\"mediaUrl + product.picturesdefault[0]\" alt=\"Imagen principal\" class=\"w-100 pic01\" />\r\n <img [src]=\"mediaUrl + product.picturesdefault[1]\" alt=\"Imagen secundaria\" class=\"w-100 pic02\" />\r\n } @else {\r\n <img [src]=\"mediaUrl + product.picturesdefault[0]\" alt=\"Imagen principal\" class=\"w-100 pic01\" />\r\n }\r\n }\r\n </div>\r\n <!-- Precio -->\r\n\r\n\r\n <!-- Nombre del producto -->\r\n <h6 class=\"title\">{{ product.name | titlecase }}</h6>\r\n\r\n <div class=\"sku\" [innerHTML]=\"product.shortdetails\"></div>\r\n\r\n @if (shouldShowPrice) {\r\n <app-price-ec [price]=\"product.price\" [saleprice]=\"product.saleprice\" class=\"\" />\r\n }\r\n @if(!hidePrices){\r\n @if(!showPricesOnlyToLoggedUsers || isAuthenticated$){\r\n\r\n <div class=\"fixBottom\">\r\n\r\n <!-- Bot\u00F3n de acciones -->\r\n <!-- <ng-container *ecProductStock=\"product; else noStock\"> -->\r\n <!-- Cuando no tiene marca especial o es de tipo 'standard' -->\r\n @if (!product.special_mark || product.special_mark.length === 0 || product.special_mark[0]?.type ===\r\n 'standard') {\r\n <button class=\"btn standard\" [ngClass]=\"isCollection ? 'px-2 w-100 d-sm-block' : 'py-2 px-4'\">\r\n <ng-container *ngIf=\"isCollection; else normalText\">\r\n <span> {{(\"buy\" | translate) | uppercase}} </span>\r\n </ng-container>\r\n <ng-template #normalText>\r\n {{(\"buy\" | translate) | uppercase}}\r\n </ng-template>\r\n </button>\r\n }@else {\r\n <!-- Caso 1: Agotado o Disponible muy pronto -->\r\n @if (product.special_mark[0]?.type === 'out_of_stock' || product.special_mark[0]?.type === 'coming_soon') {\r\n <button class=\"btn\" [ngClass]=\"isCollection ? 'px-2 w-100 d-sm-block' : 'py-2 px-4'\">\r\n @if(isCollection){\r\n <span>{{ product.special_mark[0].name | uppercase }} </span>\r\n }@else {\r\n {{ product.special_mark[0]?.name | uppercase }}\r\n }\r\n </button>}\r\n <!-- Caso 2: Contacto por WhatsApp -->\r\n @if (product.special_mark[0].type === 'whatsapp_contact') {\r\n <button class=\"btn\" [ngClass]=\"isCollection ? 'px-2 w-100 d-sm-block' : 'py-2 px-4'\"\r\n (click)=\"openWhatsApp(product.special_mark[0]?.whatsappContact)\">\r\n @if(isCollection){\r\n <span>{{ product.special_mark[0]?.name | uppercase }}</span>\r\n }@else {\r\n {{ product.special_mark[0]?.name | uppercase }}\r\n }\r\n\r\n </button>\r\n }\r\n <!-- Caso 3: Solicitar m\u00E1s informaci\u00F3n -->\r\n @if (product.special_mark[0]?.type === 'more_info') {\r\n <button class=\"btn\" [ngClass]=\"isCollection ? 'px-2 w-100 d-sm-block' : 'py-2 px-4'\">\r\n @if(isCollection){\r\n <span>{{ product.special_mark[0]?.name | uppercase }}</span>\r\n }@else {\r\n {{ product.special_mark[0]?.name | uppercase }}\r\n }\r\n </button>\r\n }\r\n }\r\n </div>\r\n }}\r\n</a>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.UpperCasePipe, name: "uppercase" }, { kind: "pipe", type: i1.TitleCasePipe, name: "titlecase" }, { kind: "component", type: PriceEcComponent, selector: "app-price-ec", inputs: ["price", "saleprice", "basePrice", "taxeAmount", "taxes", "priceSize", "showTaxLegendOnly", "disableTaxInfo", "customPriceTemplate", "customSalePriceTemplate", "customSimplePriceTemplate", "customSimpleSalePriceTemplate", "customTaxTemplate", "customOnlyTaxLabelTemplate"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: FormsModule }] });
|
|
6802
7172
|
}
|
|
6803
7173
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProductEcComponent, decorators: [{
|
|
6804
7174
|
type: Component,
|
|
6805
|
-
args: [{ selector: 'app-product-ec', standalone: true, imports: [CommonModule, PriceEcComponent, RouterLink, TranslateModule], template: "<a [routerLink]=\"['/product', product.id]\" class=\"text-decoration-none producto\">\r\n <!-- Marca especial y descuento -->\r\n <!-- <div *ngIf=\"product.saleprice || (product.special_mark && product.special_mark !== null && product.special_mark !== undefined && product.special_mark.length >0)\"\r\n class=\"marcas\">\r\n <div *ecProductStock=\"product\" [ecProductMini]=\"product.special_mark\"></div>\r\n <ng-container *ngIf=\"shouldShowPrice\">\r\n <div *ecProductStock=\"product\" [ngClass]=\"{'tag-dsc float-right': product.saleprice}\"\r\n [ecProductOff]=\"product\">\r\n </div>\r\n </ng-container>\r\n </div> -->\r\n\r\n <!-- Imagen del producto -->\r\n <div class=\"foto\">\r\n @if(product.picturesdefault){\r\n @if (product.picturesdefault && product.picturesdefault.length > 1 ) {\r\n <img [src]=\"mediaUrl + product.picturesdefault[0]\" alt=\"Imagen principal\" class=\"w-100 pic01\" />\r\n <img [src]=\"mediaUrl + product.picturesdefault[1]\" alt=\"Imagen secundaria\" class=\"w-100 pic02\" />\r\n } @else {\r\n <img [src]=\"mediaUrl + product.picturesdefault[0]\" alt=\"Imagen principal\" class=\"w-100 pic01\" />\r\n }\r\n }\r\n </div>\r\n <!-- Precio -->\r\n\r\n\r\n <!-- Nombre del producto -->\r\n <h6 class=\"title\">{{ product.name | titlecase }}</h6>\r\n\r\n <div class=\"sku\" [innerHTML]=\"product.shortdetails\"></div>\r\n\r\n @if (shouldShowPrice) {\r\n <app-price-ec [price]=\"product.price\" [saleprice]=\"product.saleprice\" class=\"\" />\r\n }\r\n @if(!hidePrices){\r\n @if(!showPricesOnlyToLoggedUsers || isAuthenticated$){\r\n\r\n <div class=\"fixBottom\">\r\n\r\n <!-- Bot\u00F3n de acciones -->\r\n <!-- <ng-container *ecProductStock=\"product; else noStock\"> -->\r\n <!-- Cuando no tiene marca especial o es de tipo 'standard' -->\r\n @if (!product.special_mark || product.special_mark.length === 0 || product.special_mark[0]?.type ===\r\n 'standard') {\r\n <button class=\"btn standard\" [ngClass]=\"isCollection ? 'px-2 w-100 d-sm-block' : 'py-2 px-4'\">\r\n <ng-container *ngIf=\"isCollection; else normalText\">\r\n <span> {{(\"buy\" | translate) | uppercase}} </span>\r\n </ng-container>\r\n <ng-template #normalText>\r\n {{(\"buy\" | translate) | uppercase}}\r\n </ng-template>\r\n </button>\r\n }@else {\r\n <!-- Caso 1: Agotado o Disponible muy pronto -->\r\n @if (product.special_mark[0]?.type === 'out_of_stock' || product.special_mark[0]?.type === 'coming_soon') {\r\n <button class=\"btn\" [ngClass]=\"isCollection ? 'px-2 w-100 d-sm-block' : 'py-2 px-4'\">\r\n @if(isCollection){\r\n <span>{{ product.special_mark[0].name | uppercase }} </span>\r\n }@else {\r\n {{ product.special_mark[0]?.name | uppercase }}\r\n }\r\n </button>}\r\n <!-- Caso 2: Contacto por WhatsApp -->\r\n @if (product.special_mark[0].type === 'whatsapp_contact') {\r\n <button class=\"btn\" [ngClass]=\"isCollection ? 'px-2 w-100 d-sm-block' : 'py-2 px-4'\"\r\n (click)=\"openWhatsApp(product.special_mark[0]?.whatsappContact)\">\r\n @if(isCollection){\r\n <span>{{ product.special_mark[0]?.name | uppercase }}</span>\r\n }@else {\r\n {{ product.special_mark[0]?.name | uppercase }}\r\n }\r\n\r\n </button>\r\n }\r\n <!-- Caso 3: Solicitar m\u00E1s informaci\u00F3n -->\r\n @if (product.special_mark[0]?.type === 'more_info') {\r\n <button class=\"btn\" [ngClass]=\"isCollection ? 'px-2 w-100 d-sm-block' : 'py-2 px-4'\">\r\n @if(isCollection){\r\n <span>{{ product.special_mark[0]?.name | uppercase }}</span>\r\n }@else {\r\n {{ product.special_mark[0]?.name | uppercase }}\r\n }\r\n </button>\r\n }\r\n }\r\n </div>\r\n }}\r\n</a>" }]
|
|
7175
|
+
args: [{ selector: 'app-product-ec', standalone: true, imports: [CommonModule, PriceEcComponent, RouterLink, TranslateModule, FormsModule], template: "<a [routerLink]=\"['/product', product.id]\" class=\"text-decoration-none producto\">\r\n <!-- Marca especial y descuento -->\r\n <!-- <div *ngIf=\"product.saleprice || (product.special_mark && product.special_mark !== null && product.special_mark !== undefined && product.special_mark.length >0)\"\r\n class=\"marcas\">\r\n <div *ecProductStock=\"product\" [ecProductMini]=\"product.special_mark\"></div>\r\n <ng-container *ngIf=\"shouldShowPrice\">\r\n <div *ecProductStock=\"product\" [ngClass]=\"{'tag-dsc float-right': product.saleprice}\"\r\n [ecProductOff]=\"product\">\r\n </div>\r\n </ng-container>\r\n </div> -->\r\n\r\n <!-- Imagen del producto -->\r\n <div class=\"foto\">\r\n @if(product.picturesdefault){\r\n @if (product.picturesdefault && product.picturesdefault.length > 1 ) {\r\n <img [src]=\"mediaUrl + product.picturesdefault[0]\" alt=\"Imagen principal\" class=\"w-100 pic01\" />\r\n <img [src]=\"mediaUrl + product.picturesdefault[1]\" alt=\"Imagen secundaria\" class=\"w-100 pic02\" />\r\n } @else {\r\n <img [src]=\"mediaUrl + product.picturesdefault[0]\" alt=\"Imagen principal\" class=\"w-100 pic01\" />\r\n }\r\n }\r\n </div>\r\n <!-- Precio -->\r\n\r\n\r\n <!-- Nombre del producto -->\r\n <h6 class=\"title\">{{ product.name | titlecase }}</h6>\r\n\r\n <div class=\"sku\" [innerHTML]=\"product.shortdetails\"></div>\r\n\r\n @if (shouldShowPrice) {\r\n <app-price-ec [price]=\"product.price\" [saleprice]=\"product.saleprice\" class=\"\" />\r\n }\r\n @if(!hidePrices){\r\n @if(!showPricesOnlyToLoggedUsers || isAuthenticated$){\r\n\r\n <div class=\"fixBottom\">\r\n\r\n <!-- Bot\u00F3n de acciones -->\r\n <!-- <ng-container *ecProductStock=\"product; else noStock\"> -->\r\n <!-- Cuando no tiene marca especial o es de tipo 'standard' -->\r\n @if (!product.special_mark || product.special_mark.length === 0 || product.special_mark[0]?.type ===\r\n 'standard') {\r\n <button class=\"btn standard\" [ngClass]=\"isCollection ? 'px-2 w-100 d-sm-block' : 'py-2 px-4'\">\r\n <ng-container *ngIf=\"isCollection; else normalText\">\r\n <span> {{(\"buy\" | translate) | uppercase}} </span>\r\n </ng-container>\r\n <ng-template #normalText>\r\n {{(\"buy\" | translate) | uppercase}}\r\n </ng-template>\r\n </button>\r\n }@else {\r\n <!-- Caso 1: Agotado o Disponible muy pronto -->\r\n @if (product.special_mark[0]?.type === 'out_of_stock' || product.special_mark[0]?.type === 'coming_soon') {\r\n <button class=\"btn\" [ngClass]=\"isCollection ? 'px-2 w-100 d-sm-block' : 'py-2 px-4'\">\r\n @if(isCollection){\r\n <span>{{ product.special_mark[0].name | uppercase }} </span>\r\n }@else {\r\n {{ product.special_mark[0]?.name | uppercase }}\r\n }\r\n </button>}\r\n <!-- Caso 2: Contacto por WhatsApp -->\r\n @if (product.special_mark[0].type === 'whatsapp_contact') {\r\n <button class=\"btn\" [ngClass]=\"isCollection ? 'px-2 w-100 d-sm-block' : 'py-2 px-4'\"\r\n (click)=\"openWhatsApp(product.special_mark[0]?.whatsappContact)\">\r\n @if(isCollection){\r\n <span>{{ product.special_mark[0]?.name | uppercase }}</span>\r\n }@else {\r\n {{ product.special_mark[0]?.name | uppercase }}\r\n }\r\n\r\n </button>\r\n }\r\n <!-- Caso 3: Solicitar m\u00E1s informaci\u00F3n -->\r\n @if (product.special_mark[0]?.type === 'more_info') {\r\n <button class=\"btn\" [ngClass]=\"isCollection ? 'px-2 w-100 d-sm-block' : 'py-2 px-4'\">\r\n @if(isCollection){\r\n <span>{{ product.special_mark[0]?.name | uppercase }}</span>\r\n }@else {\r\n {{ product.special_mark[0]?.name | uppercase }}\r\n }\r\n </button>\r\n }\r\n }\r\n </div>\r\n }}\r\n</a>" }]
|
|
6806
7176
|
}], ctorParameters: () => [], propDecorators: { product: [{
|
|
6807
7177
|
type: Input,
|
|
6808
7178
|
args: [{
|
|
@@ -7070,8 +7440,14 @@ class BlockNewsletterEcComponent {
|
|
|
7070
7440
|
this._toastService.show(this.success_message || success_message);
|
|
7071
7441
|
this.loading = false;
|
|
7072
7442
|
}, (err) => {
|
|
7073
|
-
|
|
7074
|
-
|
|
7443
|
+
if (err.status === 400) {
|
|
7444
|
+
this._toastService.error('newsletter_email_already_registered');
|
|
7445
|
+
this.loading = false;
|
|
7446
|
+
}
|
|
7447
|
+
else {
|
|
7448
|
+
this._toastService.error('inquiry-error');
|
|
7449
|
+
this.loading = false;
|
|
7450
|
+
}
|
|
7075
7451
|
});
|
|
7076
7452
|
}
|
|
7077
7453
|
else {
|
|
@@ -7376,6 +7752,212 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
7376
7752
|
args: ['mainCanvas', { static: true }]
|
|
7377
7753
|
}] } });
|
|
7378
7754
|
|
|
7755
|
+
class ComponentHelper {
|
|
7756
|
+
constructor() {
|
|
7757
|
+
this.ecOnConstruct();
|
|
7758
|
+
}
|
|
7759
|
+
ecOnInit = (params = {}) => {
|
|
7760
|
+
};
|
|
7761
|
+
ecOnConstruct = (params = {}) => {
|
|
7762
|
+
};
|
|
7763
|
+
hasParams = (params, searched) => {
|
|
7764
|
+
if (!params || !searched)
|
|
7765
|
+
return false;
|
|
7766
|
+
const q = searched.trim().toLowerCase();
|
|
7767
|
+
return params.some(p => {
|
|
7768
|
+
const code = p?.['code']?.toString().toLowerCase() ?? '';
|
|
7769
|
+
// Primero chequeo exacto, y si no, parcial
|
|
7770
|
+
return code === q || code.includes(q);
|
|
7771
|
+
});
|
|
7772
|
+
};
|
|
7773
|
+
navigateOnRouter(router, url) {
|
|
7774
|
+
router.navigateByUrl(`/${url}`);
|
|
7775
|
+
}
|
|
7776
|
+
}
|
|
7777
|
+
|
|
7778
|
+
/**
|
|
7779
|
+
* Catch genérico para redirecciones de pagos.
|
|
7780
|
+
* - Normaliza el estado recibido por params/query.
|
|
7781
|
+
* - Informa el resultado al opener (postMessage), BroadcastChannel y localStorage.
|
|
7782
|
+
* - Intenta cerrarse; si el cierre falla, redirige según el estado.
|
|
7783
|
+
*/
|
|
7784
|
+
class RedsysCatchEcComponent extends ComponentHelper {
|
|
7785
|
+
activedRoute;
|
|
7786
|
+
router;
|
|
7787
|
+
checkoutService;
|
|
7788
|
+
renderer;
|
|
7789
|
+
elementRef;
|
|
7790
|
+
document;
|
|
7791
|
+
platformId;
|
|
7792
|
+
message = '';
|
|
7793
|
+
subscription = null;
|
|
7794
|
+
sid = '';
|
|
7795
|
+
bc;
|
|
7796
|
+
constructor(activedRoute, router, checkoutService, renderer, elementRef, document, platformId) {
|
|
7797
|
+
super();
|
|
7798
|
+
this.activedRoute = activedRoute;
|
|
7799
|
+
this.router = router;
|
|
7800
|
+
this.checkoutService = checkoutService;
|
|
7801
|
+
this.renderer = renderer;
|
|
7802
|
+
this.elementRef = elementRef;
|
|
7803
|
+
this.document = document;
|
|
7804
|
+
this.platformId = platformId;
|
|
7805
|
+
this.hideHeaderFooter();
|
|
7806
|
+
this.ecOnConstruct();
|
|
7807
|
+
}
|
|
7808
|
+
ngOnInit() {
|
|
7809
|
+
if (isPlatformBrowser(this.platformId) && 'BroadcastChannel' in window) {
|
|
7810
|
+
this.bc = new BroadcastChannel('mp_payment');
|
|
7811
|
+
}
|
|
7812
|
+
this.subscription = combineLatest([this.activedRoute.params, this.activedRoute.queryParams])
|
|
7813
|
+
.subscribe(([routeParams, q]) => {
|
|
7814
|
+
let stateStr = routeParams['state'];
|
|
7815
|
+
if (stateStr === 'statuspayment')
|
|
7816
|
+
stateStr = q['status'];
|
|
7817
|
+
const statusParam = (stateStr || q['status'] || q['state'] || '').toString();
|
|
7818
|
+
const state = this.normalizeState(statusParam);
|
|
7819
|
+
this.sid = (q['sid'] || (isPlatformBrowser(this.platformId) ? localStorage.getItem('mp:sid') : '') || '').toString();
|
|
7820
|
+
this.storeTotalAmount(q);
|
|
7821
|
+
this.setStateInLocal('Su pago fue procesado con éxito.', state);
|
|
7822
|
+
this.signalState(state);
|
|
7823
|
+
this.tryCloseSelf(() => {
|
|
7824
|
+
const target = (state === 'success' || state === 'pending')
|
|
7825
|
+
? ['/checkout/order_success']
|
|
7826
|
+
: ['/checkout'];
|
|
7827
|
+
setTimeout(() => this.router.navigate(target), 4500);
|
|
7828
|
+
});
|
|
7829
|
+
});
|
|
7830
|
+
this.ecOnInit();
|
|
7831
|
+
}
|
|
7832
|
+
ngOnDestroy() {
|
|
7833
|
+
this.subscription?.unsubscribe();
|
|
7834
|
+
this.bc?.close();
|
|
7835
|
+
this.showHeaderFooter();
|
|
7836
|
+
}
|
|
7837
|
+
/** Guarda total_amount si viene desde el PSP. */
|
|
7838
|
+
storeTotalAmount(queryParams) {
|
|
7839
|
+
const totalAmount = queryParams['total_amount'];
|
|
7840
|
+
if (totalAmount && isPlatformBrowser(this.platformId)) {
|
|
7841
|
+
localStorage.setItem('total_amount', totalAmount);
|
|
7842
|
+
}
|
|
7843
|
+
}
|
|
7844
|
+
/** Setea mensaje y estado en storages. */
|
|
7845
|
+
setStateInLocal = (mensaje, state) => {
|
|
7846
|
+
this.message = mensaje;
|
|
7847
|
+
if (!isPlatformBrowser(this.platformId))
|
|
7848
|
+
return;
|
|
7849
|
+
try {
|
|
7850
|
+
localStorage.setItem('state', state);
|
|
7851
|
+
}
|
|
7852
|
+
catch { }
|
|
7853
|
+
try {
|
|
7854
|
+
sessionStorage.setItem('modalnews', 'false');
|
|
7855
|
+
}
|
|
7856
|
+
catch { }
|
|
7857
|
+
};
|
|
7858
|
+
/** Normaliza estados heterogéneos de distintos gateways. */
|
|
7859
|
+
normalizeState(raw) {
|
|
7860
|
+
const v = (raw || '').toLowerCase();
|
|
7861
|
+
if (v === '200' || v === 'ok' || v === 'success')
|
|
7862
|
+
return 'success';
|
|
7863
|
+
if (v === 'pending')
|
|
7864
|
+
return 'pending';
|
|
7865
|
+
if (v === 'cancel')
|
|
7866
|
+
return 'cancel';
|
|
7867
|
+
return 'failure'; // failure, 0, error, rejected, chargeback, desconocidos
|
|
7868
|
+
}
|
|
7869
|
+
/**
|
|
7870
|
+
* Informa el resultado: postMessage al opener, BroadcastChannel y localStorage
|
|
7871
|
+
* (este último permite polling en la pestaña madre).
|
|
7872
|
+
*/
|
|
7873
|
+
signalState(state) {
|
|
7874
|
+
if (!isPlatformBrowser(this.platformId))
|
|
7875
|
+
return;
|
|
7876
|
+
const sid = this.sid || localStorage.getItem('mp:sid') || '';
|
|
7877
|
+
const payload = { type: 'mp:state', sid, state };
|
|
7878
|
+
try {
|
|
7879
|
+
window.opener && window.opener.postMessage(payload, '*');
|
|
7880
|
+
}
|
|
7881
|
+
catch { }
|
|
7882
|
+
try {
|
|
7883
|
+
this.bc?.postMessage(payload);
|
|
7884
|
+
}
|
|
7885
|
+
catch { }
|
|
7886
|
+
try {
|
|
7887
|
+
localStorage.setItem(`mp:state:${sid}`, state);
|
|
7888
|
+
}
|
|
7889
|
+
catch { }
|
|
7890
|
+
try {
|
|
7891
|
+
localStorage.setItem('state', state);
|
|
7892
|
+
}
|
|
7893
|
+
catch { }
|
|
7894
|
+
}
|
|
7895
|
+
/** Intenta cerrar la pestaña actual; si falla, ejecuta el callback de fallback. */
|
|
7896
|
+
tryCloseSelf(onFail) {
|
|
7897
|
+
if (!isPlatformBrowser(this.platformId))
|
|
7898
|
+
return onFail();
|
|
7899
|
+
let attempted = false;
|
|
7900
|
+
try {
|
|
7901
|
+
window.close();
|
|
7902
|
+
attempted = true;
|
|
7903
|
+
}
|
|
7904
|
+
catch { }
|
|
7905
|
+
if (!attempted)
|
|
7906
|
+
onFail();
|
|
7907
|
+
}
|
|
7908
|
+
/** Oculta header/footer para esta pantalla mínima. */
|
|
7909
|
+
hideHeaderFooter() {
|
|
7910
|
+
if (!isPlatformBrowser(this.platformId))
|
|
7911
|
+
return;
|
|
7912
|
+
const header = this.document.querySelector('header');
|
|
7913
|
+
const footer = this.document.querySelector('footer');
|
|
7914
|
+
if (header)
|
|
7915
|
+
this.renderer.setStyle(header, 'display', 'none');
|
|
7916
|
+
if (footer)
|
|
7917
|
+
this.renderer.setStyle(footer, 'display', 'none');
|
|
7918
|
+
}
|
|
7919
|
+
/** Restaura header/footer al salir. */
|
|
7920
|
+
showHeaderFooter() {
|
|
7921
|
+
if (!isPlatformBrowser(this.platformId))
|
|
7922
|
+
return;
|
|
7923
|
+
const header = this.document.querySelector('header');
|
|
7924
|
+
const footer = this.document.querySelector('footer');
|
|
7925
|
+
if (header)
|
|
7926
|
+
this.renderer.removeStyle(header, 'display');
|
|
7927
|
+
if (footer)
|
|
7928
|
+
this.renderer.removeStyle(footer, 'display');
|
|
7929
|
+
}
|
|
7930
|
+
setStateInSession(mensaje, state) {
|
|
7931
|
+
this.message = mensaje;
|
|
7932
|
+
if (!isPlatformBrowser(this.platformId))
|
|
7933
|
+
return;
|
|
7934
|
+
try {
|
|
7935
|
+
sessionStorage.setItem('state', state);
|
|
7936
|
+
}
|
|
7937
|
+
catch { }
|
|
7938
|
+
try {
|
|
7939
|
+
localStorage.setItem('state', state);
|
|
7940
|
+
}
|
|
7941
|
+
catch { }
|
|
7942
|
+
try {
|
|
7943
|
+
sessionStorage.setItem('modalnews', 'false');
|
|
7944
|
+
}
|
|
7945
|
+
catch { }
|
|
7946
|
+
}
|
|
7947
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RedsysCatchEcComponent, deps: [{ token: i2.ActivatedRoute }, { token: i2.Router }, { token: CheckoutService }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: DOCUMENT }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Component });
|
|
7948
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: RedsysCatchEcComponent, isStandalone: true, selector: "app-redsys-catch-ec", usesInheritance: true, ngImport: i0, template: "<div id=\"container\">\r\n <div class=\"row\">\r\n <div class=\"col align-self-center\">\r\n <h4 class=\"titpage center-block text-center font-nexa font-lg my-3\">{{ message | uppercase }}</h4>\r\n </div>\r\n </div>\r\n <div class=\"row\">\r\n <div class=\"col align-self-center\">\r\n <h5 class=\"center-block text-center font-nexa my-3\">Redirigiendo en segundos...</h5>\r\n <br>\r\n <div class=\"d-flex flex-column jusitfy-content-center align-items-center\">\r\n <app-loading-full-ec></app-loading-full-ec>\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: [".loader{border:16px solid #f3f3f3;border-top:16px solid #dc3545;border-radius:50%;width:50px;height:50px;animation:spin 2s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.flex-container{display:flex;justify-content:center;align-items:center;height:80vh;width:100%}.flex-container>div{width:90%;height:100px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.UpperCasePipe, name: "uppercase" }, { kind: "component", type: LoadingFullEcComponent, selector: "app-loading-full-ec" }] });
|
|
7949
|
+
}
|
|
7950
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RedsysCatchEcComponent, decorators: [{
|
|
7951
|
+
type: Component,
|
|
7952
|
+
args: [{ selector: 'app-redsys-catch-ec', standalone: true, imports: [CommonModule, LoadingFullEcComponent], template: "<div id=\"container\">\r\n <div class=\"row\">\r\n <div class=\"col align-self-center\">\r\n <h4 class=\"titpage center-block text-center font-nexa font-lg my-3\">{{ message | uppercase }}</h4>\r\n </div>\r\n </div>\r\n <div class=\"row\">\r\n <div class=\"col align-self-center\">\r\n <h5 class=\"center-block text-center font-nexa my-3\">Redirigiendo en segundos...</h5>\r\n <br>\r\n <div class=\"d-flex flex-column jusitfy-content-center align-items-center\">\r\n <app-loading-full-ec></app-loading-full-ec>\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: [".loader{border:16px solid #f3f3f3;border-top:16px solid #dc3545;border-radius:50%;width:50px;height:50px;animation:spin 2s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.flex-container{display:flex;justify-content:center;align-items:center;height:80vh;width:100%}.flex-container>div{width:90%;height:100px}\n"] }]
|
|
7953
|
+
}], ctorParameters: () => [{ type: i2.ActivatedRoute }, { type: i2.Router }, { type: CheckoutService }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: Document, decorators: [{
|
|
7954
|
+
type: Inject,
|
|
7955
|
+
args: [DOCUMENT]
|
|
7956
|
+
}] }, { type: undefined, decorators: [{
|
|
7957
|
+
type: Inject,
|
|
7958
|
+
args: [PLATFORM_ID]
|
|
7959
|
+
}] }] });
|
|
7960
|
+
|
|
7379
7961
|
// export * from './rating-ec/rating-ec.component';
|
|
7380
7962
|
|
|
7381
7963
|
class BlockFormContactEcComponent extends BlockEcComponent {
|
|
@@ -7651,6 +8233,7 @@ class LoginFormEcComponent {
|
|
|
7651
8233
|
_formBuilder = inject(FormBuilder);
|
|
7652
8234
|
_toastService = inject(ToastService);
|
|
7653
8235
|
_router = inject(Router);
|
|
8236
|
+
showPassword = false;
|
|
7654
8237
|
/**
|
|
7655
8238
|
* Parametro para indicar si tras loguear
|
|
7656
8239
|
* debe redireccionar o no.
|
|
@@ -7739,6 +8322,9 @@ class LoginFormEcComponent {
|
|
|
7739
8322
|
? resolverFunction()
|
|
7740
8323
|
: this._router.navigateByUrl(this.redirectTo);
|
|
7741
8324
|
}
|
|
8325
|
+
togglePassword() {
|
|
8326
|
+
this.showPassword = !this.showPassword;
|
|
8327
|
+
}
|
|
7742
8328
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LoginFormEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7743
8329
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: LoginFormEcComponent, isStandalone: true, selector: "app-login-form-ec", inputs: { redirect: "redirect", redirectTo: "redirectTo", inCart: "inCart" }, outputs: { ready: "ready" }, ngImport: i0, template: "<div class=\"d-flex flex-column position-relative\">\r\n <h1 class=\"right-line ff-ubuntu-light mb-4\"><span>Ingresar</span></h1>\r\n <p class=\"ff-ubuntu-light font-sm pr-4 mb-4\">\r\n Si ya est\u00E1s registrado. Ingresa en tu cuenta con tu email y la\r\n contrase\u00F1a adecuada.\r\n </p>\r\n <div class=\"w-md-50 w-100 text-center\">\r\n <form [formGroup]=\"loginForm()\" (submit)=\"login($event)\">\r\n <input class=\"form-control mb-4 radius-0\" type=\"email\" formControlName=\"username\"\r\n placeholder=\"Correo Electr\u00F3nico\">\r\n <input class=\"form-control mb-4 radius-0\" type=\"password\" formControlName=\"password\"\r\n placeholder=\"Contrase\u00F1a\">\r\n\r\n <div class=\"row d-flex flex-column\">\r\n <div class=\"col-12 mb-4\">\r\n <button type=\"submit\"\r\n class=\"bg-gray border-0 px-4 py-2 color-white ff-ubuntu-light\">INGRESAR</button>\r\n </div>\r\n <div class=\"col-12 d-flex justify-content-center align-items-center\">\r\n <a [routerLink]=\"'/auth/forgot-password'\" class=\"font-md ff-ubuntu-light\">\r\n \u00BFOlvid\u00F3 su contrase\u00F1a?\r\n </a>\r\n </div>\r\n </div>\r\n </form>\r\n </div>\r\n @if(loading){\r\n <app-loading-section-ec></app-loading-section-ec>\r\n }\r\n</div>", styles: [""], dependencies: [{ kind: "component", type: LoadingSectionEcComponent, selector: "app-loading-section-ec" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] });
|
|
7744
8330
|
}
|
|
@@ -7838,6 +8424,7 @@ class RegisterFormEcComponent {
|
|
|
7838
8424
|
_analyticsService = inject(AnalyticsService);
|
|
7839
8425
|
_formBuilder = inject(FormBuilder);
|
|
7840
8426
|
channelConfigService = inject(ChannelService);
|
|
8427
|
+
showPassword = false;
|
|
7841
8428
|
/**
|
|
7842
8429
|
* Indica si debe redireccionar o se queda en la misma pantalla
|
|
7843
8430
|
*/
|
|
@@ -7953,6 +8540,9 @@ class RegisterFormEcComponent {
|
|
|
7953
8540
|
this.register_loading = false;
|
|
7954
8541
|
}
|
|
7955
8542
|
}
|
|
8543
|
+
togglePassword() {
|
|
8544
|
+
this.showPassword = !this.showPassword;
|
|
8545
|
+
}
|
|
7956
8546
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RegisterFormEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7957
8547
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: RegisterFormEcComponent, isStandalone: true, selector: "app-register-form-ec", inputs: { redirect: "redirect" }, outputs: { ready: "ready" }, ngImport: i0, template: "<div class=\"w-100 pl-md-5 position-relative\" id=\"register\">\r\n <div class=\"py-2\">\r\n <h5>CREAR CUENTA</h5>\r\n </div>\r\n <form id=\"registro\" [formGroup]=\"registerForm\" (submit)=\"register($event)\">\r\n <div class=\"form-group\">\r\n <label for=\"\" class=\"form-label\">NOMBRE</label>\r\n <input formControlName=\"firstName\" class=\"form-control rounded-0\" type=\"text\" placeholder=\"Nombre\">\r\n </div>\r\n <div class=\"form-group\">\r\n <label for=\"\" class=\"form-label\">APELLIDO</label>\r\n <input formControlName=\"lastName\" class=\"form-control rounded-0\" type=\"text\" placeholder=\"Apellido\">\r\n </div>\r\n <div class=\"form-group\">\r\n <label for=\"\" class=\"\">CORREO ELECTRONICO</label>\r\n <input formControlName=\"email\" email required class=\"form-control rounded-0\" type=\"email\"\r\n placeholder=\"Correo electr\u00F3nico\">\r\n </div>\r\n <div class=\"form-group\">\r\n <label for=\"\" class=\"form-label\">CONTRASE\u00D1A</label>\r\n <input formControlName=\"plainPassword\" required class=\"form-control rounded-0\" type=\"password\"\r\n placeholder=\"Contrase\u00F1a\">\r\n </div>\r\n <div class=\"form-group\">\r\n <label for=\"\" class=\"form-label\">REPETIR CONTRASE\u00D1A</label>\r\n <input formControlName=\"plainPassword2\" required class=\"form-control rounded-0\" type=\"password\"\r\n placeholder=\"Repetir contrase\u00F1a\">\r\n </div>\r\n\r\n <div class=\"custom-control d-flex flex-row form-check custom-checkbox mr-sm-2 mt-4 mb-2\">\r\n <input type=\"checkbox\" formControlName=\"terms\" required class=\"custom-control-input form-check-input\" name=\"Color2\"\r\n id=\"Color2\">\r\n <label class=\"custom-control-label ff-ubuntu-light font-sm form-check-label\" for=\"Color2\"> He\r\n le\u00EDdo y acepto las pol\u00EDticas de privacidad y los t\u00E9rminos y\r\n condiciones</label>\r\n </div>\r\n\r\n <div class=\"custom-control d-flex flex-row form-check custom-checkbox mr-sm-2 mb-4\">\r\n <input type=\"checkbox\" formControlName=\"newsletter\" class=\"custom-control-input form-check-input\" name=\"Color3\" id=\"Color3\">\r\n <label class=\"custom-control-label form-check-label ff-ubuntu-light font-sm\" for=\"Color3\">\r\n Suscripci\u00F3n al Newsletter</label>\r\n </div>\r\n\r\n <div class=\"row\">\r\n <div class=\"col-12\">\r\n <button [disabled]=\"registerForm.invalid\" type=\"submit\"\r\n class=\"btn btn-primary px-5 py-2 h-fit\">CREAR</button>\r\n </div>\r\n </div>\r\n </form>\r\n @if(loading){\r\n <app-loading-section-ec />\r\n }\r\n \r\n</div>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$3.CheckboxRequiredValidator, selector: "input[type=checkbox][required][formControlName],input[type=checkbox][required][formControl],input[type=checkbox][required][ngModel]" }, { kind: "directive", type: i1$3.EmailValidator, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: ["email"] }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: LoadingSectionEcComponent, selector: "app-loading-section-ec" }] });
|
|
7958
8548
|
}
|
|
@@ -8107,20 +8697,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
8107
8697
|
type: Output
|
|
8108
8698
|
}] } });
|
|
8109
8699
|
|
|
8110
|
-
class ComponentHelper {
|
|
8111
|
-
constructor() {
|
|
8112
|
-
this.ecOnConstruct();
|
|
8113
|
-
}
|
|
8114
|
-
ecOnInit = (params = {}) => {
|
|
8115
|
-
};
|
|
8116
|
-
ecOnConstruct = (params = {}) => {
|
|
8117
|
-
};
|
|
8118
|
-
hasParams = (params, searched) => params && params != null && params.find(param => param['code']?.toLowerCase().includes(searched.toLowerCase())) !== undefined;
|
|
8119
|
-
navigateOnRouter(router, url) {
|
|
8120
|
-
router.navigateByUrl(`/${url}`);
|
|
8121
|
-
}
|
|
8122
|
-
}
|
|
8123
|
-
|
|
8124
8700
|
class PasswordResetEcComponent extends ComponentHelper {
|
|
8125
8701
|
authService;
|
|
8126
8702
|
toastr;
|
|
@@ -8330,6 +8906,14 @@ class FiltersEcComponent {
|
|
|
8330
8906
|
});
|
|
8331
8907
|
}) ?? false;
|
|
8332
8908
|
}
|
|
8909
|
+
/**
|
|
8910
|
+
* Verifica si una categoría tiene la propiedad isVisible y está marcada como visible
|
|
8911
|
+
* @param category - La categoría a verificar
|
|
8912
|
+
* @returns true si la categoría es visible, false en caso contrario
|
|
8913
|
+
*/
|
|
8914
|
+
hasVisibleProperty(category) {
|
|
8915
|
+
return category.isVisible === true;
|
|
8916
|
+
}
|
|
8333
8917
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FiltersEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8334
8918
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: FiltersEcComponent, isStandalone: true, selector: "lib-filters-ec", inputs: { setSelect: "setSelect" }, ngImport: i0, template: "<p>filters-ec works!</p>\r\n", styles: [""] });
|
|
8335
8919
|
}
|
|
@@ -8410,6 +8994,7 @@ class ProductDetailEcComponent {
|
|
|
8410
8994
|
routeSubscription;
|
|
8411
8995
|
route = inject(ActivatedRoute);
|
|
8412
8996
|
currentProductId;
|
|
8997
|
+
_router = inject(Router);
|
|
8413
8998
|
ngOnDestroy() {
|
|
8414
8999
|
this.routeSubscription?.unsubscribe();
|
|
8415
9000
|
}
|
|
@@ -8471,11 +9056,12 @@ class ProductDetailEcComponent {
|
|
|
8471
9056
|
}
|
|
8472
9057
|
updateMetaTags(product) {
|
|
8473
9058
|
const descripcionLimpia = he.decode(product.description || '').replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim();
|
|
8474
|
-
const currentUrl = this._consts.
|
|
9059
|
+
const currentUrl = this._consts.getFrontendUrl() + this._router.url; // URL absoluta del producto
|
|
9060
|
+
const imageUrl = this._consts.getAbsoluteImageUrl(Array.isArray(product.picturesdefault) ? product.picturesdefault[0] : product.picturesdefault);
|
|
8475
9061
|
this._meta.updateTag({ property: 'og:title', content: product.name || '' });
|
|
8476
9062
|
this._meta.updateTag({ property: 'og:description', content: descripcionLimpia || '' });
|
|
8477
|
-
this._meta.updateTag({ property: 'og:image', content:
|
|
8478
|
-
this._meta.updateTag({ property: 'og:url', content: currentUrl });
|
|
9063
|
+
this._meta.updateTag({ property: 'og:image', content: imageUrl || '' });
|
|
9064
|
+
// this._meta.updateTag({ property: 'og:url', content: currentUrl });
|
|
8479
9065
|
this._meta.updateTag({ property: 'og:type', content: 'product' });
|
|
8480
9066
|
}
|
|
8481
9067
|
decodeHtml(html) {
|
|
@@ -8497,25 +9083,31 @@ class ProductDetailEcComponent {
|
|
|
8497
9083
|
}, 2000);
|
|
8498
9084
|
}
|
|
8499
9085
|
plus(stock, multipleQuantity) {
|
|
9086
|
+
const current = Number(this.quantity()); // <-- fuerza a número
|
|
8500
9087
|
if (multipleQuantity && multipleQuantity > 0) {
|
|
8501
|
-
stock
|
|
8502
|
-
?
|
|
8503
|
-
|
|
8504
|
-
|
|
9088
|
+
stock
|
|
9089
|
+
? (current < stock
|
|
9090
|
+
? this.quantity.set(current + multipleQuantity)
|
|
9091
|
+
: this._toastService.show('out-of-stock-actually'))
|
|
9092
|
+
: this.quantity.set(current + multipleQuantity);
|
|
8505
9093
|
}
|
|
8506
9094
|
else {
|
|
8507
|
-
stock
|
|
8508
|
-
?
|
|
8509
|
-
|
|
8510
|
-
|
|
9095
|
+
stock
|
|
9096
|
+
? (current < stock
|
|
9097
|
+
? this.quantity.set(current + 1)
|
|
9098
|
+
: this._toastService.show('out-of-stock-actually'))
|
|
9099
|
+
: this.quantity.set(current + 1);
|
|
8511
9100
|
}
|
|
8512
9101
|
}
|
|
8513
9102
|
less(multipleQuantity) {
|
|
9103
|
+
const current = Number(this.quantity()); // <-- fuerza a número
|
|
8514
9104
|
if (multipleQuantity && multipleQuantity > 0) {
|
|
8515
|
-
|
|
9105
|
+
current > multipleQuantity
|
|
9106
|
+
? this.quantity.set(current - multipleQuantity)
|
|
9107
|
+
: null;
|
|
8516
9108
|
}
|
|
8517
9109
|
else {
|
|
8518
|
-
|
|
9110
|
+
current > 1 ? this.quantity.set(current - 1) : null;
|
|
8519
9111
|
}
|
|
8520
9112
|
}
|
|
8521
9113
|
checkStock(stock) {
|
|
@@ -8621,13 +9213,19 @@ class CartEcComponent {
|
|
|
8621
9213
|
isAuthenticated$ = this._authService.isAuthenticated();
|
|
8622
9214
|
getTotalAmount = this._cartService.getTotalAmount();
|
|
8623
9215
|
couponCode$ = this._cartService.getCouponCode();
|
|
9216
|
+
hideTaxes = false;
|
|
9217
|
+
injector;
|
|
8624
9218
|
constructor() {
|
|
8625
9219
|
//console.log("constructo.....");
|
|
9220
|
+
this.injector = inject(Injector);
|
|
8626
9221
|
this._channelService.channel$.subscribe((res) => {
|
|
8627
9222
|
//console.log("construct")
|
|
8628
9223
|
this.channel = res;
|
|
8629
9224
|
//this.initializeSteps();
|
|
8630
9225
|
});
|
|
9226
|
+
this.injector.get(ChannelService).channel$.subscribe(channel => {
|
|
9227
|
+
this.hideTaxes = !!channel.hideTaxes;
|
|
9228
|
+
});
|
|
8631
9229
|
}
|
|
8632
9230
|
removeCoupon() {
|
|
8633
9231
|
// console.log(this.couponCode$)
|
|
@@ -8699,6 +9297,7 @@ class CartItemEcComponent {
|
|
|
8699
9297
|
_cartService = inject(CartService);
|
|
8700
9298
|
_toastService = inject(ToastService);
|
|
8701
9299
|
_constants = inject(CoreConstantsService);
|
|
9300
|
+
parametersService = inject(ParametersService);
|
|
8702
9301
|
mediaUrl = this._constants.mediaUrl();
|
|
8703
9302
|
quantity = 0;
|
|
8704
9303
|
variantsToShow = ['TALLA', 'COLOR'];
|
|
@@ -8709,28 +9308,56 @@ class CartItemEcComponent {
|
|
|
8709
9308
|
// console.log(this.item, this.mediaUrl);
|
|
8710
9309
|
}
|
|
8711
9310
|
updateQuantity(stock) {
|
|
9311
|
+
const originalQuantity = this.item.quantity; // Guardar cantidad original
|
|
8712
9312
|
if (this.quantity > 0 && this.quantity <= stock) {
|
|
8713
|
-
this._cartService.updateItemQuantity(this.item, this.quantity);
|
|
9313
|
+
const success = this._cartService.updateItemQuantity(this.item, this.quantity);
|
|
9314
|
+
// Si la validación falló, restaurar la cantidad original
|
|
9315
|
+
if (!success) {
|
|
9316
|
+
this.quantity = originalQuantity;
|
|
9317
|
+
}
|
|
8714
9318
|
}
|
|
8715
9319
|
else {
|
|
8716
|
-
|
|
9320
|
+
// Restaurar cantidad original si está fuera de rango
|
|
9321
|
+
this.quantity = originalQuantity;
|
|
8717
9322
|
this._toastService.show('out-of-stock-actually');
|
|
8718
9323
|
}
|
|
8719
9324
|
}
|
|
8720
|
-
|
|
9325
|
+
plus(stock, value = 1) {
|
|
8721
9326
|
if (this.isQuantityUpdating)
|
|
8722
9327
|
return;
|
|
8723
9328
|
this.isQuantityUpdating = true;
|
|
8724
|
-
let
|
|
8725
|
-
|
|
9329
|
+
let newQuantity = Number(this.quantity) + value; // Forzar a número
|
|
9330
|
+
// Verificar stock ANTES de llamar al servicio
|
|
9331
|
+
if (newQuantity > stock) {
|
|
9332
|
+
this._toastService.show('out-of-stock-actually');
|
|
9333
|
+
setTimeout(() => { this.isQuantityUpdating = false; }, 1000);
|
|
9334
|
+
return;
|
|
9335
|
+
}
|
|
9336
|
+
const success = this._cartService.updateItemQuantity(this.item, newQuantity);
|
|
9337
|
+
// Solo actualizar el input si la operación fue exitosa
|
|
9338
|
+
if (success) {
|
|
9339
|
+
this.quantity = newQuantity;
|
|
9340
|
+
}
|
|
9341
|
+
// Si success es false, NO mostrar mensaje aquí porque ya lo mostró validateQuantity()
|
|
8726
9342
|
setTimeout(() => { this.isQuantityUpdating = false; }, 1000);
|
|
8727
9343
|
}
|
|
8728
|
-
|
|
9344
|
+
less(stock, value = 1) {
|
|
8729
9345
|
if (this.isQuantityUpdating)
|
|
8730
9346
|
return;
|
|
8731
9347
|
this.isQuantityUpdating = true;
|
|
8732
|
-
let
|
|
8733
|
-
|
|
9348
|
+
let newQuantity = Number(this.quantity) - value; // Forzar a número
|
|
9349
|
+
// Verificar cantidad mínima ANTES de llamar al servicio
|
|
9350
|
+
if (newQuantity <= 0) {
|
|
9351
|
+
// No permitir cantidades menores o iguales a 0
|
|
9352
|
+
setTimeout(() => { this.isQuantityUpdating = false; }, 1000);
|
|
9353
|
+
return;
|
|
9354
|
+
}
|
|
9355
|
+
const success = this._cartService.updateItemQuantity(this.item, newQuantity);
|
|
9356
|
+
// Solo actualizar el input si la operación fue exitosa
|
|
9357
|
+
if (success) {
|
|
9358
|
+
this.quantity = newQuantity;
|
|
9359
|
+
}
|
|
9360
|
+
// Si success es false, NO mostrar mensaje aquí porque ya lo mostró validateQuantity()
|
|
8734
9361
|
setTimeout(() => { this.isQuantityUpdating = false; }, 1000);
|
|
8735
9362
|
}
|
|
8736
9363
|
deleteCartItem() {
|
|
@@ -8785,6 +9412,9 @@ class CartItemEcComponent {
|
|
|
8785
9412
|
}
|
|
8786
9413
|
return false; // Solo se ejecuta si no se cumple la condición
|
|
8787
9414
|
}
|
|
9415
|
+
// PARAMETROS
|
|
9416
|
+
parameters$ = this.parametersService.getParameters();
|
|
9417
|
+
hasParams = this.parametersService.hasParams;
|
|
8788
9418
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CartItemEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8789
9419
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: CartItemEcComponent, isStandalone: true, selector: "app-cart-item-ec", inputs: { item: "item", inSidebar: "inSidebar" }, ngImport: i0, template: "@if(!inSidebar){\r\n<p>cart-item-ec works!</p>\r\n}@else{\r\n\r\n<div class=\"row\">\r\n <div class=\"col-3\">\r\n @let product= item.product;\r\n @if(item.variant_id && product.variants.length>0){\r\n <img [src]=\"mediaUrl + product.variants[0].images[0]\" alt=\"\" class=\"img-fluid\">\r\n }@else{\r\n <img [src]=\"mediaUrl + product.picturesdefault[0]\" alt=\"\" class=\"img-fluid\">\r\n }\r\n </div>\r\n <div class=\"col-7\">\r\n <div class=\"info d-flex flex-column align-items-start\">\r\n @if (item.product.special_mark?.length > 0 || item.product.saleprice) {\r\n <div class=\"marcas\">\r\n <img [src]=\"mediaUrl + (item.product.special_mark?.[0]?.images[0] || '')\" alt=\"\">\r\n\r\n @if (item.product.saleprice) {\r\n <div class=\"tag-dsc\">\r\n {{\r\n createDiscountMessage(item.product.saleprice,\r\n item.product.price)\r\n }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n <a class=\"title text-dark text-decoration-none m-0 p-0 h6 mb-0\"\r\n [routerLink]=\"['/product', item.variant_id]\">{{\r\n item.product.name | titlecase\r\n }}</a>\r\n <div class=\"qty1\">\r\n <span>{{ item.product.id}}</span>\r\n </div>\r\n <div class=\"price h6 fw-bold mb-0 pb-0\">{{ item.product.price | ecCurrencySymbol\r\n }}</div>\r\n @if(getVariants(item); as options){\r\n <div class=\"d-flex align-items-center p-0\">\r\n @for(option of options; track $index){\r\n <span class=\"me-1\"> {{option.name | titlecase}}:</span>\r\n @if(option.name == 'COLOR'){\r\n <div class=\"p-2 rounded\" [style.background]=\"'#' + option.value\"></div>\r\n }@else{\r\n <b>{{option.value}}</b>\r\n }\r\n }\r\n </div>\r\n }\r\n <div class=\"campoCantidad mt-2\">\r\n <div class=\"numero\">\r\n <button (click)=\"less(item.product.variants[0]?.stock)\" class=\"btn btn-outline-secondary\"\r\n type=\"button\" id=\"button-addon1\">\r\n <i class=\"fa fa-minus\" aria-hidden=\"true\"></i>\r\n </button>\r\n <input type=\"text\" class=\"form-control text-center\" placeholder=\"\"\r\n aria-label=\"Example text with button addon\" aria-describedby=\"button-addon1\"\r\n [value]=\"item.quantity\" min=\"1\" step=\"1\" [(ngModel)]=\"quantity\"\r\n (change)=\"updateQuantity(item.product.variants[0]?.stock)\">\r\n <button (click)=\"plus(item.product.variants[0]?.stock)\" class=\"btn btn-outline-secondary\"\r\n type=\"button\" id=\"button-addon1\">\r\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i>\r\n </button>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"col-2\">\r\n <a (click)=\"deleteCartItem()\" class=\"btn botBorrar\"><i class=\"fa fa-trash\" aria-hidden=\"true\"></i></a>\r\n </div>\r\n</div>\r\n\r\n\r\n\r\n\r\n\r\n}", styles: [""], dependencies: [{ kind: "pipe", type: TitleCasePipe, name: "titlecase" }, { kind: "pipe", type: EcCurrencySymbolPipe, name: "ecCurrencySymbol" }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
|
|
8790
9420
|
}
|
|
@@ -9296,108 +9926,174 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
9296
9926
|
class MpRedirectEcComponent {
|
|
9297
9927
|
_paymentService = inject(PaymentService);
|
|
9298
9928
|
_toastService = inject(ToastService);
|
|
9929
|
+
platformId = inject(PLATFORM_ID);
|
|
9930
|
+
finished = false;
|
|
9299
9931
|
method = null;
|
|
9300
9932
|
total_amount = 0;
|
|
9301
9933
|
allData;
|
|
9302
9934
|
ready = new EventEmitter();
|
|
9303
9935
|
preference;
|
|
9304
|
-
loading = false;
|
|
9305
9936
|
url;
|
|
9306
|
-
|
|
9307
|
-
|
|
9308
|
-
|
|
9309
|
-
|
|
9310
|
-
|
|
9311
|
-
|
|
9937
|
+
// Fases de UI
|
|
9938
|
+
phase = 'idle';
|
|
9939
|
+
get isIdle() { return this.phase === 'idle'; }
|
|
9940
|
+
get isPaying() { return this.phase === 'paying'; }
|
|
9941
|
+
get isFinalizing() { return this.phase === 'finalizing'; }
|
|
9942
|
+
ventana = null;
|
|
9943
|
+
windowRef;
|
|
9944
|
+
sid = '';
|
|
9945
|
+
bc;
|
|
9946
|
+
pollTimer;
|
|
9947
|
+
pollStartedAt = 0;
|
|
9948
|
+
ngOnInit() {
|
|
9312
9949
|
if (isPlatformBrowser(this.platformId)) {
|
|
9313
|
-
this.
|
|
9314
|
-
|
|
9950
|
+
this.windowRef = window;
|
|
9951
|
+
if ('BroadcastChannel' in window) {
|
|
9952
|
+
this.bc = new BroadcastChannel('mp_payment');
|
|
9953
|
+
this.bc.onmessage = (e) => this.onMpMessage(e?.data);
|
|
9954
|
+
}
|
|
9955
|
+
window.addEventListener('storage', this.onStorage);
|
|
9956
|
+
window.addEventListener('message', this.onWindowMessage);
|
|
9315
9957
|
}
|
|
9316
|
-
}
|
|
9317
|
-
ngOnInit() {
|
|
9318
9958
|
this.getPreference();
|
|
9319
9959
|
}
|
|
9960
|
+
ngOnDestroy() {
|
|
9961
|
+
if (!isPlatformBrowser(this.platformId))
|
|
9962
|
+
return;
|
|
9963
|
+
this.bc?.close();
|
|
9964
|
+
window.removeEventListener('storage', this.onStorage);
|
|
9965
|
+
window.removeEventListener('message', this.onWindowMessage);
|
|
9966
|
+
if (this.pollTimer)
|
|
9967
|
+
clearInterval(this.pollTimer);
|
|
9968
|
+
}
|
|
9969
|
+
/** Cancela manualmente el pago y finaliza el flujo con estado "cancel". */
|
|
9320
9970
|
clickClose = () => {
|
|
9321
|
-
|
|
9322
|
-
|
|
9971
|
+
if (this.finished)
|
|
9972
|
+
return;
|
|
9973
|
+
this.finishWithState('cancel');
|
|
9323
9974
|
};
|
|
9975
|
+
/**
|
|
9976
|
+
* Inicia el pago abriendo `init_point` en una ventana/pestaña nueva.
|
|
9977
|
+
* Genera un SID y lo persiste para casar la respuesta del catch.
|
|
9978
|
+
* Si el popup es bloqueado, hace fallback navegando en la misma pestaña.
|
|
9979
|
+
*/
|
|
9324
9980
|
iniciar = () => {
|
|
9325
|
-
this.
|
|
9326
|
-
|
|
9327
|
-
this.
|
|
9328
|
-
this.
|
|
9329
|
-
|
|
9330
|
-
|
|
9331
|
-
|
|
9332
|
-
|
|
9333
|
-
this.
|
|
9334
|
-
|
|
9335
|
-
|
|
9336
|
-
|
|
9337
|
-
|
|
9338
|
-
|
|
9339
|
-
|
|
9340
|
-
|
|
9341
|
-
|
|
9342
|
-
|
|
9343
|
-
|
|
9344
|
-
this.
|
|
9345
|
-
this.
|
|
9346
|
-
|
|
9347
|
-
}
|
|
9348
|
-
if (state == 'failure') {
|
|
9349
|
-
this.ventana?.close();
|
|
9350
|
-
this.processError('');
|
|
9351
|
-
return;
|
|
9352
|
-
}
|
|
9353
|
-
if (state == 'cancel') {
|
|
9354
|
-
this.ventana?.close();
|
|
9355
|
-
this.processError('Se cancelo el pago con mercado pago');
|
|
9981
|
+
if (!isPlatformBrowser(this.platformId) || !this.windowRef || !this.url)
|
|
9982
|
+
return;
|
|
9983
|
+
this.phase = 'paying';
|
|
9984
|
+
this.sid = this.genSid();
|
|
9985
|
+
const url = new URL(this.url);
|
|
9986
|
+
localStorage.setItem('mp:sid', this.sid);
|
|
9987
|
+
this.ventana = this.windowRef.open(this.url, '_blank');
|
|
9988
|
+
// popup bloqueado → fallback a navegación en misma pestaña
|
|
9989
|
+
if (!this.ventana || this.ventana.closed) {
|
|
9990
|
+
this.windowRef.location.href = this.url;
|
|
9991
|
+
return;
|
|
9992
|
+
}
|
|
9993
|
+
// polling de último recurso (hasta 10 minutos)
|
|
9994
|
+
this.pollStartedAt = Date.now();
|
|
9995
|
+
if (this.pollTimer)
|
|
9996
|
+
clearInterval(this.pollTimer);
|
|
9997
|
+
this.pollTimer = setInterval(() => {
|
|
9998
|
+
if (Date.now() - this.pollStartedAt > 10 * 60 * 1000) {
|
|
9999
|
+
clearInterval(this.pollTimer);
|
|
10000
|
+
this.pollTimer = null;
|
|
10001
|
+
this.phase = 'idle';
|
|
10002
|
+
this.processError('Tiempo de espera agotado al procesar el pago.');
|
|
9356
10003
|
return;
|
|
9357
10004
|
}
|
|
9358
|
-
this.
|
|
9359
|
-
|
|
10005
|
+
this.checkLocalStorageOnce();
|
|
10006
|
+
}, 1000);
|
|
10007
|
+
};
|
|
10008
|
+
onWindowMessage = (event) => {
|
|
10009
|
+
const data = event?.data;
|
|
10010
|
+
this.onMpMessage(data);
|
|
10011
|
+
};
|
|
10012
|
+
onStorage = (e) => {
|
|
10013
|
+
if (!e.key || !this.sid)
|
|
9360
10014
|
return;
|
|
10015
|
+
if (e.key === `mp:state:${this.sid}` && e.newValue) {
|
|
10016
|
+
const state = e.newValue;
|
|
10017
|
+
this.finishWithState(state);
|
|
9361
10018
|
}
|
|
9362
|
-
setTimeout(() => {
|
|
9363
|
-
this.callState();
|
|
9364
|
-
}, 5000);
|
|
9365
10019
|
};
|
|
9366
|
-
|
|
9367
|
-
|
|
9368
|
-
|
|
10020
|
+
onMpMessage = (data) => {
|
|
10021
|
+
if (!data || data.type !== 'mp:state')
|
|
10022
|
+
return;
|
|
10023
|
+
if (data.sid !== this.sid)
|
|
10024
|
+
return;
|
|
10025
|
+
this.finishWithState(data.state);
|
|
10026
|
+
};
|
|
10027
|
+
checkLocalStorageOnce() {
|
|
10028
|
+
if (!this.sid)
|
|
10029
|
+
return;
|
|
10030
|
+
const state = localStorage.getItem(`mp:state:${this.sid}`);
|
|
10031
|
+
if (state)
|
|
10032
|
+
this.finishWithState(state);
|
|
10033
|
+
}
|
|
10034
|
+
/** Cierra el flujo de pago con el estado final y notifica al padre. */
|
|
10035
|
+
finishWithState(state) {
|
|
10036
|
+
if (this.finished)
|
|
10037
|
+
return;
|
|
10038
|
+
this.finished = true;
|
|
10039
|
+
if (this.pollTimer)
|
|
10040
|
+
clearInterval(this.pollTimer);
|
|
10041
|
+
this.pollTimer = null;
|
|
10042
|
+
localStorage.removeItem(`mp:state:${this.sid}`);
|
|
10043
|
+
localStorage.removeItem('mp:sid');
|
|
10044
|
+
localStorage.removeItem('state');
|
|
10045
|
+
try {
|
|
10046
|
+
this.ventana && !this.ventana.closed && this.ventana.close();
|
|
10047
|
+
}
|
|
10048
|
+
catch { }
|
|
10049
|
+
this.ventana = null;
|
|
10050
|
+
if (state === 'success' || state === 'pending') {
|
|
10051
|
+
this.phase = 'finalizing';
|
|
10052
|
+
this.ready.emit(true);
|
|
10053
|
+
}
|
|
10054
|
+
else if (state === 'failure' || state === 'cancel') {
|
|
10055
|
+
this.phase = 'idle';
|
|
10056
|
+
this._toastService.show(state === 'cancel' ? 'Se canceló el pago con Mercado Pago' : 'payment-error');
|
|
10057
|
+
}
|
|
10058
|
+
else {
|
|
10059
|
+
this.phase = 'idle';
|
|
10060
|
+
this._toastService.show('payment-error');
|
|
10061
|
+
}
|
|
10062
|
+
}
|
|
10063
|
+
genSid() {
|
|
10064
|
+
return `mp_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
10065
|
+
}
|
|
10066
|
+
processError = (msg) => {
|
|
10067
|
+
this._toastService.show(msg || 'payment-error');
|
|
9369
10068
|
};
|
|
10069
|
+
/** Limpia posibles residuos de estado en storages. */
|
|
9370
10070
|
clearStorageState = () => {
|
|
9371
|
-
|
|
9372
|
-
|
|
10071
|
+
if (!isPlatformBrowser(this.platformId))
|
|
10072
|
+
return;
|
|
10073
|
+
localStorage.removeItem('state');
|
|
10074
|
+
const sid = localStorage.getItem('mp:sid');
|
|
10075
|
+
if (sid)
|
|
10076
|
+
localStorage.removeItem(`mp:state:${sid}`);
|
|
10077
|
+
};
|
|
10078
|
+
/** Obtiene la preferencia e inicializa `url` (init_point). */
|
|
10079
|
+
getPreference = () => {
|
|
10080
|
+
this._paymentService.getPreference(this.allData).then((res) => {
|
|
10081
|
+
this.preference = res;
|
|
10082
|
+
this.url = this.preference?.init_point;
|
|
10083
|
+
this.renderMP(this.preference);
|
|
10084
|
+
}, () => this.setError('operation-error'));
|
|
9373
10085
|
};
|
|
9374
|
-
getPreference = () => this._paymentService.getPreference(this.allData).then(res => {
|
|
9375
|
-
this.preference = res;
|
|
9376
|
-
this.url = this.preference.init_point;
|
|
9377
|
-
this.renderMP(this.preference);
|
|
9378
|
-
}, err => this.setError('operation-error'));
|
|
9379
10086
|
setError = (message) => {
|
|
9380
10087
|
//this.error = message;
|
|
9381
10088
|
};
|
|
9382
|
-
renderMP = (
|
|
9383
|
-
this.window?.addEventListener("message", (event) => {
|
|
9384
|
-
if (event.origin !== 'https://www.mercadopago.com.ar' || !event.data.type) {
|
|
9385
|
-
return;
|
|
9386
|
-
}
|
|
9387
|
-
let dataType = event.data.type;
|
|
9388
|
-
if (dataType === 'submit') {
|
|
9389
|
-
const paymentData = event.data.value;
|
|
9390
|
-
return;
|
|
9391
|
-
}
|
|
9392
|
-
});
|
|
9393
|
-
};
|
|
10089
|
+
renderMP = (_pref) => { };
|
|
9394
10090
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MpRedirectEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9395
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: MpRedirectEcComponent, isStandalone: true, selector: "app-mp-redirect-ec", inputs: { method: "method", total_amount: "total_amount", allData: "allData" }, outputs: { ready: "ready" }, ngImport: i0, template: "<div class=\"text-center\">\r\n\t@if(url){\r\n\
|
|
10091
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: MpRedirectEcComponent, isStandalone: true, selector: "app-mp-redirect-ec", inputs: { method: "method", total_amount: "total_amount", allData: "allData" }, outputs: { ready: "ready" }, ngImport: i0, template: "<div class=\"text-center\">\r\n\t@if(url) {\r\n\r\n\t@if(isIdle) {\r\n\t<button (click)=\"iniciar()\" class=\"btn btn-outline-primary rounded-0 comprar mt-3\">Pagar</button>\r\n\t}\r\n\r\n\t@if(isPaying) {\r\n\t<div class=\"d-flex flex-column jusitfy-content-center align-items-center mt-2\">\r\n\t\t<h3>Procesando el pago por Mercado Pago</h3>\r\n\t\t<h5>Record\u00E1 tocar \u201CVolver al sitio\u201D en Mercado Pago para finalizar.</h5>\r\n\t\t<app-loading-full-ec></app-loading-full-ec>\r\n\t</div>\r\n\r\n\t<div class=\"container-fluid\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-5\">\r\n\t\t\t\t<hr>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"col-2 text-center\"><label>o</label></div>\r\n\t\t\t<div class=\"col-5\">\r\n\t\t\t\t<hr>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n\r\n\t<div class=\"d-flex flex-column justify-content-center align-items-center mt-2\">\r\n\t\t<button (click)=\"clickClose()\" class=\"btn btn-outline-secondary\">Cancelar pago</button>\r\n\t</div>\r\n\t}\r\n\r\n\t@if(isFinalizing) {\r\n\t<div class=\"d-flex flex-column jusitfy-content-center align-items-center mt-2\">\r\n\t\t<h3>Confirmando pago y redirigiendo\u2026</h3>\r\n\t\t<h5>No cierres ni recargues esta p\u00E1gina.</h5>\r\n\t\t<app-loading-full-ec></app-loading-full-ec>\r\n\t</div>\r\n\t}\r\n\r\n\t} @else {\r\n\t<div class=\"d-flex flex-column justify-content-center align-items-center mt-2\">\r\n\t\t<app-loading-full-ec></app-loading-full-ec>\r\n\t</div>\r\n\t}\r\n</div>", styles: [""], dependencies: [{ kind: "component", type: LoadingFullEcComponent, selector: "app-loading-full-ec" }] });
|
|
9396
10092
|
}
|
|
9397
10093
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MpRedirectEcComponent, decorators: [{
|
|
9398
10094
|
type: Component,
|
|
9399
|
-
args: [{ selector: 'app-mp-redirect-ec', standalone: true, imports: [LoadingFullEcComponent], template: "<div class=\"text-center\">\r\n\t@if(url){\r\n\
|
|
9400
|
-
}],
|
|
10095
|
+
args: [{ selector: 'app-mp-redirect-ec', standalone: true, imports: [LoadingFullEcComponent], template: "<div class=\"text-center\">\r\n\t@if(url) {\r\n\r\n\t@if(isIdle) {\r\n\t<button (click)=\"iniciar()\" class=\"btn btn-outline-primary rounded-0 comprar mt-3\">Pagar</button>\r\n\t}\r\n\r\n\t@if(isPaying) {\r\n\t<div class=\"d-flex flex-column jusitfy-content-center align-items-center mt-2\">\r\n\t\t<h3>Procesando el pago por Mercado Pago</h3>\r\n\t\t<h5>Record\u00E1 tocar \u201CVolver al sitio\u201D en Mercado Pago para finalizar.</h5>\r\n\t\t<app-loading-full-ec></app-loading-full-ec>\r\n\t</div>\r\n\r\n\t<div class=\"container-fluid\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-5\">\r\n\t\t\t\t<hr>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"col-2 text-center\"><label>o</label></div>\r\n\t\t\t<div class=\"col-5\">\r\n\t\t\t\t<hr>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n\r\n\t<div class=\"d-flex flex-column justify-content-center align-items-center mt-2\">\r\n\t\t<button (click)=\"clickClose()\" class=\"btn btn-outline-secondary\">Cancelar pago</button>\r\n\t</div>\r\n\t}\r\n\r\n\t@if(isFinalizing) {\r\n\t<div class=\"d-flex flex-column jusitfy-content-center align-items-center mt-2\">\r\n\t\t<h3>Confirmando pago y redirigiendo\u2026</h3>\r\n\t\t<h5>No cierres ni recargues esta p\u00E1gina.</h5>\r\n\t\t<app-loading-full-ec></app-loading-full-ec>\r\n\t</div>\r\n\t}\r\n\r\n\t} @else {\r\n\t<div class=\"d-flex flex-column justify-content-center align-items-center mt-2\">\r\n\t\t<app-loading-full-ec></app-loading-full-ec>\r\n\t</div>\r\n\t}\r\n</div>" }]
|
|
10096
|
+
}], propDecorators: { method: [{
|
|
9401
10097
|
type: Input
|
|
9402
10098
|
}], total_amount: [{
|
|
9403
10099
|
type: Input
|
|
@@ -9640,11 +10336,11 @@ class DecidirEcComponent extends ComponentHelper {
|
|
|
9640
10336
|
obj.style.width = obj.contentWindow.document.body.scrollWidth + 'px';
|
|
9641
10337
|
};
|
|
9642
10338
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DecidirEcComponent, deps: [{ token: i0.Renderer2 }, { token: ConnectionService }, { token: ToastService }, { token: CoreConstantsService }, { token: ApiConstantsService }, { token: CartService }, { token: i2.ActivatedRoute }, { token: i1$4.DomSanitizer }, { token: ParametersService }], target: i0.ɵɵFactoryTarget.Component });
|
|
9643
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: DecidirEcComponent, isStandalone: true, selector: "app-decidir-ec", inputs: { paymentServiceInst: "paymentServiceInst", method: "method", total_amount: "total_amount", allData: "allData", user_data: "user_data" }, outputs: { ready: "ready" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div class=\"text-center\">\r\n <h3>Continuar con el pago en Decidir</h3>\r\n @if (method) {\r\n <p class=\"px-5\">{{ method.description }}</p>\r\n <p class=\"px-5\">{{ method.instructions }}</p>\r\n }\r\n @if (!loading) {\r\n <button class=\"btn btn-outline-secondary comprar\" (click)=\"openModal()\">Pagar</button>\r\n } @else {\r\n <div class=\"d-flex flex-column jusitfy-content-center align-items-center mt-2\">\r\n <app-loading-full-ec></app-loading-full-ec>\r\n </div>\r\n }\r\n </div>\r\n\r\n@if (showModal) {\r\n<div class=\"modal-backdrop\" (click)=\"clickClose()\">\r\n <div class=\"modal-dialog modal-lg\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"modal-content\">\r\n\r\n <div class=\"modal-body\">\r\n <div class=\"payment-container\">\r\n \r\n <!-- Iframe del formulario de decidir -->\r\n <div class=\"iframe-container\">\r\n <iframe [src]=\"url\" frameborder=\"0\" class=\"payment-iframe\"></iframe>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n}\r\n", styles: [".modal-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#0009;display:flex;justify-content:center;align-items:center;z-index:1050
|
|
10339
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: DecidirEcComponent, isStandalone: true, selector: "app-decidir-ec", inputs: { paymentServiceInst: "paymentServiceInst", method: "method", total_amount: "total_amount", allData: "allData", user_data: "user_data" }, outputs: { ready: "ready" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div class=\"text-center\">\r\n <h3>Continuar con el pago en Decidir</h3>\r\n @if (method) {\r\n <p class=\"px-5\">{{ method.description }}</p>\r\n <p class=\"px-5\">{{ method.instructions }}</p>\r\n }\r\n @if (!loading) {\r\n <button class=\"btn btn-outline-secondary comprar\" (click)=\"openModal()\">Pagar</button>\r\n } @else {\r\n <div class=\"d-flex flex-column jusitfy-content-center align-items-center mt-2\">\r\n <app-loading-full-ec></app-loading-full-ec>\r\n </div>\r\n }\r\n </div>\r\n\r\n@if (showModal) {\r\n<div class=\"modal-backdrop\" (click)=\"clickClose()\">\r\n <div class=\"modal-dialog modal-lg\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"modal-content\">\r\n\r\n <div class=\"modal-body\">\r\n <div class=\"payment-container\">\r\n \r\n <!-- Iframe del formulario de decidir -->\r\n <div class=\"iframe-container\">\r\n <iframe [src]=\"url\" frameborder=\"0\" class=\"payment-iframe\"></iframe>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n}\r\n", styles: [".modal-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#0009;display:flex;justify-content:center;align-items:center;z-index:1050;backdrop-filter:blur(2px)}.modal-dialog{max-width:90%;max-height:90%;width:800px;background:#fff;border-radius:16px;overflow:hidden;box-shadow:0 20px 60px #0000004d;animation:modalFadeIn .3s ease-out}.modal-dialog.modal-lg{max-width:900px;width:90%}@keyframes modalFadeIn{0%{opacity:0;transform:scale(.9) translateY(-20px)}to{opacity:1;transform:scale(1) translateY(0)}}.modal-content{display:flex;flex-direction:column;height:100%;border:none;border-radius:16px;background:#fff}.modal-header{padding:1.5rem 2rem;border-bottom:1px solid #e9ecef;background:linear-gradient(135deg,#f8f9fa,#e9ecef);display:flex;justify-content:space-between;align-items:center;position:relative}.modal-header:after{content:\"\";position:absolute;bottom:0;left:0;right:0;height:1px;background:linear-gradient(90deg,transparent 0%,#dee2e6 50%,transparent 100%)}.modal-header .modal-title{margin:0;font-size:1.5rem;font-weight:700;color:#2c3e50;text-shadow:0 1px 2px rgba(0,0,0,.1)}.modal-header .btn-close{background:none;border:none;font-size:1.8rem;color:#6c757d;cursor:pointer;padding:0;width:35px;height:35px;display:flex;align-items:center;justify-content:center;border-radius:50%;transition:all .3s ease;position:relative}.modal-header .btn-close:hover{background-color:#dc3545;color:#fff;transform:rotate(90deg);box-shadow:0 4px 12px #dc35454d}.modal-header .btn-close:active{transform:rotate(90deg) scale(.95)}.modal-body{padding:0;flex:1;overflow:hidden;background:#fff}.payment-container{height:100%;display:flex;flex-direction:column;background:#fff}.cards-accepted{padding:1.5rem 2rem;text-align:center;border-bottom:1px solid #e9ecef;background:linear-gradient(135deg,#fff,#f8f9fa);position:relative}.cards-accepted:after{content:\"\";position:absolute;bottom:0;left:5%;right:5%;height:1px;background:linear-gradient(90deg,transparent 0%,#dee2e6 50%,transparent 100%)}.cards-accepted .cards-img{height:45px;max-width:100%;object-fit:contain;filter:drop-shadow(0 2px 4px rgba(0,0,0,.1));transition:transform .2s ease}.cards-accepted .cards-img:hover{transform:scale(1.05)}.iframe-container{flex:1;padding:1.5rem;background:#fff;position:relative}.iframe-container:before{content:\"\";position:absolute;top:0;left:1.5rem;right:1.5rem;height:1px;background:linear-gradient(90deg,transparent 0%,#e9ecef 50%,transparent 100%)}.payment-iframe{width:100%;height:620px;border:none;border-radius:12px;background:#fff;box-shadow:inset 0 2px 8px #0000000d}.half-width{width:49%!important}.ml-1{margin-left:1%}#card-form{height:450px}.iframeStyle{height:520px;width:100%}@media only screen and (max-width: 1024px){.modal-dialog,.modal-dialog.modal-lg{max-width:95%;width:95%}.payment-iframe{height:650px}.modal-header{padding:1rem 1.5rem}.modal-header .modal-title{font-size:1.125rem}.cards-accepted{padding:.75rem 1.5rem}}@media only screen and (max-width: 680px){.modal-dialog{max-width:98%;width:98%;margin:1rem;max-height:calc(100vh - 2rem)}.modal-dialog.modal-lg{max-width:98%;width:98%}.payment-iframe{height:550px}.modal-header{padding:1rem}.modal-header .modal-title{font-size:1rem}.modal-header .btn-close{width:28px;height:28px;font-size:1.25rem}.cards-accepted{padding:.5rem 1rem}.cards-accepted .cards-img{height:35px}.iframe-container{padding:.5rem}}@media only screen and (max-width: 480px){.modal-dialog{margin:.5rem;max-height:calc(100vh - 1rem);border-radius:8px}.modal-content{border-radius:8px}.payment-iframe{height:500px}.cards-accepted .cards-img{height:30px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: LoadingFullEcComponent, selector: "app-loading-full-ec" }] });
|
|
9644
10340
|
}
|
|
9645
10341
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DecidirEcComponent, decorators: [{
|
|
9646
10342
|
type: Component,
|
|
9647
|
-
args: [{ selector: 'app-decidir-ec', standalone: true, imports: [CommonModule, FormsModule, LoadingFullEcComponent], template: "<div class=\"text-center\">\r\n <h3>Continuar con el pago en Decidir</h3>\r\n @if (method) {\r\n <p class=\"px-5\">{{ method.description }}</p>\r\n <p class=\"px-5\">{{ method.instructions }}</p>\r\n }\r\n @if (!loading) {\r\n <button class=\"btn btn-outline-secondary comprar\" (click)=\"openModal()\">Pagar</button>\r\n } @else {\r\n <div class=\"d-flex flex-column jusitfy-content-center align-items-center mt-2\">\r\n <app-loading-full-ec></app-loading-full-ec>\r\n </div>\r\n }\r\n </div>\r\n\r\n@if (showModal) {\r\n<div class=\"modal-backdrop\" (click)=\"clickClose()\">\r\n <div class=\"modal-dialog modal-lg\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"modal-content\">\r\n\r\n <div class=\"modal-body\">\r\n <div class=\"payment-container\">\r\n \r\n <!-- Iframe del formulario de decidir -->\r\n <div class=\"iframe-container\">\r\n <iframe [src]=\"url\" frameborder=\"0\" class=\"payment-iframe\"></iframe>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n}\r\n", styles: [".modal-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#0009;display:flex;justify-content:center;align-items:center;z-index:1050
|
|
10343
|
+
args: [{ selector: 'app-decidir-ec', standalone: true, imports: [CommonModule, FormsModule, LoadingFullEcComponent], template: "<div class=\"text-center\">\r\n <h3>Continuar con el pago en Decidir</h3>\r\n @if (method) {\r\n <p class=\"px-5\">{{ method.description }}</p>\r\n <p class=\"px-5\">{{ method.instructions }}</p>\r\n }\r\n @if (!loading) {\r\n <button class=\"btn btn-outline-secondary comprar\" (click)=\"openModal()\">Pagar</button>\r\n } @else {\r\n <div class=\"d-flex flex-column jusitfy-content-center align-items-center mt-2\">\r\n <app-loading-full-ec></app-loading-full-ec>\r\n </div>\r\n }\r\n </div>\r\n\r\n@if (showModal) {\r\n<div class=\"modal-backdrop\" (click)=\"clickClose()\">\r\n <div class=\"modal-dialog modal-lg\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"modal-content\">\r\n\r\n <div class=\"modal-body\">\r\n <div class=\"payment-container\">\r\n \r\n <!-- Iframe del formulario de decidir -->\r\n <div class=\"iframe-container\">\r\n <iframe [src]=\"url\" frameborder=\"0\" class=\"payment-iframe\"></iframe>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n}\r\n", styles: [".modal-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#0009;display:flex;justify-content:center;align-items:center;z-index:1050;backdrop-filter:blur(2px)}.modal-dialog{max-width:90%;max-height:90%;width:800px;background:#fff;border-radius:16px;overflow:hidden;box-shadow:0 20px 60px #0000004d;animation:modalFadeIn .3s ease-out}.modal-dialog.modal-lg{max-width:900px;width:90%}@keyframes modalFadeIn{0%{opacity:0;transform:scale(.9) translateY(-20px)}to{opacity:1;transform:scale(1) translateY(0)}}.modal-content{display:flex;flex-direction:column;height:100%;border:none;border-radius:16px;background:#fff}.modal-header{padding:1.5rem 2rem;border-bottom:1px solid #e9ecef;background:linear-gradient(135deg,#f8f9fa,#e9ecef);display:flex;justify-content:space-between;align-items:center;position:relative}.modal-header:after{content:\"\";position:absolute;bottom:0;left:0;right:0;height:1px;background:linear-gradient(90deg,transparent 0%,#dee2e6 50%,transparent 100%)}.modal-header .modal-title{margin:0;font-size:1.5rem;font-weight:700;color:#2c3e50;text-shadow:0 1px 2px rgba(0,0,0,.1)}.modal-header .btn-close{background:none;border:none;font-size:1.8rem;color:#6c757d;cursor:pointer;padding:0;width:35px;height:35px;display:flex;align-items:center;justify-content:center;border-radius:50%;transition:all .3s ease;position:relative}.modal-header .btn-close:hover{background-color:#dc3545;color:#fff;transform:rotate(90deg);box-shadow:0 4px 12px #dc35454d}.modal-header .btn-close:active{transform:rotate(90deg) scale(.95)}.modal-body{padding:0;flex:1;overflow:hidden;background:#fff}.payment-container{height:100%;display:flex;flex-direction:column;background:#fff}.cards-accepted{padding:1.5rem 2rem;text-align:center;border-bottom:1px solid #e9ecef;background:linear-gradient(135deg,#fff,#f8f9fa);position:relative}.cards-accepted:after{content:\"\";position:absolute;bottom:0;left:5%;right:5%;height:1px;background:linear-gradient(90deg,transparent 0%,#dee2e6 50%,transparent 100%)}.cards-accepted .cards-img{height:45px;max-width:100%;object-fit:contain;filter:drop-shadow(0 2px 4px rgba(0,0,0,.1));transition:transform .2s ease}.cards-accepted .cards-img:hover{transform:scale(1.05)}.iframe-container{flex:1;padding:1.5rem;background:#fff;position:relative}.iframe-container:before{content:\"\";position:absolute;top:0;left:1.5rem;right:1.5rem;height:1px;background:linear-gradient(90deg,transparent 0%,#e9ecef 50%,transparent 100%)}.payment-iframe{width:100%;height:620px;border:none;border-radius:12px;background:#fff;box-shadow:inset 0 2px 8px #0000000d}.half-width{width:49%!important}.ml-1{margin-left:1%}#card-form{height:450px}.iframeStyle{height:520px;width:100%}@media only screen and (max-width: 1024px){.modal-dialog,.modal-dialog.modal-lg{max-width:95%;width:95%}.payment-iframe{height:650px}.modal-header{padding:1rem 1.5rem}.modal-header .modal-title{font-size:1.125rem}.cards-accepted{padding:.75rem 1.5rem}}@media only screen and (max-width: 680px){.modal-dialog{max-width:98%;width:98%;margin:1rem;max-height:calc(100vh - 2rem)}.modal-dialog.modal-lg{max-width:98%;width:98%}.payment-iframe{height:550px}.modal-header{padding:1rem}.modal-header .modal-title{font-size:1rem}.modal-header .btn-close{width:28px;height:28px;font-size:1.25rem}.cards-accepted{padding:.5rem 1rem}.cards-accepted .cards-img{height:35px}.iframe-container{padding:.5rem}}@media only screen and (max-width: 480px){.modal-dialog{margin:.5rem;max-height:calc(100vh - 1rem);border-radius:8px}.modal-content{border-radius:8px}.payment-iframe{height:500px}.cards-accepted .cards-img{height:30px}}\n"] }]
|
|
9648
10344
|
}], ctorParameters: () => [{ type: i0.Renderer2 }, { type: ConnectionService }, { type: ToastService }, { type: CoreConstantsService }, { type: ApiConstantsService }, { type: CartService }, { type: i2.ActivatedRoute }, { type: i1$4.DomSanitizer }, { type: ParametersService }], propDecorators: { paymentServiceInst: [{
|
|
9649
10345
|
type: Input
|
|
9650
10346
|
}], method: [{
|
|
@@ -11515,5 +12211,5 @@ const directives = [
|
|
|
11515
12211
|
* Generated bundle index. Do not edit.
|
|
11516
12212
|
*/
|
|
11517
12213
|
|
|
11518
|
-
export { AccountEcComponent, AddressingService, AnalyticsService, AuthEcComponent, AuthService, AuthStorageService, BlockBannerBoxEcComponent, BlockBannerFullEcComponent, BlockFormContactEcComponent, BlockHtmlEcComponent, BlockNewsletterEcComponent, BlockProductsEcComponent, BlocksEcComponent, BlocksRepositoryService, BlocksService, BreadcrumbEcComponent, CartEcComponent, CartItemEcComponent, CartService, ChannelService, CheckoutEcComponent, CheckoutService, CollectionEcComponent, ConfirmAccountEcComponent, ContactEcComponent, CoreConstantsService, CouponEcComponent, CurrencyService, DopplerService, ENVIRONMENT_TOKEN, EcCurrencySymbolPipe, EcSafeHtmlPipe, FacebookPixelService, FaqsEcComponent, FiltersEcComponent, FiltersService, FiltersSortEcComponent, FooterEcComponent, ForgotPasswordEcComponent, FormService, GTMService, GoogleAnalyticsService, HeaderEcComponent, HomeEcComponent, LoadingFullEcComponent, LoadingInlineEcComponent, LoadingSectionEcComponent, LocalStorageService, LoginFormEcComponent, MagnizoomEcComponent, MetricoolPixelService, NgxLocalStorageService, OptionsService, OrderEcComponent, OrderUtilityService, OrdersListEcComponent, OrdersService, PaginationService, ParametersService, ParamsContext, PasswordResetEcComponent, PaymentService, PriceEcComponent, PriceRangeFilterComponent, ProductDetailEcComponent, ProductDetailService, ProductEcComponent, ProductOffDirective, ProductStockDirective, ProductsService, ReCaptchaEcComponent, ReCaptchaService, RegisterFormEcComponent, RegisterWholesalerFormEcComponent, RelatedProductsEcComponent, ReviewsEcComponent, ReviewsFormEcComponent, SectionContainerEcComponent, ShareEcComponent, ShipmentService, SidebarEcComponent, StoresEcComponent, SuccessEcComponent, TestService, ToastService, VariantsEcComponent, authGuard, authInterceptor, directives, provideEnvironment };
|
|
12214
|
+
export { AccountEcComponent, AddressingService, AnalyticsService, AuthEcComponent, AuthService, AuthStorageService, BlockBannerBoxEcComponent, BlockBannerFullEcComponent, BlockFormContactEcComponent, BlockHtmlEcComponent, BlockNewsletterEcComponent, BlockProductsEcComponent, BlocksEcComponent, BlocksRepositoryService, BlocksService, BreadcrumbEcComponent, CartEcComponent, CartItemEcComponent, CartService, ChannelService, CheckoutEcComponent, CheckoutService, CollectionEcComponent, ConfirmAccountEcComponent, ContactEcComponent, CoreConstantsService, CouponEcComponent, CurrencyService, DopplerService, ENVIRONMENT_TOKEN, EcCurrencySymbolPipe, EcSafeHtmlPipe, FacebookPixelService, FaqsEcComponent, FiltersEcComponent, FiltersService, FiltersSortEcComponent, FooterEcComponent, ForgotPasswordEcComponent, FormService, GTMService, GoogleAnalyticsService, HeaderEcComponent, HomeEcComponent, LoadingFullEcComponent, LoadingInlineEcComponent, LoadingSectionEcComponent, LocalStorageService, LoginFormEcComponent, MagnizoomEcComponent, MetricoolPixelService, NgxLocalStorageService, OptionsService, OrderEcComponent, OrderUtilityService, OrdersListEcComponent, OrdersService, PaginationService, ParametersService, ParamsContext, PasswordResetEcComponent, PaymentService, PriceEcComponent, PriceRangeFilterComponent, ProductDetailEcComponent, ProductDetailService, ProductEcComponent, ProductOffDirective, ProductStockDirective, ProductsService, ReCaptchaEcComponent, ReCaptchaService, RedsysCatchEcComponent, RegisterFormEcComponent, RegisterWholesalerFormEcComponent, RelatedProductsEcComponent, ReviewsEcComponent, ReviewsFormEcComponent, SectionContainerEcComponent, ShareEcComponent, ShipmentService, SidebarEcComponent, StoresEcComponent, SuccessEcComponent, TestService, ToastService, VariantsEcComponent, authGuard, authInterceptor, directives, provideEnvironment };
|
|
11519
12215
|
//# sourceMappingURL=ng-easycommerce-v18.mjs.map
|