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.
- package/README.md +18 -0
- 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 -106
- 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';
|
|
@@ -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
|
-
|
|
8557
|
-
|
|
8558
|
-
|
|
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
|
-
|
|
9551
|
-
|
|
9552
|
-
|
|
9553
|
-
|
|
9554
|
-
|
|
9555
|
-
|
|
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.
|
|
9558
|
-
|
|
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
|
-
|
|
9566
|
-
|
|
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.
|
|
9570
|
-
|
|
9571
|
-
this.
|
|
9572
|
-
this.
|
|
9573
|
-
|
|
9574
|
-
|
|
9575
|
-
|
|
9576
|
-
|
|
9577
|
-
this.
|
|
9578
|
-
|
|
9579
|
-
|
|
9580
|
-
|
|
9581
|
-
|
|
9582
|
-
|
|
9583
|
-
|
|
9584
|
-
|
|
9585
|
-
|
|
9586
|
-
|
|
9587
|
-
|
|
9588
|
-
this.
|
|
9589
|
-
this.
|
|
9590
|
-
|
|
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.
|
|
9603
|
-
|
|
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
|
-
|
|
9611
|
-
|
|
9612
|
-
|
|
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
|
-
|
|
9616
|
-
|
|
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 = (
|
|
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\
|
|
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\
|
|
9644
|
-
}],
|
|
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
|