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

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 (28) hide show
  1. package/README.md +18 -0
  2. package/esm2022/lib/ec-components/abstractions-components/menu-ec.component.mjs +17 -1
  3. package/esm2022/lib/ec-components/auth-ec/login-form-ec/login-form-ec.component.mjs +5 -1
  4. package/esm2022/lib/ec-components/auth-ec/register-form-ec/register-form-ec.component.mjs +5 -1
  5. package/esm2022/lib/ec-components/cart-ec/cart-item-ec/cart-item-ec.component.mjs +6 -2
  6. package/esm2022/lib/ec-components/checkout-ec/payment-ec/payment-methods/mp-redirect-ec/mp-redirect-ec.component.mjs +141 -75
  7. package/esm2022/lib/ec-components/filters-ec/filters-ec.component.mjs +30 -5
  8. package/esm2022/lib/ec-components/header-ec/header-ec.component.mjs +23 -3
  9. package/esm2022/lib/ec-components/product-ec/product-ec.component.mjs +95 -5
  10. package/esm2022/lib/ec-components/widgets-ec/index.mjs +2 -1
  11. package/esm2022/lib/ec-components/widgets-ec/redsys-catch-ec/redsys-catch-ec.component.mjs +193 -0
  12. package/esm2022/lib/interfaces/filter.mjs +1 -1
  13. package/esm2022/lib/interfaces/options.mjs +1 -1
  14. package/fesm2022/ng-easycommerce-v18.mjs +517 -106
  15. package/fesm2022/ng-easycommerce-v18.mjs.map +1 -1
  16. package/lib/ec-components/abstractions-components/menu-ec.component.d.ts +12 -0
  17. package/lib/ec-components/auth-ec/login-form-ec/login-form-ec.component.d.ts +2 -0
  18. package/lib/ec-components/auth-ec/register-form-ec/register-form-ec.component.d.ts +2 -0
  19. package/lib/ec-components/cart-ec/cart-item-ec/cart-item-ec.component.d.ts +5 -0
  20. package/lib/ec-components/checkout-ec/payment-ec/payment-methods/mp-redirect-ec/mp-redirect-ec.component.d.ts +38 -16
  21. package/lib/ec-components/filters-ec/filters-ec.component.d.ts +12 -4
  22. package/lib/ec-components/header-ec/header-ec.component.d.ts +5 -1
  23. package/lib/ec-components/product-ec/product-ec.component.d.ts +10 -1
  24. package/lib/ec-components/widgets-ec/index.d.ts +1 -0
  25. package/lib/ec-components/widgets-ec/redsys-catch-ec/redsys-catch-ec.component.d.ts +47 -0
  26. package/lib/interfaces/filter.d.ts +1 -0
  27. package/lib/interfaces/options.d.ts +2 -0
  28. 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';
@@ -6057,6 +6057,22 @@ class MenuEcComponent {
6057
6057
  hasVisibleProperty(category) {
6058
6058
  return category.isVisible === true;
6059
6059
  }
6060
+ filterVisibleTree(list) {
6061
+ return (list ?? [])
6062
+ .filter((n) => n?.isVisible === true)
6063
+ .map(n => ({ ...n, children: this.filterVisibleTree(n.children) }));
6064
+ }
6065
+ // Exponé streams ya filtrados
6066
+ categoriesVisible$ = this.categories$.pipe(map((list) => this.filterVisibleTree(list)));
6067
+ sectionsVisible$ = this.sections$.pipe(map((list) => this.filterVisibleTree(list)));
6068
+ attributesVisible$ = this.attributes$.pipe(map((list) => this.filterVisibleTree(list)));
6069
+ // Helpers de conveniencia opcionales
6070
+ getVisibleChildren(node) {
6071
+ return this.filterVisibleTree(node?.children);
6072
+ }
6073
+ hasVisibleChildren(node) {
6074
+ return this.getVisibleChildren(node).length > 0;
6075
+ }
6060
6076
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MenuEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6061
6077
  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
6078
  }
@@ -6203,6 +6219,11 @@ class HeaderEcComponent extends MenuEcComponent {
6203
6219
  hidePrices = false;
6204
6220
  __authService = inject(AuthService);
6205
6221
  _channelService = inject(ChannelService);
6222
+ changeDetector = inject(ChangeDetectorRef);
6223
+ appRouter = inject(Router);
6224
+ platformId = inject(PLATFORM_ID);
6225
+ // Observable del estado de autenticación
6226
+ logged$;
6206
6227
  isAuthenticated$ = this.__authService.isAuthenticated();
6207
6228
  constructor() {
6208
6229
  super();
@@ -6216,11 +6237,26 @@ class HeaderEcComponent extends MenuEcComponent {
6216
6237
  coreConstantsService = inject(CoreConstantsService);
6217
6238
  router = inject(Router);
6218
6239
  cdr = inject(ChangeDetectorRef); // Inyectamos ChangeDetectorRef para forzar la actualización
6219
- platformId = inject(PLATFORM_ID);
6220
6240
  ngOnInit() {
6221
6241
  this.channel = this.coreConstantsService.getChannel();
6222
6242
  this.onWindowScroll();
6223
6243
  this.detectRouteChange(); // Llamamos a la función que detecta el cambio de ruta
6244
+ // Usar el Observable del AuthService
6245
+ this.logged$ = this.__authService.loggedIn$;
6246
+ // Suscribirse al Observable y forzar detección de cambios cuando sea necesario
6247
+ this.logged$.subscribe(isLoggedIn => {
6248
+ this.changeDetector.detectChanges();
6249
+ });
6250
+ if (isPlatformBrowser(this.platformId)) {
6251
+ this.appRouter.events.subscribe(evt => {
6252
+ if (evt instanceof NavigationEnd) {
6253
+ // Forzar detección de cambios después de navegación
6254
+ setTimeout(() => {
6255
+ this.changeDetector.detectChanges();
6256
+ }, 100);
6257
+ }
6258
+ });
6259
+ }
6224
6260
  }
6225
6261
  ngAfterViewInit() {
6226
6262
  this.setupMobileMenu(); // Inicializamos el menú móvil
@@ -6934,6 +6970,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
6934
6970
  class ProductEcComponent {
6935
6971
  injector = inject(Injector);
6936
6972
  routerService = inject(Router);
6973
+ _cartService = inject(CartService);
6974
+ _toastService = inject(ToastService);
6975
+ isAddingToCart = signal(false);
6976
+ quantity = signal(1);
6937
6977
  /**
6938
6978
  * Navega al detalle del producto y sube al inicio de la página
6939
6979
  * @param productId ID del producto
@@ -7006,12 +7046,97 @@ class ProductEcComponent {
7006
7046
  const discount = ((originalPrice - salePrice) / originalPrice) * 100;
7007
7047
  return Math.round(discount);
7008
7048
  }
7049
+ plus(stock, multipleQuantity) {
7050
+ console.log('Aumentando cantidad');
7051
+ const current = Number(this.quantity()); // <-- fuerza a número
7052
+ if (multipleQuantity && multipleQuantity > 0) {
7053
+ stock
7054
+ ? (current < stock
7055
+ ? this.quantity.set(current + multipleQuantity)
7056
+ : this._toastService.show('out-of-stock-actually'))
7057
+ : this.quantity.set(current + multipleQuantity);
7058
+ }
7059
+ else {
7060
+ stock
7061
+ ? (current < stock
7062
+ ? this.quantity.set(current + 1)
7063
+ : this._toastService.show('out-of-stock-actually'))
7064
+ : this.quantity.set(current + 1);
7065
+ }
7066
+ }
7067
+ less(multipleQuantity) {
7068
+ console.log('Disminuyendo cantidad');
7069
+ const current = Number(this.quantity()); // <-- fuerza a número
7070
+ if (multipleQuantity && multipleQuantity > 0) {
7071
+ current > multipleQuantity
7072
+ ? this.quantity.set(current - multipleQuantity)
7073
+ : null;
7074
+ }
7075
+ else {
7076
+ current > 1 ? this.quantity.set(current - 1) : null;
7077
+ }
7078
+ }
7079
+ addToCart() {
7080
+ console.log('Añadiendo al carrito');
7081
+ if (this.isAddingToCart() || this.quantity() <= 0)
7082
+ return;
7083
+ // Verificar que tenemos el producto y sus variantes
7084
+ if (!this.product || !this.product.variants || this.product.variants.length === 0) {
7085
+ this._toastService.show('cant-buy');
7086
+ return;
7087
+ }
7088
+ // Verificar stock
7089
+ const firstVariant = this.product.variants[0];
7090
+ if (!firstVariant.stock || firstVariant.stock <= 0) {
7091
+ this._toastService.show('out-of-stock');
7092
+ return;
7093
+ }
7094
+ // Verificar que no se supere el stock disponible
7095
+ if (this.quantity() > firstVariant.stock) {
7096
+ this._toastService.show('out-of-stock-actually');
7097
+ return;
7098
+ }
7099
+ this.isAddingToCart.set(true);
7100
+ try {
7101
+ // Agregar al carrito usando CartService directamente
7102
+ this._cartService.addToCart(this.product, this.quantity(), firstVariant.code);
7103
+ console.log('Producto agregado al carrito exitosamente');
7104
+ // Resetear cantidad a 1 después de agregar al carrito
7105
+ this.quantity.set(1);
7106
+ }
7107
+ catch (error) {
7108
+ console.error('Error al agregar al carrito:', error);
7109
+ this._toastService.show('cant-buy');
7110
+ }
7111
+ setTimeout(() => {
7112
+ this.isAddingToCart.set(false);
7113
+ }, 2000);
7114
+ }
7115
+ checkStock(stock) {
7116
+ if (this.quantity() >= stock)
7117
+ this.quantity.set(stock);
7118
+ }
7119
+ onQuantityChange(event) {
7120
+ const target = event.target;
7121
+ const value = +target.value;
7122
+ // Validar que el valor sea mayor a 0
7123
+ if (value > 0) {
7124
+ this.quantity.set(value);
7125
+ // Validar contra el stock disponible
7126
+ const maxStock = this.product?.variants?.[0]?.stock || this.product?.stock || 0;
7127
+ this.checkStock(maxStock);
7128
+ }
7129
+ else {
7130
+ // Si el valor es 0 o negativo, resetear a 1
7131
+ this.quantity.set(1);
7132
+ }
7133
+ }
7009
7134
  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" }] });
7135
+ 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
7136
  }
7012
7137
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProductEcComponent, decorators: [{
7013
7138
  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>" }]
7139
+ 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
7140
  }], ctorParameters: () => [], propDecorators: { product: [{
7016
7141
  type: Input,
7017
7142
  args: [{
@@ -7589,6 +7714,212 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
7589
7714
  args: ['mainCanvas', { static: true }]
7590
7715
  }] } });
7591
7716
 
7717
+ class ComponentHelper {
7718
+ constructor() {
7719
+ this.ecOnConstruct();
7720
+ }
7721
+ ecOnInit = (params = {}) => {
7722
+ };
7723
+ ecOnConstruct = (params = {}) => {
7724
+ };
7725
+ hasParams = (params, searched) => {
7726
+ if (!params || !searched)
7727
+ return false;
7728
+ const q = searched.trim().toLowerCase();
7729
+ return params.some(p => {
7730
+ const code = p?.['code']?.toString().toLowerCase() ?? '';
7731
+ // Primero chequeo exacto, y si no, parcial
7732
+ return code === q || code.includes(q);
7733
+ });
7734
+ };
7735
+ navigateOnRouter(router, url) {
7736
+ router.navigateByUrl(`/${url}`);
7737
+ }
7738
+ }
7739
+
7740
+ /**
7741
+ * Catch genérico para redirecciones de pagos.
7742
+ * - Normaliza el estado recibido por params/query.
7743
+ * - Informa el resultado al opener (postMessage), BroadcastChannel y localStorage.
7744
+ * - Intenta cerrarse; si el cierre falla, redirige según el estado.
7745
+ */
7746
+ class RedsysCatchEcComponent extends ComponentHelper {
7747
+ activedRoute;
7748
+ router;
7749
+ checkoutService;
7750
+ renderer;
7751
+ elementRef;
7752
+ document;
7753
+ platformId;
7754
+ message = '';
7755
+ subscription = null;
7756
+ sid = '';
7757
+ bc;
7758
+ constructor(activedRoute, router, checkoutService, renderer, elementRef, document, platformId) {
7759
+ super();
7760
+ this.activedRoute = activedRoute;
7761
+ this.router = router;
7762
+ this.checkoutService = checkoutService;
7763
+ this.renderer = renderer;
7764
+ this.elementRef = elementRef;
7765
+ this.document = document;
7766
+ this.platformId = platformId;
7767
+ this.hideHeaderFooter();
7768
+ this.ecOnConstruct();
7769
+ }
7770
+ ngOnInit() {
7771
+ if (isPlatformBrowser(this.platformId) && 'BroadcastChannel' in window) {
7772
+ this.bc = new BroadcastChannel('mp_payment');
7773
+ }
7774
+ this.subscription = combineLatest([this.activedRoute.params, this.activedRoute.queryParams])
7775
+ .subscribe(([routeParams, q]) => {
7776
+ let stateStr = routeParams['state'];
7777
+ if (stateStr === 'statuspayment')
7778
+ stateStr = q['status'];
7779
+ const statusParam = (stateStr || q['status'] || q['state'] || '').toString();
7780
+ const state = this.normalizeState(statusParam);
7781
+ this.sid = (q['sid'] || (isPlatformBrowser(this.platformId) ? localStorage.getItem('mp:sid') : '') || '').toString();
7782
+ this.storeTotalAmount(q);
7783
+ this.setStateInLocal('Su pago fue procesado con éxito.', state);
7784
+ this.signalState(state);
7785
+ this.tryCloseSelf(() => {
7786
+ const target = (state === 'success' || state === 'pending')
7787
+ ? ['/checkout/order_success']
7788
+ : ['/checkout'];
7789
+ setTimeout(() => this.router.navigate(target), 4500);
7790
+ });
7791
+ });
7792
+ this.ecOnInit();
7793
+ }
7794
+ ngOnDestroy() {
7795
+ this.subscription?.unsubscribe();
7796
+ this.bc?.close();
7797
+ this.showHeaderFooter();
7798
+ }
7799
+ /** Guarda total_amount si viene desde el PSP. */
7800
+ storeTotalAmount(queryParams) {
7801
+ const totalAmount = queryParams['total_amount'];
7802
+ if (totalAmount && isPlatformBrowser(this.platformId)) {
7803
+ localStorage.setItem('total_amount', totalAmount);
7804
+ }
7805
+ }
7806
+ /** Setea mensaje y estado en storages. */
7807
+ setStateInLocal = (mensaje, state) => {
7808
+ this.message = mensaje;
7809
+ if (!isPlatformBrowser(this.platformId))
7810
+ return;
7811
+ try {
7812
+ localStorage.setItem('state', state);
7813
+ }
7814
+ catch { }
7815
+ try {
7816
+ sessionStorage.setItem('modalnews', 'false');
7817
+ }
7818
+ catch { }
7819
+ };
7820
+ /** Normaliza estados heterogéneos de distintos gateways. */
7821
+ normalizeState(raw) {
7822
+ const v = (raw || '').toLowerCase();
7823
+ if (v === '200' || v === 'ok' || v === 'success')
7824
+ return 'success';
7825
+ if (v === 'pending')
7826
+ return 'pending';
7827
+ if (v === 'cancel')
7828
+ return 'cancel';
7829
+ return 'failure'; // failure, 0, error, rejected, chargeback, desconocidos
7830
+ }
7831
+ /**
7832
+ * Informa el resultado: postMessage al opener, BroadcastChannel y localStorage
7833
+ * (este último permite polling en la pestaña madre).
7834
+ */
7835
+ signalState(state) {
7836
+ if (!isPlatformBrowser(this.platformId))
7837
+ return;
7838
+ const sid = this.sid || localStorage.getItem('mp:sid') || '';
7839
+ const payload = { type: 'mp:state', sid, state };
7840
+ try {
7841
+ window.opener && window.opener.postMessage(payload, '*');
7842
+ }
7843
+ catch { }
7844
+ try {
7845
+ this.bc?.postMessage(payload);
7846
+ }
7847
+ catch { }
7848
+ try {
7849
+ localStorage.setItem(`mp:state:${sid}`, state);
7850
+ }
7851
+ catch { }
7852
+ try {
7853
+ localStorage.setItem('state', state);
7854
+ }
7855
+ catch { }
7856
+ }
7857
+ /** Intenta cerrar la pestaña actual; si falla, ejecuta el callback de fallback. */
7858
+ tryCloseSelf(onFail) {
7859
+ if (!isPlatformBrowser(this.platformId))
7860
+ return onFail();
7861
+ let attempted = false;
7862
+ try {
7863
+ window.close();
7864
+ attempted = true;
7865
+ }
7866
+ catch { }
7867
+ if (!attempted)
7868
+ onFail();
7869
+ }
7870
+ /** Oculta header/footer para esta pantalla mínima. */
7871
+ hideHeaderFooter() {
7872
+ if (!isPlatformBrowser(this.platformId))
7873
+ return;
7874
+ const header = this.document.querySelector('header');
7875
+ const footer = this.document.querySelector('footer');
7876
+ if (header)
7877
+ this.renderer.setStyle(header, 'display', 'none');
7878
+ if (footer)
7879
+ this.renderer.setStyle(footer, 'display', 'none');
7880
+ }
7881
+ /** Restaura header/footer al salir. */
7882
+ showHeaderFooter() {
7883
+ if (!isPlatformBrowser(this.platformId))
7884
+ return;
7885
+ const header = this.document.querySelector('header');
7886
+ const footer = this.document.querySelector('footer');
7887
+ if (header)
7888
+ this.renderer.removeStyle(header, 'display');
7889
+ if (footer)
7890
+ this.renderer.removeStyle(footer, 'display');
7891
+ }
7892
+ setStateInSession(mensaje, state) {
7893
+ this.message = mensaje;
7894
+ if (!isPlatformBrowser(this.platformId))
7895
+ return;
7896
+ try {
7897
+ sessionStorage.setItem('state', state);
7898
+ }
7899
+ catch { }
7900
+ try {
7901
+ localStorage.setItem('state', state);
7902
+ }
7903
+ catch { }
7904
+ try {
7905
+ sessionStorage.setItem('modalnews', 'false');
7906
+ }
7907
+ catch { }
7908
+ }
7909
+ 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 });
7910
+ 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" }] });
7911
+ }
7912
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RedsysCatchEcComponent, decorators: [{
7913
+ type: Component,
7914
+ 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"] }]
7915
+ }], ctorParameters: () => [{ type: i2.ActivatedRoute }, { type: i2.Router }, { type: CheckoutService }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: Document, decorators: [{
7916
+ type: Inject,
7917
+ args: [DOCUMENT]
7918
+ }] }, { type: undefined, decorators: [{
7919
+ type: Inject,
7920
+ args: [PLATFORM_ID]
7921
+ }] }] });
7922
+
7592
7923
  // export * from './rating-ec/rating-ec.component';
7593
7924
 
7594
7925
  class BlockFormContactEcComponent extends BlockEcComponent {
@@ -7864,6 +8195,7 @@ class LoginFormEcComponent {
7864
8195
  _formBuilder = inject(FormBuilder);
7865
8196
  _toastService = inject(ToastService);
7866
8197
  _router = inject(Router);
8198
+ showPassword = false;
7867
8199
  /**
7868
8200
  * Parametro para indicar si tras loguear
7869
8201
  * debe redireccionar o no.
@@ -7952,6 +8284,9 @@ class LoginFormEcComponent {
7952
8284
  ? resolverFunction()
7953
8285
  : this._router.navigateByUrl(this.redirectTo);
7954
8286
  }
8287
+ togglePassword() {
8288
+ this.showPassword = !this.showPassword;
8289
+ }
7955
8290
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LoginFormEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7956
8291
  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
8292
  }
@@ -8051,6 +8386,7 @@ class RegisterFormEcComponent {
8051
8386
  _analyticsService = inject(AnalyticsService);
8052
8387
  _formBuilder = inject(FormBuilder);
8053
8388
  channelConfigService = inject(ChannelService);
8389
+ showPassword = false;
8054
8390
  /**
8055
8391
  * Indica si debe redireccionar o se queda en la misma pantalla
8056
8392
  */
@@ -8166,6 +8502,9 @@ class RegisterFormEcComponent {
8166
8502
  this.register_loading = false;
8167
8503
  }
8168
8504
  }
8505
+ togglePassword() {
8506
+ this.showPassword = !this.showPassword;
8507
+ }
8169
8508
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RegisterFormEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8170
8509
  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
8510
  }
@@ -8320,29 +8659,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
8320
8659
  type: Output
8321
8660
  }] } });
8322
8661
 
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
8662
  class PasswordResetEcComponent extends ComponentHelper {
8347
8663
  authService;
8348
8664
  toastr;
@@ -8484,6 +8800,8 @@ class FiltersEcComponent {
8484
8800
  console.error('Filter or selected element is undefined:', { filter, selected });
8485
8801
  return;
8486
8802
  }
8803
+ if (selected.isVisible !== true)
8804
+ return;
8487
8805
  if (typeof filter.setSelected !== 'function') {
8488
8806
  console.error('filter.setSelected is not a function. Filter might not be an instance of the expected class:', filter);
8489
8807
  return;
@@ -8553,13 +8871,36 @@ class FiltersEcComponent {
8553
8871
  }) ?? false;
8554
8872
  }
8555
8873
  /**
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
- */
8874
+ * Verifica si una categoría tiene la propiedad isVisible y está marcada como visible
8875
+ * @param category - La categoría a verificar
8876
+ * @returns true si la categoría es visible, false en caso contrario
8877
+ */
8560
8878
  hasVisibleProperty(category) {
8561
8879
  return category.isVisible === true;
8562
8880
  }
8881
+ /** Lista visible (filtra recursivo por isVisible) */
8882
+ getVisibleData(filter) {
8883
+ if (!filter)
8884
+ return [];
8885
+ return this.filterVisibleTree(filter.data);
8886
+ }
8887
+ /** Children visibles de un nodo */
8888
+ getVisibleChildren(node) {
8889
+ return this.filterVisibleTree(node?.children ?? []);
8890
+ }
8891
+ /** Tiene hijos visibles? */
8892
+ hasVisibleChildren(node) {
8893
+ return this.getVisibleChildren(node).length > 0;
8894
+ }
8895
+ /** Utilidad recursiva */
8896
+ filterVisibleTree(list = []) {
8897
+ return (list ?? [])
8898
+ .filter(n => n.isVisible === true)
8899
+ .map(n => ({
8900
+ ...n,
8901
+ children: this.filterVisibleTree(n.children ?? [])
8902
+ }));
8903
+ }
8563
8904
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FiltersEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8564
8905
  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
8906
  }
@@ -8943,6 +9284,7 @@ class CartItemEcComponent {
8943
9284
  _cartService = inject(CartService);
8944
9285
  _toastService = inject(ToastService);
8945
9286
  _constants = inject(CoreConstantsService);
9287
+ parametersService = inject(ParametersService);
8946
9288
  mediaUrl = this._constants.mediaUrl();
8947
9289
  quantity = 0;
8948
9290
  variantsToShow = ['TALLA', 'COLOR'];
@@ -9029,6 +9371,9 @@ class CartItemEcComponent {
9029
9371
  }
9030
9372
  return false; // Solo se ejecuta si no se cumple la condición
9031
9373
  }
9374
+ // PARAMETROS
9375
+ parameters$ = this.parametersService.getParameters();
9376
+ hasParams = this.parametersService.hasParams;
9032
9377
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CartItemEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9033
9378
  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
9379
  }
@@ -9540,108 +9885,174 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
9540
9885
  class MpRedirectEcComponent {
9541
9886
  _paymentService = inject(PaymentService);
9542
9887
  _toastService = inject(ToastService);
9888
+ platformId = inject(PLATFORM_ID);
9889
+ finished = false;
9543
9890
  method = null;
9544
9891
  total_amount = 0;
9545
9892
  allData;
9546
9893
  ready = new EventEmitter();
9547
9894
  preference;
9548
- loading = false;
9549
9895
  url;
9550
- closeModal = '';
9551
- ventana;
9552
- window;
9553
- localStorage;
9554
- platformId = inject(PLATFORM_ID);
9555
- constructor() {
9896
+ // Fases de UI
9897
+ phase = 'idle';
9898
+ get isIdle() { return this.phase === 'idle'; }
9899
+ get isPaying() { return this.phase === 'paying'; }
9900
+ get isFinalizing() { return this.phase === 'finalizing'; }
9901
+ ventana = null;
9902
+ windowRef;
9903
+ sid = '';
9904
+ bc;
9905
+ pollTimer;
9906
+ pollStartedAt = 0;
9907
+ ngOnInit() {
9556
9908
  if (isPlatformBrowser(this.platformId)) {
9557
- this.window = window;
9558
- this.localStorage = localStorage;
9909
+ this.windowRef = window;
9910
+ if ('BroadcastChannel' in window) {
9911
+ this.bc = new BroadcastChannel('mp_payment');
9912
+ this.bc.onmessage = (e) => this.onMpMessage(e?.data);
9913
+ }
9914
+ window.addEventListener('storage', this.onStorage);
9915
+ window.addEventListener('message', this.onWindowMessage);
9559
9916
  }
9560
- }
9561
- ngOnInit() {
9562
9917
  this.getPreference();
9563
9918
  }
9919
+ ngOnDestroy() {
9920
+ if (!isPlatformBrowser(this.platformId))
9921
+ return;
9922
+ this.bc?.close();
9923
+ window.removeEventListener('storage', this.onStorage);
9924
+ window.removeEventListener('message', this.onWindowMessage);
9925
+ if (this.pollTimer)
9926
+ clearInterval(this.pollTimer);
9927
+ }
9928
+ /** Cancela manualmente el pago y finaliza el flujo con estado "cancel". */
9564
9929
  clickClose = () => {
9565
- /* this.closeModal = 'cancel'
9566
- this.ventana?.close() */
9930
+ if (this.finished)
9931
+ return;
9932
+ this.finishWithState('cancel');
9567
9933
  };
9934
+ /**
9935
+ * Inicia el pago abriendo `init_point` en una ventana/pestaña nueva.
9936
+ * Genera un SID y lo persiste para casar la respuesta del catch.
9937
+ * Si el popup es bloqueado, hace fallback navegando en la misma pestaña.
9938
+ */
9568
9939
  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');
9940
+ if (!isPlatformBrowser(this.platformId) || !this.windowRef || !this.url)
9941
+ return;
9942
+ this.phase = 'paying';
9943
+ this.sid = this.genSid();
9944
+ const url = new URL(this.url);
9945
+ localStorage.setItem('mp:sid', this.sid);
9946
+ this.ventana = this.windowRef.open(this.url, '_blank');
9947
+ // popup bloqueado fallback a navegación en misma pestaña
9948
+ if (!this.ventana || this.ventana.closed) {
9949
+ this.windowRef.location.href = this.url;
9950
+ return;
9951
+ }
9952
+ // polling de último recurso (hasta 10 minutos)
9953
+ this.pollStartedAt = Date.now();
9954
+ if (this.pollTimer)
9955
+ clearInterval(this.pollTimer);
9956
+ this.pollTimer = setInterval(() => {
9957
+ if (Date.now() - this.pollStartedAt > 10 * 60 * 1000) {
9958
+ clearInterval(this.pollTimer);
9959
+ this.pollTimer = null;
9960
+ this.phase = 'idle';
9961
+ this.processError('Tiempo de espera agotado al procesar el pago.');
9600
9962
  return;
9601
9963
  }
9602
- this.ventana?.close();
9603
- this.processError('');
9964
+ this.checkLocalStorageOnce();
9965
+ }, 1000);
9966
+ };
9967
+ onWindowMessage = (event) => {
9968
+ const data = event?.data;
9969
+ this.onMpMessage(data);
9970
+ };
9971
+ onStorage = (e) => {
9972
+ if (!e.key || !this.sid)
9604
9973
  return;
9974
+ if (e.key === `mp:state:${this.sid}` && e.newValue) {
9975
+ const state = e.newValue;
9976
+ this.finishWithState(state);
9605
9977
  }
9606
- setTimeout(() => {
9607
- this.callState();
9608
- }, 5000);
9609
9978
  };
9610
- processError = (err) => {
9611
- this._toastService.show(err != '' ? err : 'payment-error');
9612
- // console.log("ERROR ENVIO BACK ", err);
9979
+ onMpMessage = (data) => {
9980
+ if (!data || data.type !== 'mp:state')
9981
+ return;
9982
+ if (data.sid !== this.sid)
9983
+ return;
9984
+ this.finishWithState(data.state);
9613
9985
  };
9986
+ checkLocalStorageOnce() {
9987
+ if (!this.sid)
9988
+ return;
9989
+ const state = localStorage.getItem(`mp:state:${this.sid}`);
9990
+ if (state)
9991
+ this.finishWithState(state);
9992
+ }
9993
+ /** Cierra el flujo de pago con el estado final y notifica al padre. */
9994
+ finishWithState(state) {
9995
+ if (this.finished)
9996
+ return;
9997
+ this.finished = true;
9998
+ if (this.pollTimer)
9999
+ clearInterval(this.pollTimer);
10000
+ this.pollTimer = null;
10001
+ localStorage.removeItem(`mp:state:${this.sid}`);
10002
+ localStorage.removeItem('mp:sid');
10003
+ localStorage.removeItem('state');
10004
+ try {
10005
+ this.ventana && !this.ventana.closed && this.ventana.close();
10006
+ }
10007
+ catch { }
10008
+ this.ventana = null;
10009
+ if (state === 'success' || state === 'pending') {
10010
+ this.phase = 'finalizing';
10011
+ this.ready.emit(true);
10012
+ }
10013
+ else if (state === 'failure' || state === 'cancel') {
10014
+ this.phase = 'idle';
10015
+ this._toastService.show(state === 'cancel' ? 'Se canceló el pago con Mercado Pago' : 'payment-error');
10016
+ }
10017
+ else {
10018
+ this.phase = 'idle';
10019
+ this._toastService.show('payment-error');
10020
+ }
10021
+ }
10022
+ genSid() {
10023
+ return `mp_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
10024
+ }
10025
+ processError = (msg) => {
10026
+ this._toastService.show(msg || 'payment-error');
10027
+ };
10028
+ /** Limpia posibles residuos de estado en storages. */
9614
10029
  clearStorageState = () => {
9615
- sessionStorage.removeItem('state');
9616
- this.localStorage?.removeItem('state');
10030
+ if (!isPlatformBrowser(this.platformId))
10031
+ return;
10032
+ localStorage.removeItem('state');
10033
+ const sid = localStorage.getItem('mp:sid');
10034
+ if (sid)
10035
+ localStorage.removeItem(`mp:state:${sid}`);
10036
+ };
10037
+ /** Obtiene la preferencia e inicializa `url` (init_point). */
10038
+ getPreference = () => {
10039
+ this._paymentService.getPreference(this.allData).then((res) => {
10040
+ this.preference = res;
10041
+ this.url = this.preference?.init_point;
10042
+ this.renderMP(this.preference);
10043
+ }, () => this.setError('operation-error'));
9617
10044
  };
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
10045
  setError = (message) => {
9624
10046
  //this.error = message;
9625
10047
  };
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
- };
10048
+ renderMP = (_pref) => { };
9638
10049
  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" }] });
10050
+ 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
10051
  }
9641
10052
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MpRedirectEcComponent, decorators: [{
9642
10053
  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: [{
10054
+ 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>" }]
10055
+ }], propDecorators: { method: [{
9645
10056
  type: Input
9646
10057
  }], total_amount: [{
9647
10058
  type: Input
@@ -11761,5 +12172,5 @@ const directives = [
11761
12172
  * Generated bundle index. Do not edit.
11762
12173
  */
11763
12174
 
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 };
12175
+ 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
12176
  //# sourceMappingURL=ng-easycommerce-v18.mjs.map