ng-easycommerce-v18 0.3.14-beta.4 → 0.3.14-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +20 -0
  2. package/esm2022/lib/constants/core.constants.service.mjs +2 -2
  3. package/esm2022/lib/ec-components/abstractions-components/menu-ec.component.mjs +17 -1
  4. package/esm2022/lib/ec-components/auth-ec/login-form-ec/login-form-ec.component.mjs +5 -1
  5. package/esm2022/lib/ec-components/auth-ec/register-form-ec/register-form-ec.component.mjs +5 -1
  6. package/esm2022/lib/ec-components/cart-ec/cart-item-ec/cart-item-ec.component.mjs +6 -2
  7. package/esm2022/lib/ec-components/checkout-ec/payment-ec/payment-methods/mp-redirect-ec/mp-redirect-ec.component.mjs +141 -75
  8. package/esm2022/lib/ec-components/filters-ec/filters-ec.component.mjs +30 -5
  9. package/esm2022/lib/ec-components/header-ec/header-ec.component.mjs +23 -3
  10. package/esm2022/lib/ec-components/product-detail-ec/product-detail-ec.component.mjs +11 -10
  11. package/esm2022/lib/ec-components/product-ec/product-ec.component.mjs +95 -5
  12. package/esm2022/lib/ec-components/stores-ec/stores-ec.component.mjs +21 -6
  13. package/esm2022/lib/ec-components/widgets-ec/decidir-ec/decidir-ec.component.mjs +3 -1
  14. package/esm2022/lib/ec-components/widgets-ec/index.mjs +2 -1
  15. package/esm2022/lib/ec-components/widgets-ec/redsys-catch-ec/redsys-catch-ec.component.mjs +193 -0
  16. package/esm2022/lib/ec-services/analytics/google-analytics.service.mjs +4 -2
  17. package/esm2022/lib/ec-services/analytics/gtm.service.mjs +6 -3
  18. package/esm2022/lib/ec-services/analytics/metricool-pixel.service.mjs +4 -2
  19. package/esm2022/lib/interfaces/filter.mjs +1 -1
  20. package/esm2022/lib/interfaces/options.mjs +1 -1
  21. package/fesm2022/ng-easycommerce-v18.mjs +559 -124
  22. package/fesm2022/ng-easycommerce-v18.mjs.map +1 -1
  23. package/lib/ec-components/abstractions-components/menu-ec.component.d.ts +12 -0
  24. package/lib/ec-components/auth-ec/login-form-ec/login-form-ec.component.d.ts +2 -0
  25. package/lib/ec-components/auth-ec/register-form-ec/register-form-ec.component.d.ts +2 -0
  26. package/lib/ec-components/cart-ec/cart-item-ec/cart-item-ec.component.d.ts +5 -0
  27. package/lib/ec-components/checkout-ec/payment-ec/payment-methods/mp-redirect-ec/mp-redirect-ec.component.d.ts +38 -16
  28. package/lib/ec-components/filters-ec/filters-ec.component.d.ts +12 -4
  29. package/lib/ec-components/header-ec/header-ec.component.d.ts +5 -1
  30. package/lib/ec-components/product-ec/product-ec.component.d.ts +10 -1
  31. package/lib/ec-components/stores-ec/stores-ec.component.d.ts +2 -1
  32. package/lib/ec-components/widgets-ec/index.d.ts +1 -0
  33. package/lib/ec-components/widgets-ec/redsys-catch-ec/redsys-catch-ec.component.d.ts +47 -0
  34. package/lib/ec-services/analytics/google-analytics.service.d.ts +1 -1
  35. package/lib/ec-services/analytics/gtm.service.d.ts +1 -1
  36. package/lib/interfaces/filter.d.ts +1 -0
  37. package/lib/interfaces/options.d.ts +2 -0
  38. package/package.json +1 -1
@@ -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, FormsModule } from '@angular/forms';
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';
@@ -295,7 +295,7 @@ class CoreConstantsService {
295
295
  }
296
296
  }
297
297
  // Para SSR, intentar construir desde el document si está disponible
298
- if (this.document?.location) {
298
+ if (isPlatformBrowser(this.platformId) && this.document?.location) {
299
299
  return `${this.document.location.protocol}//${this.document.location.host}`;
300
300
  }
301
301
  // Intentar obtener desde environment
@@ -1253,7 +1253,9 @@ class GoogleAnalyticsService {
1253
1253
  * @param gtm_id id provisto por Google Tag Manager.
1254
1254
  */
1255
1255
  initialize(gtm_id) {
1256
- if (!document.getElementById('google_tag_manager')) {
1256
+ if (!isPlatformBrowser(this.platformId))
1257
+ return;
1258
+ if (!this.document?.getElementById('google_tag_manager')) {
1257
1259
  console.log('hay elemento');
1258
1260
  const declaration = this.renderer.createElement('script');
1259
1261
  declaration.async = true;
@@ -1568,9 +1570,12 @@ class GTMService {
1568
1570
  if (this.isLoaded) {
1569
1571
  return resolve(this.isLoaded);
1570
1572
  }
1573
+ if (!isPlatformBrowser(this.platformId) || !this.document) {
1574
+ return reject(false);
1575
+ }
1571
1576
  //const doc = this.browserGlobals.documentRef();
1572
1577
  this.pushOnDataLayer({ 'gtm.start': new Date().getTime(), event: 'gtm.js' });
1573
- const gtmScript = this.document?.createElement('script'); //doc.createElement('script');
1578
+ const gtmScript = this.document.createElement('script'); //doc.createElement('script');
1574
1579
  if (gtmScript) {
1575
1580
  gtmScript.id = 'GTMscript';
1576
1581
  gtmScript.async = true;
@@ -1581,7 +1586,7 @@ class GTMService {
1581
1586
  gtmScript.addEventListener('error', () => {
1582
1587
  return reject(false);
1583
1588
  });
1584
- this.document?.head.insertBefore(gtmScript, this.document.head.firstChild);
1589
+ this.document.head.insertBefore(gtmScript, this.document.head.firstChild);
1585
1590
  }
1586
1591
  });
1587
1592
  }
@@ -1982,6 +1987,8 @@ class MetricoolPixelService {
1982
1987
  * @param pixel_hash hash provisto por Metricool Pixel.
1983
1988
  */
1984
1989
  initialize = (pixel_hash) => {
1990
+ if (!isPlatformBrowser(this.platformId) || !this.document)
1991
+ return;
1985
1992
  let new_analityc_script = this.renderer.createElement('script');
1986
1993
  new_analityc_script.type = 'text/javascript';
1987
1994
  new_analityc_script.text = `
@@ -1995,7 +2002,7 @@ class MetricoolPixelService {
1995
2002
  beTracker.t({ hash: "${pixel_hash}" })
1996
2003
  });
1997
2004
  `;
1998
- this.renderer.appendChild(this.document?.body, new_analityc_script);
2005
+ this.renderer.appendChild(this.document.body, new_analityc_script);
1999
2006
  };
2000
2007
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MetricoolPixelService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2001
2008
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MetricoolPixelService, providedIn: 'root' });
@@ -6057,6 +6064,22 @@ class MenuEcComponent {
6057
6064
  hasVisibleProperty(category) {
6058
6065
  return category.isVisible === true;
6059
6066
  }
6067
+ filterVisibleTree(list) {
6068
+ return (list ?? [])
6069
+ .filter((n) => n?.isVisible === true)
6070
+ .map(n => ({ ...n, children: this.filterVisibleTree(n.children) }));
6071
+ }
6072
+ // Exponé streams ya filtrados
6073
+ categoriesVisible$ = this.categories$.pipe(map((list) => this.filterVisibleTree(list)));
6074
+ sectionsVisible$ = this.sections$.pipe(map((list) => this.filterVisibleTree(list)));
6075
+ attributesVisible$ = this.attributes$.pipe(map((list) => this.filterVisibleTree(list)));
6076
+ // Helpers de conveniencia opcionales
6077
+ getVisibleChildren(node) {
6078
+ return this.filterVisibleTree(node?.children);
6079
+ }
6080
+ hasVisibleChildren(node) {
6081
+ return this.getVisibleChildren(node).length > 0;
6082
+ }
6060
6083
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MenuEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6061
6084
  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 });
6062
6085
  }
@@ -6203,6 +6226,11 @@ class HeaderEcComponent extends MenuEcComponent {
6203
6226
  hidePrices = false;
6204
6227
  __authService = inject(AuthService);
6205
6228
  _channelService = inject(ChannelService);
6229
+ changeDetector = inject(ChangeDetectorRef);
6230
+ appRouter = inject(Router);
6231
+ platformId = inject(PLATFORM_ID);
6232
+ // Observable del estado de autenticación
6233
+ logged$;
6206
6234
  isAuthenticated$ = this.__authService.isAuthenticated();
6207
6235
  constructor() {
6208
6236
  super();
@@ -6216,11 +6244,26 @@ class HeaderEcComponent extends MenuEcComponent {
6216
6244
  coreConstantsService = inject(CoreConstantsService);
6217
6245
  router = inject(Router);
6218
6246
  cdr = inject(ChangeDetectorRef); // Inyectamos ChangeDetectorRef para forzar la actualización
6219
- platformId = inject(PLATFORM_ID);
6220
6247
  ngOnInit() {
6221
6248
  this.channel = this.coreConstantsService.getChannel();
6222
6249
  this.onWindowScroll();
6223
6250
  this.detectRouteChange(); // Llamamos a la función que detecta el cambio de ruta
6251
+ // Usar el Observable del AuthService
6252
+ this.logged$ = this.__authService.loggedIn$;
6253
+ // Suscribirse al Observable y forzar detección de cambios cuando sea necesario
6254
+ this.logged$.subscribe(isLoggedIn => {
6255
+ this.changeDetector.detectChanges();
6256
+ });
6257
+ if (isPlatformBrowser(this.platformId)) {
6258
+ this.appRouter.events.subscribe(evt => {
6259
+ if (evt instanceof NavigationEnd) {
6260
+ // Forzar detección de cambios después de navegación
6261
+ setTimeout(() => {
6262
+ this.changeDetector.detectChanges();
6263
+ }, 100);
6264
+ }
6265
+ });
6266
+ }
6224
6267
  }
6225
6268
  ngAfterViewInit() {
6226
6269
  this.setupMobileMenu(); // Inicializamos el menú móvil
@@ -6934,6 +6977,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
6934
6977
  class ProductEcComponent {
6935
6978
  injector = inject(Injector);
6936
6979
  routerService = inject(Router);
6980
+ _cartService = inject(CartService);
6981
+ _toastService = inject(ToastService);
6982
+ isAddingToCart = signal(false);
6983
+ quantity = signal(1);
6937
6984
  /**
6938
6985
  * Navega al detalle del producto y sube al inicio de la página
6939
6986
  * @param productId ID del producto
@@ -7006,12 +7053,97 @@ class ProductEcComponent {
7006
7053
  const discount = ((originalPrice - salePrice) / originalPrice) * 100;
7007
7054
  return Math.round(discount);
7008
7055
  }
7056
+ plus(stock, multipleQuantity) {
7057
+ console.log('Aumentando cantidad');
7058
+ const current = Number(this.quantity()); // <-- fuerza a número
7059
+ if (multipleQuantity && multipleQuantity > 0) {
7060
+ stock
7061
+ ? (current < stock
7062
+ ? this.quantity.set(current + multipleQuantity)
7063
+ : this._toastService.show('out-of-stock-actually'))
7064
+ : this.quantity.set(current + multipleQuantity);
7065
+ }
7066
+ else {
7067
+ stock
7068
+ ? (current < stock
7069
+ ? this.quantity.set(current + 1)
7070
+ : this._toastService.show('out-of-stock-actually'))
7071
+ : this.quantity.set(current + 1);
7072
+ }
7073
+ }
7074
+ less(multipleQuantity) {
7075
+ console.log('Disminuyendo cantidad');
7076
+ const current = Number(this.quantity()); // <-- fuerza a número
7077
+ if (multipleQuantity && multipleQuantity > 0) {
7078
+ current > multipleQuantity
7079
+ ? this.quantity.set(current - multipleQuantity)
7080
+ : null;
7081
+ }
7082
+ else {
7083
+ current > 1 ? this.quantity.set(current - 1) : null;
7084
+ }
7085
+ }
7086
+ addToCart() {
7087
+ console.log('Añadiendo al carrito');
7088
+ if (this.isAddingToCart() || this.quantity() <= 0)
7089
+ return;
7090
+ // Verificar que tenemos el producto y sus variantes
7091
+ if (!this.product || !this.product.variants || this.product.variants.length === 0) {
7092
+ this._toastService.show('cant-buy');
7093
+ return;
7094
+ }
7095
+ // Verificar stock
7096
+ const firstVariant = this.product.variants[0];
7097
+ if (!firstVariant.stock || firstVariant.stock <= 0) {
7098
+ this._toastService.show('out-of-stock');
7099
+ return;
7100
+ }
7101
+ // Verificar que no se supere el stock disponible
7102
+ if (this.quantity() > firstVariant.stock) {
7103
+ this._toastService.show('out-of-stock-actually');
7104
+ return;
7105
+ }
7106
+ this.isAddingToCart.set(true);
7107
+ try {
7108
+ // Agregar al carrito usando CartService directamente
7109
+ this._cartService.addToCart(this.product, this.quantity(), firstVariant.code);
7110
+ console.log('Producto agregado al carrito exitosamente');
7111
+ // Resetear cantidad a 1 después de agregar al carrito
7112
+ this.quantity.set(1);
7113
+ }
7114
+ catch (error) {
7115
+ console.error('Error al agregar al carrito:', error);
7116
+ this._toastService.show('cant-buy');
7117
+ }
7118
+ setTimeout(() => {
7119
+ this.isAddingToCart.set(false);
7120
+ }, 2000);
7121
+ }
7122
+ checkStock(stock) {
7123
+ if (this.quantity() >= stock)
7124
+ this.quantity.set(stock);
7125
+ }
7126
+ onQuantityChange(event) {
7127
+ const target = event.target;
7128
+ const value = +target.value;
7129
+ // Validar que el valor sea mayor a 0
7130
+ if (value > 0) {
7131
+ this.quantity.set(value);
7132
+ // Validar contra el stock disponible
7133
+ const maxStock = this.product?.variants?.[0]?.stock || this.product?.stock || 0;
7134
+ this.checkStock(maxStock);
7135
+ }
7136
+ else {
7137
+ // Si el valor es 0 o negativo, resetear a 1
7138
+ this.quantity.set(1);
7139
+ }
7140
+ }
7009
7141
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProductEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7010
- 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" }] });
7142
+ 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 }] });
7011
7143
  }
7012
7144
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProductEcComponent, decorators: [{
7013
7145
  type: Component,
7014
- 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>" }]
7146
+ 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>" }]
7015
7147
  }], ctorParameters: () => [], propDecorators: { product: [{
7016
7148
  type: Input,
7017
7149
  args: [{
@@ -7589,6 +7721,212 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
7589
7721
  args: ['mainCanvas', { static: true }]
7590
7722
  }] } });
7591
7723
 
7724
+ class ComponentHelper {
7725
+ constructor() {
7726
+ this.ecOnConstruct();
7727
+ }
7728
+ ecOnInit = (params = {}) => {
7729
+ };
7730
+ ecOnConstruct = (params = {}) => {
7731
+ };
7732
+ hasParams = (params, searched) => {
7733
+ if (!params || !searched)
7734
+ return false;
7735
+ const q = searched.trim().toLowerCase();
7736
+ return params.some(p => {
7737
+ const code = p?.['code']?.toString().toLowerCase() ?? '';
7738
+ // Primero chequeo exacto, y si no, parcial
7739
+ return code === q || code.includes(q);
7740
+ });
7741
+ };
7742
+ navigateOnRouter(router, url) {
7743
+ router.navigateByUrl(`/${url}`);
7744
+ }
7745
+ }
7746
+
7747
+ /**
7748
+ * Catch genérico para redirecciones de pagos.
7749
+ * - Normaliza el estado recibido por params/query.
7750
+ * - Informa el resultado al opener (postMessage), BroadcastChannel y localStorage.
7751
+ * - Intenta cerrarse; si el cierre falla, redirige según el estado.
7752
+ */
7753
+ class RedsysCatchEcComponent extends ComponentHelper {
7754
+ activedRoute;
7755
+ router;
7756
+ checkoutService;
7757
+ renderer;
7758
+ elementRef;
7759
+ document;
7760
+ platformId;
7761
+ message = '';
7762
+ subscription = null;
7763
+ sid = '';
7764
+ bc;
7765
+ constructor(activedRoute, router, checkoutService, renderer, elementRef, document, platformId) {
7766
+ super();
7767
+ this.activedRoute = activedRoute;
7768
+ this.router = router;
7769
+ this.checkoutService = checkoutService;
7770
+ this.renderer = renderer;
7771
+ this.elementRef = elementRef;
7772
+ this.document = document;
7773
+ this.platformId = platformId;
7774
+ this.hideHeaderFooter();
7775
+ this.ecOnConstruct();
7776
+ }
7777
+ ngOnInit() {
7778
+ if (isPlatformBrowser(this.platformId) && 'BroadcastChannel' in window) {
7779
+ this.bc = new BroadcastChannel('mp_payment');
7780
+ }
7781
+ this.subscription = combineLatest([this.activedRoute.params, this.activedRoute.queryParams])
7782
+ .subscribe(([routeParams, q]) => {
7783
+ let stateStr = routeParams['state'];
7784
+ if (stateStr === 'statuspayment')
7785
+ stateStr = q['status'];
7786
+ const statusParam = (stateStr || q['status'] || q['state'] || '').toString();
7787
+ const state = this.normalizeState(statusParam);
7788
+ this.sid = (q['sid'] || (isPlatformBrowser(this.platformId) ? localStorage.getItem('mp:sid') : '') || '').toString();
7789
+ this.storeTotalAmount(q);
7790
+ this.setStateInLocal('Su pago fue procesado con éxito.', state);
7791
+ this.signalState(state);
7792
+ this.tryCloseSelf(() => {
7793
+ const target = (state === 'success' || state === 'pending')
7794
+ ? ['/checkout/order_success']
7795
+ : ['/checkout'];
7796
+ setTimeout(() => this.router.navigate(target), 4500);
7797
+ });
7798
+ });
7799
+ this.ecOnInit();
7800
+ }
7801
+ ngOnDestroy() {
7802
+ this.subscription?.unsubscribe();
7803
+ this.bc?.close();
7804
+ this.showHeaderFooter();
7805
+ }
7806
+ /** Guarda total_amount si viene desde el PSP. */
7807
+ storeTotalAmount(queryParams) {
7808
+ const totalAmount = queryParams['total_amount'];
7809
+ if (totalAmount && isPlatformBrowser(this.platformId)) {
7810
+ localStorage.setItem('total_amount', totalAmount);
7811
+ }
7812
+ }
7813
+ /** Setea mensaje y estado en storages. */
7814
+ setStateInLocal = (mensaje, state) => {
7815
+ this.message = mensaje;
7816
+ if (!isPlatformBrowser(this.platformId))
7817
+ return;
7818
+ try {
7819
+ localStorage.setItem('state', state);
7820
+ }
7821
+ catch { }
7822
+ try {
7823
+ sessionStorage.setItem('modalnews', 'false');
7824
+ }
7825
+ catch { }
7826
+ };
7827
+ /** Normaliza estados heterogéneos de distintos gateways. */
7828
+ normalizeState(raw) {
7829
+ const v = (raw || '').toLowerCase();
7830
+ if (v === '200' || v === 'ok' || v === 'success')
7831
+ return 'success';
7832
+ if (v === 'pending')
7833
+ return 'pending';
7834
+ if (v === 'cancel')
7835
+ return 'cancel';
7836
+ return 'failure'; // failure, 0, error, rejected, chargeback, desconocidos
7837
+ }
7838
+ /**
7839
+ * Informa el resultado: postMessage al opener, BroadcastChannel y localStorage
7840
+ * (este último permite polling en la pestaña madre).
7841
+ */
7842
+ signalState(state) {
7843
+ if (!isPlatformBrowser(this.platformId))
7844
+ return;
7845
+ const sid = this.sid || localStorage.getItem('mp:sid') || '';
7846
+ const payload = { type: 'mp:state', sid, state };
7847
+ try {
7848
+ window.opener && window.opener.postMessage(payload, '*');
7849
+ }
7850
+ catch { }
7851
+ try {
7852
+ this.bc?.postMessage(payload);
7853
+ }
7854
+ catch { }
7855
+ try {
7856
+ localStorage.setItem(`mp:state:${sid}`, state);
7857
+ }
7858
+ catch { }
7859
+ try {
7860
+ localStorage.setItem('state', state);
7861
+ }
7862
+ catch { }
7863
+ }
7864
+ /** Intenta cerrar la pestaña actual; si falla, ejecuta el callback de fallback. */
7865
+ tryCloseSelf(onFail) {
7866
+ if (!isPlatformBrowser(this.platformId))
7867
+ return onFail();
7868
+ let attempted = false;
7869
+ try {
7870
+ window.close();
7871
+ attempted = true;
7872
+ }
7873
+ catch { }
7874
+ if (!attempted)
7875
+ onFail();
7876
+ }
7877
+ /** Oculta header/footer para esta pantalla mínima. */
7878
+ hideHeaderFooter() {
7879
+ if (!isPlatformBrowser(this.platformId) || !this.document)
7880
+ return;
7881
+ const header = this.document.querySelector('header');
7882
+ const footer = this.document.querySelector('footer');
7883
+ if (header)
7884
+ this.renderer.setStyle(header, 'display', 'none');
7885
+ if (footer)
7886
+ this.renderer.setStyle(footer, 'display', 'none');
7887
+ }
7888
+ /** Restaura header/footer al salir. */
7889
+ showHeaderFooter() {
7890
+ if (!isPlatformBrowser(this.platformId) || !this.document)
7891
+ return;
7892
+ const header = this.document.querySelector('header');
7893
+ const footer = this.document.querySelector('footer');
7894
+ if (header)
7895
+ this.renderer.removeStyle(header, 'display');
7896
+ if (footer)
7897
+ this.renderer.removeStyle(footer, 'display');
7898
+ }
7899
+ setStateInSession(mensaje, state) {
7900
+ this.message = mensaje;
7901
+ if (!isPlatformBrowser(this.platformId))
7902
+ return;
7903
+ try {
7904
+ sessionStorage.setItem('state', state);
7905
+ }
7906
+ catch { }
7907
+ try {
7908
+ localStorage.setItem('state', state);
7909
+ }
7910
+ catch { }
7911
+ try {
7912
+ sessionStorage.setItem('modalnews', 'false');
7913
+ }
7914
+ catch { }
7915
+ }
7916
+ 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 });
7917
+ 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" }] });
7918
+ }
7919
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RedsysCatchEcComponent, decorators: [{
7920
+ type: Component,
7921
+ 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"] }]
7922
+ }], ctorParameters: () => [{ type: i2.ActivatedRoute }, { type: i2.Router }, { type: CheckoutService }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: Document, decorators: [{
7923
+ type: Inject,
7924
+ args: [DOCUMENT]
7925
+ }] }, { type: undefined, decorators: [{
7926
+ type: Inject,
7927
+ args: [PLATFORM_ID]
7928
+ }] }] });
7929
+
7592
7930
  // export * from './rating-ec/rating-ec.component';
7593
7931
 
7594
7932
  class BlockFormContactEcComponent extends BlockEcComponent {
@@ -7864,6 +8202,7 @@ class LoginFormEcComponent {
7864
8202
  _formBuilder = inject(FormBuilder);
7865
8203
  _toastService = inject(ToastService);
7866
8204
  _router = inject(Router);
8205
+ showPassword = false;
7867
8206
  /**
7868
8207
  * Parametro para indicar si tras loguear
7869
8208
  * debe redireccionar o no.
@@ -7952,6 +8291,9 @@ class LoginFormEcComponent {
7952
8291
  ? resolverFunction()
7953
8292
  : this._router.navigateByUrl(this.redirectTo);
7954
8293
  }
8294
+ togglePassword() {
8295
+ this.showPassword = !this.showPassword;
8296
+ }
7955
8297
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LoginFormEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7956
8298
  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"] }] });
7957
8299
  }
@@ -8051,6 +8393,7 @@ class RegisterFormEcComponent {
8051
8393
  _analyticsService = inject(AnalyticsService);
8052
8394
  _formBuilder = inject(FormBuilder);
8053
8395
  channelConfigService = inject(ChannelService);
8396
+ showPassword = false;
8054
8397
  /**
8055
8398
  * Indica si debe redireccionar o se queda en la misma pantalla
8056
8399
  */
@@ -8166,6 +8509,9 @@ class RegisterFormEcComponent {
8166
8509
  this.register_loading = false;
8167
8510
  }
8168
8511
  }
8512
+ togglePassword() {
8513
+ this.showPassword = !this.showPassword;
8514
+ }
8169
8515
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RegisterFormEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8170
8516
  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" }] });
8171
8517
  }
@@ -8320,29 +8666,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
8320
8666
  type: Output
8321
8667
  }] } });
8322
8668
 
8323
- class ComponentHelper {
8324
- constructor() {
8325
- this.ecOnConstruct();
8326
- }
8327
- ecOnInit = (params = {}) => {
8328
- };
8329
- ecOnConstruct = (params = {}) => {
8330
- };
8331
- hasParams = (params, searched) => {
8332
- if (!params || !searched)
8333
- return false;
8334
- const q = searched.trim().toLowerCase();
8335
- return params.some(p => {
8336
- const code = p?.['code']?.toString().toLowerCase() ?? '';
8337
- // Primero chequeo exacto, y si no, parcial
8338
- return code === q || code.includes(q);
8339
- });
8340
- };
8341
- navigateOnRouter(router, url) {
8342
- router.navigateByUrl(`/${url}`);
8343
- }
8344
- }
8345
-
8346
8669
  class PasswordResetEcComponent extends ComponentHelper {
8347
8670
  authService;
8348
8671
  toastr;
@@ -8484,6 +8807,8 @@ class FiltersEcComponent {
8484
8807
  console.error('Filter or selected element is undefined:', { filter, selected });
8485
8808
  return;
8486
8809
  }
8810
+ if (selected.isVisible !== true)
8811
+ return;
8487
8812
  if (typeof filter.setSelected !== 'function') {
8488
8813
  console.error('filter.setSelected is not a function. Filter might not be an instance of the expected class:', filter);
8489
8814
  return;
@@ -8553,13 +8878,36 @@ class FiltersEcComponent {
8553
8878
  }) ?? false;
8554
8879
  }
8555
8880
  /**
8556
- * Verifica si una categoría tiene la propiedad isVisible y está marcada como visible
8557
- * @param category - La categoría a verificar
8558
- * @returns true si la categoría es visible, false en caso contrario
8559
- */
8881
+ * Verifica si una categoría tiene la propiedad isVisible y está marcada como visible
8882
+ * @param category - La categoría a verificar
8883
+ * @returns true si la categoría es visible, false en caso contrario
8884
+ */
8560
8885
  hasVisibleProperty(category) {
8561
8886
  return category.isVisible === true;
8562
8887
  }
8888
+ /** Lista visible (filtra recursivo por isVisible) */
8889
+ getVisibleData(filter) {
8890
+ if (!filter)
8891
+ return [];
8892
+ return this.filterVisibleTree(filter.data);
8893
+ }
8894
+ /** Children visibles de un nodo */
8895
+ getVisibleChildren(node) {
8896
+ return this.filterVisibleTree(node?.children ?? []);
8897
+ }
8898
+ /** Tiene hijos visibles? */
8899
+ hasVisibleChildren(node) {
8900
+ return this.getVisibleChildren(node).length > 0;
8901
+ }
8902
+ /** Utilidad recursiva */
8903
+ filterVisibleTree(list = []) {
8904
+ return (list ?? [])
8905
+ .filter(n => n.isVisible === true)
8906
+ .map(n => ({
8907
+ ...n,
8908
+ children: this.filterVisibleTree(n.children ?? [])
8909
+ }));
8910
+ }
8563
8911
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FiltersEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8564
8912
  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: [""] });
8565
8913
  }
@@ -8711,9 +9059,8 @@ class ProductDetailEcComponent {
8711
9059
  this._meta.updateTag({ property: 'og:type', content: 'product' });
8712
9060
  }
8713
9061
  decodeHtml(html) {
8714
- const txt = document.createElement('textarea');
8715
- txt.innerHTML = html;
8716
- return txt.value;
9062
+ // Usar he.decode en lugar de document para compatibilidad SSR
9063
+ return he.decode(html);
8717
9064
  }
8718
9065
  sanitizedHtml(html) {
8719
9066
  const decodedHtml = this.decodeHtml(html);
@@ -8762,12 +9109,14 @@ class ProductDetailEcComponent {
8762
9109
  }
8763
9110
  goToSection(section) {
8764
9111
  this.showFormContact = true;
8765
- setTimeout(() => {
8766
- const element = document.getElementById(section);
8767
- if (element) {
8768
- element.scrollIntoView({ behavior: 'smooth' });
8769
- }
8770
- }, 500);
9112
+ if (typeof document !== 'undefined') {
9113
+ setTimeout(() => {
9114
+ const element = document.getElementById(section);
9115
+ if (element) {
9116
+ element.scrollIntoView({ behavior: 'smooth' });
9117
+ }
9118
+ }, 500);
9119
+ }
8771
9120
  }
8772
9121
  resetForm = () => {
8773
9122
  this.reset = !this.reset;
@@ -8943,6 +9292,7 @@ class CartItemEcComponent {
8943
9292
  _cartService = inject(CartService);
8944
9293
  _toastService = inject(ToastService);
8945
9294
  _constants = inject(CoreConstantsService);
9295
+ parametersService = inject(ParametersService);
8946
9296
  mediaUrl = this._constants.mediaUrl();
8947
9297
  quantity = 0;
8948
9298
  variantsToShow = ['TALLA', 'COLOR'];
@@ -9029,6 +9379,9 @@ class CartItemEcComponent {
9029
9379
  }
9030
9380
  return false; // Solo se ejecuta si no se cumple la condición
9031
9381
  }
9382
+ // PARAMETROS
9383
+ parameters$ = this.parametersService.getParameters();
9384
+ hasParams = this.parametersService.hasParams;
9032
9385
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CartItemEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9033
9386
  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"] }] });
9034
9387
  }
@@ -9540,108 +9893,174 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
9540
9893
  class MpRedirectEcComponent {
9541
9894
  _paymentService = inject(PaymentService);
9542
9895
  _toastService = inject(ToastService);
9896
+ platformId = inject(PLATFORM_ID);
9897
+ finished = false;
9543
9898
  method = null;
9544
9899
  total_amount = 0;
9545
9900
  allData;
9546
9901
  ready = new EventEmitter();
9547
9902
  preference;
9548
- loading = false;
9549
9903
  url;
9550
- closeModal = '';
9551
- ventana;
9552
- window;
9553
- localStorage;
9554
- platformId = inject(PLATFORM_ID);
9555
- constructor() {
9904
+ // Fases de UI
9905
+ phase = 'idle';
9906
+ get isIdle() { return this.phase === 'idle'; }
9907
+ get isPaying() { return this.phase === 'paying'; }
9908
+ get isFinalizing() { return this.phase === 'finalizing'; }
9909
+ ventana = null;
9910
+ windowRef;
9911
+ sid = '';
9912
+ bc;
9913
+ pollTimer;
9914
+ pollStartedAt = 0;
9915
+ ngOnInit() {
9556
9916
  if (isPlatformBrowser(this.platformId)) {
9557
- this.window = window;
9558
- this.localStorage = localStorage;
9917
+ this.windowRef = window;
9918
+ if ('BroadcastChannel' in window) {
9919
+ this.bc = new BroadcastChannel('mp_payment');
9920
+ this.bc.onmessage = (e) => this.onMpMessage(e?.data);
9921
+ }
9922
+ window.addEventListener('storage', this.onStorage);
9923
+ window.addEventListener('message', this.onWindowMessage);
9559
9924
  }
9560
- }
9561
- ngOnInit() {
9562
9925
  this.getPreference();
9563
9926
  }
9927
+ ngOnDestroy() {
9928
+ if (!isPlatformBrowser(this.platformId))
9929
+ return;
9930
+ this.bc?.close();
9931
+ window.removeEventListener('storage', this.onStorage);
9932
+ window.removeEventListener('message', this.onWindowMessage);
9933
+ if (this.pollTimer)
9934
+ clearInterval(this.pollTimer);
9935
+ }
9936
+ /** Cancela manualmente el pago y finaliza el flujo con estado "cancel". */
9564
9937
  clickClose = () => {
9565
- /* this.closeModal = 'cancel'
9566
- this.ventana?.close() */
9938
+ if (this.finished)
9939
+ return;
9940
+ this.finishWithState('cancel');
9567
9941
  };
9942
+ /**
9943
+ * Inicia el pago abriendo `init_point` en una ventana/pestaña nueva.
9944
+ * Genera un SID y lo persiste para casar la respuesta del catch.
9945
+ * Si el popup es bloqueado, hace fallback navegando en la misma pestaña.
9946
+ */
9568
9947
  iniciar = () => {
9569
- this.closeModal = '';
9570
- this.clearStorageState();
9571
- this.ventana = this.window?.open(this.url);
9572
- this.callState();
9573
- };
9574
- callState = () => {
9575
- let state = this.closeModal != '' ? this.closeModal : this.localStorage?.getItem('state');
9576
- !state && this.ventana.closed && (state = 'cancel');
9577
- this.loading = true;
9578
- state && console.log(state);
9579
- if (state) {
9580
- this.loading = false;
9581
- this.localStorage?.removeItem('state');
9582
- if (state == 'success') {
9583
- this.ventana?.close();
9584
- this.ready.emit(true);
9585
- return;
9586
- }
9587
- if (state == 'pending') {
9588
- this.ventana?.close();
9589
- this.ready.emit(true);
9590
- return;
9591
- }
9592
- if (state == 'failure') {
9593
- this.ventana?.close();
9594
- this.processError('');
9595
- return;
9596
- }
9597
- if (state == 'cancel') {
9598
- this.ventana?.close();
9599
- this.processError('Se cancelo el pago con mercado pago');
9948
+ if (!isPlatformBrowser(this.platformId) || !this.windowRef || !this.url)
9949
+ return;
9950
+ this.phase = 'paying';
9951
+ this.sid = this.genSid();
9952
+ const url = new URL(this.url);
9953
+ localStorage.setItem('mp:sid', this.sid);
9954
+ this.ventana = this.windowRef.open(this.url, '_blank');
9955
+ // popup bloqueado fallback a navegación en misma pestaña
9956
+ if (!this.ventana || this.ventana.closed) {
9957
+ this.windowRef.location.href = this.url;
9958
+ return;
9959
+ }
9960
+ // polling de último recurso (hasta 10 minutos)
9961
+ this.pollStartedAt = Date.now();
9962
+ if (this.pollTimer)
9963
+ clearInterval(this.pollTimer);
9964
+ this.pollTimer = setInterval(() => {
9965
+ if (Date.now() - this.pollStartedAt > 10 * 60 * 1000) {
9966
+ clearInterval(this.pollTimer);
9967
+ this.pollTimer = null;
9968
+ this.phase = 'idle';
9969
+ this.processError('Tiempo de espera agotado al procesar el pago.');
9600
9970
  return;
9601
9971
  }
9602
- this.ventana?.close();
9603
- this.processError('');
9972
+ this.checkLocalStorageOnce();
9973
+ }, 1000);
9974
+ };
9975
+ onWindowMessage = (event) => {
9976
+ const data = event?.data;
9977
+ this.onMpMessage(data);
9978
+ };
9979
+ onStorage = (e) => {
9980
+ if (!e.key || !this.sid)
9604
9981
  return;
9982
+ if (e.key === `mp:state:${this.sid}` && e.newValue) {
9983
+ const state = e.newValue;
9984
+ this.finishWithState(state);
9605
9985
  }
9606
- setTimeout(() => {
9607
- this.callState();
9608
- }, 5000);
9609
9986
  };
9610
- processError = (err) => {
9611
- this._toastService.show(err != '' ? err : 'payment-error');
9612
- // console.log("ERROR ENVIO BACK ", err);
9987
+ onMpMessage = (data) => {
9988
+ if (!data || data.type !== 'mp:state')
9989
+ return;
9990
+ if (data.sid !== this.sid)
9991
+ return;
9992
+ this.finishWithState(data.state);
9993
+ };
9994
+ checkLocalStorageOnce() {
9995
+ if (!this.sid)
9996
+ return;
9997
+ const state = localStorage.getItem(`mp:state:${this.sid}`);
9998
+ if (state)
9999
+ this.finishWithState(state);
10000
+ }
10001
+ /** Cierra el flujo de pago con el estado final y notifica al padre. */
10002
+ finishWithState(state) {
10003
+ if (this.finished)
10004
+ return;
10005
+ this.finished = true;
10006
+ if (this.pollTimer)
10007
+ clearInterval(this.pollTimer);
10008
+ this.pollTimer = null;
10009
+ localStorage.removeItem(`mp:state:${this.sid}`);
10010
+ localStorage.removeItem('mp:sid');
10011
+ localStorage.removeItem('state');
10012
+ try {
10013
+ this.ventana && !this.ventana.closed && this.ventana.close();
10014
+ }
10015
+ catch { }
10016
+ this.ventana = null;
10017
+ if (state === 'success' || state === 'pending') {
10018
+ this.phase = 'finalizing';
10019
+ this.ready.emit(true);
10020
+ }
10021
+ else if (state === 'failure' || state === 'cancel') {
10022
+ this.phase = 'idle';
10023
+ this._toastService.show(state === 'cancel' ? 'Se canceló el pago con Mercado Pago' : 'payment-error');
10024
+ }
10025
+ else {
10026
+ this.phase = 'idle';
10027
+ this._toastService.show('payment-error');
10028
+ }
10029
+ }
10030
+ genSid() {
10031
+ return `mp_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
10032
+ }
10033
+ processError = (msg) => {
10034
+ this._toastService.show(msg || 'payment-error');
9613
10035
  };
10036
+ /** Limpia posibles residuos de estado en storages. */
9614
10037
  clearStorageState = () => {
9615
- sessionStorage.removeItem('state');
9616
- this.localStorage?.removeItem('state');
10038
+ if (!isPlatformBrowser(this.platformId))
10039
+ return;
10040
+ localStorage.removeItem('state');
10041
+ const sid = localStorage.getItem('mp:sid');
10042
+ if (sid)
10043
+ localStorage.removeItem(`mp:state:${sid}`);
10044
+ };
10045
+ /** Obtiene la preferencia e inicializa `url` (init_point). */
10046
+ getPreference = () => {
10047
+ this._paymentService.getPreference(this.allData).then((res) => {
10048
+ this.preference = res;
10049
+ this.url = this.preference?.init_point;
10050
+ this.renderMP(this.preference);
10051
+ }, () => this.setError('operation-error'));
9617
10052
  };
9618
- getPreference = () => this._paymentService.getPreference(this.allData).then(res => {
9619
- this.preference = res;
9620
- this.url = this.preference.init_point;
9621
- this.renderMP(this.preference);
9622
- }, err => this.setError('operation-error'));
9623
10053
  setError = (message) => {
9624
10054
  //this.error = message;
9625
10055
  };
9626
- renderMP = (preference) => {
9627
- this.window?.addEventListener("message", (event) => {
9628
- if (event.origin !== 'https://www.mercadopago.com.ar' || !event.data.type) {
9629
- return;
9630
- }
9631
- let dataType = event.data.type;
9632
- if (dataType === 'submit') {
9633
- const paymentData = event.data.value;
9634
- return;
9635
- }
9636
- });
9637
- };
10056
+ renderMP = (_pref) => { };
9638
10057
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MpRedirectEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9639
- 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\t\t@if(!loading){\r\n\t\t\t<button (click)=\"iniciar()\" class=\"btn btn-outline-primary rounded-0 comprar mt-3\">Pagar</button>\r\n\t\t} @else {\r\n\t\t\t<div class=\"d-flex flex-column jusitfy-content-center align-items-center mt-2\">\r\n\t\t\t\t<h3>Procesando el pago por mercado pago</h3>\r\n\t\t\t\t<h5>Recuerde hacer click en \"Volver al sitio\" desde mercado pago para finalizar la compra.</h5>\r\n\t\t\t\t<app-loading-full-ec></app-loading-full-ec>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"container-fluid\">\r\n\t\t\t\t<div class=\"row\">\r\n\t\t\t\t\t<div class=\"col-5\">\r\n\t\t\t\t\t\t<hr>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div class=\"col-2 text-center\">\r\n\t\t\t\t\t\t<label for=\"\">o</label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div class=\"col-5\">\r\n\t\t\t\t\t\t<hr>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"d-flex flex-column justify-content-center align-items-center mt-2\">\r\n\t\t\t\t<button (click)=\"clickClose()\" class=\"btn btn-outline-secondary\">Cancelar pago</button>\r\n\t\t\t</div>\r\n\t\t}\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" }] });
10058
+ 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" }] });
9640
10059
  }
9641
10060
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MpRedirectEcComponent, decorators: [{
9642
10061
  type: Component,
9643
- args: [{ selector: 'app-mp-redirect-ec', standalone: true, imports: [LoadingFullEcComponent], template: "<div class=\"text-center\">\r\n\t@if(url){\r\n\t\t@if(!loading){\r\n\t\t\t<button (click)=\"iniciar()\" class=\"btn btn-outline-primary rounded-0 comprar mt-3\">Pagar</button>\r\n\t\t} @else {\r\n\t\t\t<div class=\"d-flex flex-column jusitfy-content-center align-items-center mt-2\">\r\n\t\t\t\t<h3>Procesando el pago por mercado pago</h3>\r\n\t\t\t\t<h5>Recuerde hacer click en \"Volver al sitio\" desde mercado pago para finalizar la compra.</h5>\r\n\t\t\t\t<app-loading-full-ec></app-loading-full-ec>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"container-fluid\">\r\n\t\t\t\t<div class=\"row\">\r\n\t\t\t\t\t<div class=\"col-5\">\r\n\t\t\t\t\t\t<hr>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div class=\"col-2 text-center\">\r\n\t\t\t\t\t\t<label for=\"\">o</label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div class=\"col-5\">\r\n\t\t\t\t\t\t<hr>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"d-flex flex-column justify-content-center align-items-center mt-2\">\r\n\t\t\t\t<button (click)=\"clickClose()\" class=\"btn btn-outline-secondary\">Cancelar pago</button>\r\n\t\t\t</div>\r\n\t\t}\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>" }]
9644
- }], ctorParameters: () => [], propDecorators: { method: [{
10062
+ 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>" }]
10063
+ }], propDecorators: { method: [{
9645
10064
  type: Input
9646
10065
  }], total_amount: [{
9647
10066
  type: Input
@@ -9880,6 +10299,8 @@ class DecidirEcComponent extends ComponentHelper {
9880
10299
  });
9881
10300
  };
9882
10301
  resizeIframe = (obj) => {
10302
+ if (typeof document === 'undefined' || !obj.contentWindow || !obj.contentWindow.document)
10303
+ return;
9883
10304
  obj.style.height = obj.contentWindow.document.body.scrollHeight + 'px';
9884
10305
  obj.style.width = obj.contentWindow.document.body.scrollWidth + 'px';
9885
10306
  };
@@ -11193,6 +11614,7 @@ class StoresEcComponent extends ComponentHelper {
11193
11614
  storesService;
11194
11615
  consts;
11195
11616
  sanitizer;
11617
+ platformId;
11196
11618
  stores = new BehaviorSubject([]);
11197
11619
  filterStores = null;
11198
11620
  storesAll = null;
@@ -11205,11 +11627,12 @@ class StoresEcComponent extends ComponentHelper {
11205
11627
  markers = [];
11206
11628
  locations = [];
11207
11629
  ultimoElementoSeleccionado = null;
11208
- constructor(storesService, consts, sanitizer) {
11630
+ constructor(storesService, consts, sanitizer, platformId) {
11209
11631
  super();
11210
11632
  this.storesService = storesService;
11211
11633
  this.consts = consts;
11212
11634
  this.sanitizer = sanitizer;
11635
+ this.platformId = platformId;
11213
11636
  this.urlmap = this.sanitizer.bypassSecurityTrustResourceUrl('https://www.google.com/maps/embed?pb=!1m10!1m8!1m3!1d13137.519688957545!2d-58.3888163!3d-34.5945533!3m2!1i1024!2i768!4f13.1!5e0!3m2!1ses-419!2sar!4v1523889204148');
11214
11637
  this.storesService.stores
11215
11638
  .pipe(filter$1((stores) => Array.isArray(stores) && stores.length > 0))
@@ -11282,6 +11705,8 @@ class StoresEcComponent extends ComponentHelper {
11282
11705
  return true;
11283
11706
  };
11284
11707
  initMap() {
11708
+ if (!isPlatformBrowser(this.platformId))
11709
+ return;
11285
11710
  this.storesService.stores.pipe(skipWhile(stores => !stores || stores.length === 0) // Omitir valores vacíos
11286
11711
  ).subscribe((res) => {
11287
11712
  // this.stores.next(res ?? []); // Eliminado para no sobrescribir el listado principal
@@ -11302,7 +11727,10 @@ class StoresEcComponent extends ComponentHelper {
11302
11727
  });
11303
11728
  const center = bounds.getCenter();
11304
11729
  const style = [{ "elementType": "geometry", "stylers": [{ "color": "#212121" }] }, { "elementType": "labels.icon", "stylers": [{ "visibility": "off" }] }, { "elementType": "labels.text.fill", "stylers": [{ "color": "#757575" }] }, { "elementType": "labels.text.stroke", "stylers": [{ "color": "#212121" }] }, { "featureType": "administrative", "elementType": "geometry", "stylers": [{ "color": "#757575" }] }, { "featureType": "administrative.country", "elementType": "labels.text.fill", "stylers": [{ "color": "#9e9e9e" }] }, { "featureType": "administrative.locality", "elementType": "labels.text.fill", "stylers": [{ "color": "#bdbdbd" }] }, { "featureType": "poi", "elementType": "labels.text.fill", "stylers": [{ "color": "#757575" }] }, { "featureType": "poi.business", "stylers": [{ "visibility": "off" }] }, { "featureType": "poi.park", "elementType": "geometry", "stylers": [{ "color": "#181818" }] }, { "featureType": "poi.park", "elementType": "labels.text.fill", "stylers": [{ "color": "#616161" }] }, { "featureType": "poi.park", "elementType": "labels.text.stroke", "stylers": [{ "color": "#1b1b1b" }] }, { "featureType": "road", "elementType": "geometry.fill", "stylers": [{ "color": "#2c2c2c" }] }, { "featureType": "road", "elementType": "labels.icon", "stylers": [{ "visibility": "off" }] }, { "featureType": "road", "elementType": "labels.text.fill", "stylers": [{ "color": "#8a8a8a" }] }, { "featureType": "road.arterial", "elementType": "geometry", "stylers": [{ "color": "#373737" }] }, { "featureType": "road.arterial", "elementType": "labels", "stylers": [{ "visibility": "off" }] }, { "featureType": "road.highway", "elementType": "geometry", "stylers": [{ "color": "#3c3c3c" }] }, { "featureType": "road.highway", "elementType": "labels", "stylers": [{ "visibility": "off" }] }, { "featureType": "road.highway.controlled_access", "elementType": "geometry", "stylers": [{ "color": "#4e4e4e" }] }, { "featureType": "road.local", "stylers": [{ "visibility": "off" }] }, { "featureType": "road.local", "elementType": "labels.text.fill", "stylers": [{ "color": "#616161" }] }, { "featureType": "transit", "stylers": [{ "visibility": "off" }] }, { "featureType": "transit", "elementType": "labels.text.fill", "stylers": [{ "color": "#757575" }] }, { "featureType": "water", "elementType": "geometry", "stylers": [{ "color": "#000000" }] }, { "featureType": "water", "elementType": "labels.text.fill", "stylers": [{ "color": "#3d3d3d" }] }];
11305
- this.map = new google.maps.Map(document.getElementById('map'), {
11730
+ const mapElement = document.getElementById('map');
11731
+ if (!mapElement)
11732
+ return;
11733
+ this.map = new google.maps.Map(mapElement, {
11306
11734
  zoom: 12,
11307
11735
  center: center, // Centrar el mapa en el centro calculado
11308
11736
  styles: style // Aplica los estilos personalizados
@@ -11320,6 +11748,8 @@ class StoresEcComponent extends ComponentHelper {
11320
11748
  marker.set('id', location.id); // Associate marker with its ID
11321
11749
  this.markers.push(marker);
11322
11750
  marker.addListener('click', () => {
11751
+ if (typeof document === 'undefined')
11752
+ return;
11323
11753
  const elemento = document.getElementById(location.id);
11324
11754
  const contenedor = document.getElementById('home');
11325
11755
  if (elemento && contenedor) {
@@ -11347,6 +11777,8 @@ class StoresEcComponent extends ComponentHelper {
11347
11777
  });
11348
11778
  }
11349
11779
  showStoreOnMap(storeCode) {
11780
+ if (!isPlatformBrowser(this.platformId))
11781
+ return;
11350
11782
  this.stopBounce();
11351
11783
  const marker = this.markers.find(m => m.get('id') === storeCode);
11352
11784
  const elemento = document.getElementById(storeCode);
@@ -11368,13 +11800,16 @@ class StoresEcComponent extends ComponentHelper {
11368
11800
  marker.setAnimation(null);
11369
11801
  });
11370
11802
  }
11371
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StoresEcComponent, deps: [{ token: StoresService }, { token: CoreConstantsService }, { token: i1$4.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component });
11803
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StoresEcComponent, deps: [{ token: StoresService }, { token: CoreConstantsService }, { token: i1$4.DomSanitizer }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Component });
11372
11804
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: StoresEcComponent, isStandalone: true, selector: "app-store-ec", usesInheritance: true, ngImport: i0, template: "<!-- <div class=\"row w-100 mx-auto my-4 px-3 bb-s bt-md-s py-1\">\r\n <strong>{{ 'stores' | translate }}</strong>\r\n</div>\r\n@if(stores){\r\n<div class=\"row\">\r\n <div class=\"col-12 col-md-3 order-1 order-md-1\">\r\n <div class=\"row\">\r\n <div class=\"form-group w-100\">\r\n <select (change)=\"selectChange($event.target.value)\" class=\"rounded-0 form-control form-control-sm\"\r\n id=\"exampleFormControlSelect1\">\r\n <option selected [value]=\"''\">Seleccione provincia</option>\r\n <option [value]=\"item.code\" *ngFor=\"let item of getProvices(stores)\"> {{item.name}}\r\n </option>\r\n </select>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"col-12 col-md-3 order-3 order-md-2\">\r\n <div class=\"container-fluid scrolleable\" *ngIf=\"filterStores && filterStores.length\">\r\n <div class=\"row mb-1\" *ngFor=\"let store of filterStores; let i = index\">\r\n <div class=\"col-12\">\r\n <h6 class=\"\"><strong>{{ store.name }}</strong></h6>\r\n <label>{{ store.address }}</label>\r\n <label>{{ store.phone }}</label>\r\n <div [innerHtml]=\"store.note\"></div>\r\n <div class=\"text-right\">\r\n\r\n <a *ngIf=\"store.urlMap\" (click)=\"updateMap (store.urlMap)\" class=\"custom-a\">Ver mapa</a>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"col-12 col-md-6 order-2 order-md-3 my-4 mt-md-0\">\r\n\r\n <iframe id=\"map-iframe\" [src]=\"urlmap\" frameborder=\"0\"></iframe>\r\n </div>\r\n</div>\r\n}@else {\r\n<div class=\"d-flex flex-row justify-content-center my-5 align-items-center alto-total\">\r\n <h5 class=\"text-center\">{{ 'no-stores' | translate }}</h5>\r\n</div>\r\n}\r\n\r\n\r\n\r\n<ng-template #loading>\r\n <div class=\"container\">\r\n <div class=\"row\">\r\n <div class=\"col-12 align-items-center\">\r\n <div class=\"d-flex flex-column justify-content-center align-items-center my-5\">\r\n <app-loading-full-ec></app-loading-full-ec>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</ng-template> -->", styles: [".scrolleable{height:70vh;overflow:auto}@media screen and (max-width: 768px){.scrolleable{height:auto}}.background-white{background-color:#fff}.alto-total{height:60vh}.custom-a{color:#000}#map-iframe{width:100%;border:0;height:100%}@media screen and (max-width: 425px){#map-iframe{height:400px}}\n"], dependencies: [{ kind: "ngmodule", type: TranslateModule }] });
11373
11805
  }
11374
11806
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StoresEcComponent, decorators: [{
11375
11807
  type: Component,
11376
11808
  args: [{ selector: 'app-store-ec', standalone: true, imports: [TranslateModule], template: "<!-- <div class=\"row w-100 mx-auto my-4 px-3 bb-s bt-md-s py-1\">\r\n <strong>{{ 'stores' | translate }}</strong>\r\n</div>\r\n@if(stores){\r\n<div class=\"row\">\r\n <div class=\"col-12 col-md-3 order-1 order-md-1\">\r\n <div class=\"row\">\r\n <div class=\"form-group w-100\">\r\n <select (change)=\"selectChange($event.target.value)\" class=\"rounded-0 form-control form-control-sm\"\r\n id=\"exampleFormControlSelect1\">\r\n <option selected [value]=\"''\">Seleccione provincia</option>\r\n <option [value]=\"item.code\" *ngFor=\"let item of getProvices(stores)\"> {{item.name}}\r\n </option>\r\n </select>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"col-12 col-md-3 order-3 order-md-2\">\r\n <div class=\"container-fluid scrolleable\" *ngIf=\"filterStores && filterStores.length\">\r\n <div class=\"row mb-1\" *ngFor=\"let store of filterStores; let i = index\">\r\n <div class=\"col-12\">\r\n <h6 class=\"\"><strong>{{ store.name }}</strong></h6>\r\n <label>{{ store.address }}</label>\r\n <label>{{ store.phone }}</label>\r\n <div [innerHtml]=\"store.note\"></div>\r\n <div class=\"text-right\">\r\n\r\n <a *ngIf=\"store.urlMap\" (click)=\"updateMap (store.urlMap)\" class=\"custom-a\">Ver mapa</a>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"col-12 col-md-6 order-2 order-md-3 my-4 mt-md-0\">\r\n\r\n <iframe id=\"map-iframe\" [src]=\"urlmap\" frameborder=\"0\"></iframe>\r\n </div>\r\n</div>\r\n}@else {\r\n<div class=\"d-flex flex-row justify-content-center my-5 align-items-center alto-total\">\r\n <h5 class=\"text-center\">{{ 'no-stores' | translate }}</h5>\r\n</div>\r\n}\r\n\r\n\r\n\r\n<ng-template #loading>\r\n <div class=\"container\">\r\n <div class=\"row\">\r\n <div class=\"col-12 align-items-center\">\r\n <div class=\"d-flex flex-column justify-content-center align-items-center my-5\">\r\n <app-loading-full-ec></app-loading-full-ec>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</ng-template> -->", styles: [".scrolleable{height:70vh;overflow:auto}@media screen and (max-width: 768px){.scrolleable{height:auto}}.background-white{background-color:#fff}.alto-total{height:60vh}.custom-a{color:#000}#map-iframe{width:100%;border:0;height:100%}@media screen and (max-width: 425px){#map-iframe{height:400px}}\n"] }]
11377
- }], ctorParameters: () => [{ type: StoresService }, { type: CoreConstantsService }, { type: i1$4.DomSanitizer }] });
11809
+ }], ctorParameters: () => [{ type: StoresService }, { type: CoreConstantsService }, { type: i1$4.DomSanitizer }, { type: Object, decorators: [{
11810
+ type: Inject,
11811
+ args: [PLATFORM_ID]
11812
+ }] }] });
11378
11813
 
11379
11814
  class PriceRangeFilterComponent {
11380
11815
  _filtersService = inject(FiltersService);
@@ -11761,5 +12196,5 @@ const directives = [
11761
12196
  * Generated bundle index. Do not edit.
11762
12197
  */
11763
12198
 
11764
- 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 };
12199
+ 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 };
11765
12200
  //# sourceMappingURL=ng-easycommerce-v18.mjs.map