ng-easycommerce-v18 0.3.14-beta.3 → 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.
- package/README.md +18 -0
- package/esm2022/lib/constants/api.constants.service.mjs +1 -7
- package/esm2022/lib/ec-components/abstractions-components/menu-ec.component.mjs +17 -1
- package/esm2022/lib/ec-components/auth-ec/login-form-ec/login-form-ec.component.mjs +5 -1
- package/esm2022/lib/ec-components/auth-ec/register-form-ec/register-form-ec.component.mjs +5 -1
- package/esm2022/lib/ec-components/cart-ec/cart-item-ec/cart-item-ec.component.mjs +6 -2
- package/esm2022/lib/ec-components/checkout-ec/payment-ec/payment-methods/mp-redirect-ec/mp-redirect-ec.component.mjs +141 -75
- package/esm2022/lib/ec-components/filters-ec/filters-ec.component.mjs +30 -5
- package/esm2022/lib/ec-components/header-ec/header-ec.component.mjs +23 -3
- package/esm2022/lib/ec-components/product-ec/product-ec.component.mjs +95 -5
- package/esm2022/lib/ec-components/widgets-ec/index.mjs +2 -1
- package/esm2022/lib/ec-components/widgets-ec/redsys-catch-ec/redsys-catch-ec.component.mjs +193 -0
- package/esm2022/lib/interfaces/filter.mjs +1 -1
- package/esm2022/lib/interfaces/options.mjs +1 -1
- package/fesm2022/ng-easycommerce-v18.mjs +517 -112
- package/fesm2022/ng-easycommerce-v18.mjs.map +1 -1
- package/lib/ec-components/abstractions-components/menu-ec.component.d.ts +12 -0
- package/lib/ec-components/auth-ec/login-form-ec/login-form-ec.component.d.ts +2 -0
- package/lib/ec-components/auth-ec/register-form-ec/register-form-ec.component.d.ts +2 -0
- package/lib/ec-components/cart-ec/cart-item-ec/cart-item-ec.component.d.ts +5 -0
- package/lib/ec-components/checkout-ec/payment-ec/payment-methods/mp-redirect-ec/mp-redirect-ec.component.d.ts +38 -16
- package/lib/ec-components/filters-ec/filters-ec.component.d.ts +12 -4
- package/lib/ec-components/header-ec/header-ec.component.d.ts +5 -1
- package/lib/ec-components/product-ec/product-ec.component.d.ts +10 -1
- package/lib/ec-components/widgets-ec/index.d.ts +1 -0
- package/lib/ec-components/widgets-ec/redsys-catch-ec/redsys-catch-ec.component.d.ts +47 -0
- package/lib/interfaces/filter.d.ts +1 -0
- package/lib/interfaces/options.d.ts +2 -0
- 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
|
|
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';
|
|
@@ -87,14 +87,8 @@ class ApiConstantsService {
|
|
|
87
87
|
}
|
|
88
88
|
// 2️⃣ Runtime (SSR / Node)
|
|
89
89
|
if (isPlatformServer(this.platformId)) {
|
|
90
|
-
// Prioriza la inyección del token API_URL
|
|
91
90
|
if (this.ssrApiUrl)
|
|
92
91
|
return this.ssrApiUrl;
|
|
93
|
-
// Si no se inyectó, toma del entorno
|
|
94
|
-
if (isPlatformServer(this.platformId)) {
|
|
95
|
-
if (this.ssrApiUrl)
|
|
96
|
-
return this.ssrApiUrl;
|
|
97
|
-
}
|
|
98
92
|
}
|
|
99
93
|
// 3️⃣ Fallback (environment de Angular)
|
|
100
94
|
return this.environment.apiUrl ?? '';
|
|
@@ -6063,6 +6057,22 @@ class MenuEcComponent {
|
|
|
6063
6057
|
hasVisibleProperty(category) {
|
|
6064
6058
|
return category.isVisible === true;
|
|
6065
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
|
+
}
|
|
6066
6076
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MenuEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6067
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 });
|
|
6068
6078
|
}
|
|
@@ -6209,6 +6219,11 @@ class HeaderEcComponent extends MenuEcComponent {
|
|
|
6209
6219
|
hidePrices = false;
|
|
6210
6220
|
__authService = inject(AuthService);
|
|
6211
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$;
|
|
6212
6227
|
isAuthenticated$ = this.__authService.isAuthenticated();
|
|
6213
6228
|
constructor() {
|
|
6214
6229
|
super();
|
|
@@ -6222,11 +6237,26 @@ class HeaderEcComponent extends MenuEcComponent {
|
|
|
6222
6237
|
coreConstantsService = inject(CoreConstantsService);
|
|
6223
6238
|
router = inject(Router);
|
|
6224
6239
|
cdr = inject(ChangeDetectorRef); // Inyectamos ChangeDetectorRef para forzar la actualización
|
|
6225
|
-
platformId = inject(PLATFORM_ID);
|
|
6226
6240
|
ngOnInit() {
|
|
6227
6241
|
this.channel = this.coreConstantsService.getChannel();
|
|
6228
6242
|
this.onWindowScroll();
|
|
6229
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
|
+
}
|
|
6230
6260
|
}
|
|
6231
6261
|
ngAfterViewInit() {
|
|
6232
6262
|
this.setupMobileMenu(); // Inicializamos el menú móvil
|
|
@@ -6940,6 +6970,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
6940
6970
|
class ProductEcComponent {
|
|
6941
6971
|
injector = inject(Injector);
|
|
6942
6972
|
routerService = inject(Router);
|
|
6973
|
+
_cartService = inject(CartService);
|
|
6974
|
+
_toastService = inject(ToastService);
|
|
6975
|
+
isAddingToCart = signal(false);
|
|
6976
|
+
quantity = signal(1);
|
|
6943
6977
|
/**
|
|
6944
6978
|
* Navega al detalle del producto y sube al inicio de la página
|
|
6945
6979
|
* @param productId ID del producto
|
|
@@ -7012,12 +7046,97 @@ class ProductEcComponent {
|
|
|
7012
7046
|
const discount = ((originalPrice - salePrice) / originalPrice) * 100;
|
|
7013
7047
|
return Math.round(discount);
|
|
7014
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
|
+
}
|
|
7015
7134
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProductEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7016
|
-
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 }] });
|
|
7017
7136
|
}
|
|
7018
7137
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProductEcComponent, decorators: [{
|
|
7019
7138
|
type: Component,
|
|
7020
|
-
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>" }]
|
|
7021
7140
|
}], ctorParameters: () => [], propDecorators: { product: [{
|
|
7022
7141
|
type: Input,
|
|
7023
7142
|
args: [{
|
|
@@ -7595,6 +7714,212 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
7595
7714
|
args: ['mainCanvas', { static: true }]
|
|
7596
7715
|
}] } });
|
|
7597
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
|
+
|
|
7598
7923
|
// export * from './rating-ec/rating-ec.component';
|
|
7599
7924
|
|
|
7600
7925
|
class BlockFormContactEcComponent extends BlockEcComponent {
|
|
@@ -7870,6 +8195,7 @@ class LoginFormEcComponent {
|
|
|
7870
8195
|
_formBuilder = inject(FormBuilder);
|
|
7871
8196
|
_toastService = inject(ToastService);
|
|
7872
8197
|
_router = inject(Router);
|
|
8198
|
+
showPassword = false;
|
|
7873
8199
|
/**
|
|
7874
8200
|
* Parametro para indicar si tras loguear
|
|
7875
8201
|
* debe redireccionar o no.
|
|
@@ -7958,6 +8284,9 @@ class LoginFormEcComponent {
|
|
|
7958
8284
|
? resolverFunction()
|
|
7959
8285
|
: this._router.navigateByUrl(this.redirectTo);
|
|
7960
8286
|
}
|
|
8287
|
+
togglePassword() {
|
|
8288
|
+
this.showPassword = !this.showPassword;
|
|
8289
|
+
}
|
|
7961
8290
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LoginFormEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7962
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"] }] });
|
|
7963
8292
|
}
|
|
@@ -8057,6 +8386,7 @@ class RegisterFormEcComponent {
|
|
|
8057
8386
|
_analyticsService = inject(AnalyticsService);
|
|
8058
8387
|
_formBuilder = inject(FormBuilder);
|
|
8059
8388
|
channelConfigService = inject(ChannelService);
|
|
8389
|
+
showPassword = false;
|
|
8060
8390
|
/**
|
|
8061
8391
|
* Indica si debe redireccionar o se queda en la misma pantalla
|
|
8062
8392
|
*/
|
|
@@ -8172,6 +8502,9 @@ class RegisterFormEcComponent {
|
|
|
8172
8502
|
this.register_loading = false;
|
|
8173
8503
|
}
|
|
8174
8504
|
}
|
|
8505
|
+
togglePassword() {
|
|
8506
|
+
this.showPassword = !this.showPassword;
|
|
8507
|
+
}
|
|
8175
8508
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RegisterFormEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8176
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" }] });
|
|
8177
8510
|
}
|
|
@@ -8326,29 +8659,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
8326
8659
|
type: Output
|
|
8327
8660
|
}] } });
|
|
8328
8661
|
|
|
8329
|
-
class ComponentHelper {
|
|
8330
|
-
constructor() {
|
|
8331
|
-
this.ecOnConstruct();
|
|
8332
|
-
}
|
|
8333
|
-
ecOnInit = (params = {}) => {
|
|
8334
|
-
};
|
|
8335
|
-
ecOnConstruct = (params = {}) => {
|
|
8336
|
-
};
|
|
8337
|
-
hasParams = (params, searched) => {
|
|
8338
|
-
if (!params || !searched)
|
|
8339
|
-
return false;
|
|
8340
|
-
const q = searched.trim().toLowerCase();
|
|
8341
|
-
return params.some(p => {
|
|
8342
|
-
const code = p?.['code']?.toString().toLowerCase() ?? '';
|
|
8343
|
-
// Primero chequeo exacto, y si no, parcial
|
|
8344
|
-
return code === q || code.includes(q);
|
|
8345
|
-
});
|
|
8346
|
-
};
|
|
8347
|
-
navigateOnRouter(router, url) {
|
|
8348
|
-
router.navigateByUrl(`/${url}`);
|
|
8349
|
-
}
|
|
8350
|
-
}
|
|
8351
|
-
|
|
8352
8662
|
class PasswordResetEcComponent extends ComponentHelper {
|
|
8353
8663
|
authService;
|
|
8354
8664
|
toastr;
|
|
@@ -8490,6 +8800,8 @@ class FiltersEcComponent {
|
|
|
8490
8800
|
console.error('Filter or selected element is undefined:', { filter, selected });
|
|
8491
8801
|
return;
|
|
8492
8802
|
}
|
|
8803
|
+
if (selected.isVisible !== true)
|
|
8804
|
+
return;
|
|
8493
8805
|
if (typeof filter.setSelected !== 'function') {
|
|
8494
8806
|
console.error('filter.setSelected is not a function. Filter might not be an instance of the expected class:', filter);
|
|
8495
8807
|
return;
|
|
@@ -8559,13 +8871,36 @@ class FiltersEcComponent {
|
|
|
8559
8871
|
}) ?? false;
|
|
8560
8872
|
}
|
|
8561
8873
|
/**
|
|
8562
|
-
|
|
8563
|
-
|
|
8564
|
-
|
|
8565
|
-
|
|
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
|
+
*/
|
|
8566
8878
|
hasVisibleProperty(category) {
|
|
8567
8879
|
return category.isVisible === true;
|
|
8568
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
|
+
}
|
|
8569
8904
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FiltersEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8570
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: [""] });
|
|
8571
8906
|
}
|
|
@@ -8949,6 +9284,7 @@ class CartItemEcComponent {
|
|
|
8949
9284
|
_cartService = inject(CartService);
|
|
8950
9285
|
_toastService = inject(ToastService);
|
|
8951
9286
|
_constants = inject(CoreConstantsService);
|
|
9287
|
+
parametersService = inject(ParametersService);
|
|
8952
9288
|
mediaUrl = this._constants.mediaUrl();
|
|
8953
9289
|
quantity = 0;
|
|
8954
9290
|
variantsToShow = ['TALLA', 'COLOR'];
|
|
@@ -9035,6 +9371,9 @@ class CartItemEcComponent {
|
|
|
9035
9371
|
}
|
|
9036
9372
|
return false; // Solo se ejecuta si no se cumple la condición
|
|
9037
9373
|
}
|
|
9374
|
+
// PARAMETROS
|
|
9375
|
+
parameters$ = this.parametersService.getParameters();
|
|
9376
|
+
hasParams = this.parametersService.hasParams;
|
|
9038
9377
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CartItemEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9039
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"] }] });
|
|
9040
9379
|
}
|
|
@@ -9546,108 +9885,174 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
9546
9885
|
class MpRedirectEcComponent {
|
|
9547
9886
|
_paymentService = inject(PaymentService);
|
|
9548
9887
|
_toastService = inject(ToastService);
|
|
9888
|
+
platformId = inject(PLATFORM_ID);
|
|
9889
|
+
finished = false;
|
|
9549
9890
|
method = null;
|
|
9550
9891
|
total_amount = 0;
|
|
9551
9892
|
allData;
|
|
9552
9893
|
ready = new EventEmitter();
|
|
9553
9894
|
preference;
|
|
9554
|
-
loading = false;
|
|
9555
9895
|
url;
|
|
9556
|
-
|
|
9557
|
-
|
|
9558
|
-
|
|
9559
|
-
|
|
9560
|
-
|
|
9561
|
-
|
|
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() {
|
|
9562
9908
|
if (isPlatformBrowser(this.platformId)) {
|
|
9563
|
-
this.
|
|
9564
|
-
|
|
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);
|
|
9565
9916
|
}
|
|
9566
|
-
}
|
|
9567
|
-
ngOnInit() {
|
|
9568
9917
|
this.getPreference();
|
|
9569
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". */
|
|
9570
9929
|
clickClose = () => {
|
|
9571
|
-
|
|
9572
|
-
|
|
9930
|
+
if (this.finished)
|
|
9931
|
+
return;
|
|
9932
|
+
this.finishWithState('cancel');
|
|
9573
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
|
+
*/
|
|
9574
9939
|
iniciar = () => {
|
|
9575
|
-
this.
|
|
9576
|
-
|
|
9577
|
-
this.
|
|
9578
|
-
this.
|
|
9579
|
-
|
|
9580
|
-
|
|
9581
|
-
|
|
9582
|
-
|
|
9583
|
-
this.
|
|
9584
|
-
|
|
9585
|
-
|
|
9586
|
-
|
|
9587
|
-
|
|
9588
|
-
|
|
9589
|
-
|
|
9590
|
-
|
|
9591
|
-
|
|
9592
|
-
|
|
9593
|
-
|
|
9594
|
-
this.
|
|
9595
|
-
this.
|
|
9596
|
-
|
|
9597
|
-
}
|
|
9598
|
-
if (state == 'failure') {
|
|
9599
|
-
this.ventana?.close();
|
|
9600
|
-
this.processError('');
|
|
9601
|
-
return;
|
|
9602
|
-
}
|
|
9603
|
-
if (state == 'cancel') {
|
|
9604
|
-
this.ventana?.close();
|
|
9605
|
-
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.');
|
|
9606
9962
|
return;
|
|
9607
9963
|
}
|
|
9608
|
-
this.
|
|
9609
|
-
|
|
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)
|
|
9610
9973
|
return;
|
|
9974
|
+
if (e.key === `mp:state:${this.sid}` && e.newValue) {
|
|
9975
|
+
const state = e.newValue;
|
|
9976
|
+
this.finishWithState(state);
|
|
9611
9977
|
}
|
|
9612
|
-
setTimeout(() => {
|
|
9613
|
-
this.callState();
|
|
9614
|
-
}, 5000);
|
|
9615
9978
|
};
|
|
9616
|
-
|
|
9617
|
-
|
|
9618
|
-
|
|
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);
|
|
9619
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. */
|
|
9620
10029
|
clearStorageState = () => {
|
|
9621
|
-
|
|
9622
|
-
|
|
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'));
|
|
9623
10044
|
};
|
|
9624
|
-
getPreference = () => this._paymentService.getPreference(this.allData).then(res => {
|
|
9625
|
-
this.preference = res;
|
|
9626
|
-
this.url = this.preference.init_point;
|
|
9627
|
-
this.renderMP(this.preference);
|
|
9628
|
-
}, err => this.setError('operation-error'));
|
|
9629
10045
|
setError = (message) => {
|
|
9630
10046
|
//this.error = message;
|
|
9631
10047
|
};
|
|
9632
|
-
renderMP = (
|
|
9633
|
-
this.window?.addEventListener("message", (event) => {
|
|
9634
|
-
if (event.origin !== 'https://www.mercadopago.com.ar' || !event.data.type) {
|
|
9635
|
-
return;
|
|
9636
|
-
}
|
|
9637
|
-
let dataType = event.data.type;
|
|
9638
|
-
if (dataType === 'submit') {
|
|
9639
|
-
const paymentData = event.data.value;
|
|
9640
|
-
return;
|
|
9641
|
-
}
|
|
9642
|
-
});
|
|
9643
|
-
};
|
|
10048
|
+
renderMP = (_pref) => { };
|
|
9644
10049
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MpRedirectEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9645
|
-
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\
|
|
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" }] });
|
|
9646
10051
|
}
|
|
9647
10052
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MpRedirectEcComponent, decorators: [{
|
|
9648
10053
|
type: Component,
|
|
9649
|
-
args: [{ selector: 'app-mp-redirect-ec', standalone: true, imports: [LoadingFullEcComponent], template: "<div class=\"text-center\">\r\n\t@if(url){\r\n\
|
|
9650
|
-
}],
|
|
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: [{
|
|
9651
10056
|
type: Input
|
|
9652
10057
|
}], total_amount: [{
|
|
9653
10058
|
type: Input
|
|
@@ -11767,5 +12172,5 @@ const directives = [
|
|
|
11767
12172
|
* Generated bundle index. Do not edit.
|
|
11768
12173
|
*/
|
|
11769
12174
|
|
|
11770
|
-
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 };
|
|
11771
12176
|
//# sourceMappingURL=ng-easycommerce-v18.mjs.map
|