ng-easycommerce-v18 0.3.17-beta.2 → 0.3.17-beta.3

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.
@@ -1,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, makeEnvironmentProviders, inject, Injectable, PLATFORM_ID, RendererFactory2, afterNextRender, signal, EnvironmentInjector, runInInjectionContext, Component, ChangeDetectorRef, HostListener, CUSTOM_ELEMENTS_SCHEMA, Input, Pipe, Injector, EventEmitter, Output, forwardRef, afterRender, ViewChild, Inject, computed, Renderer2, ChangeDetectionStrategy, Directive } from '@angular/core';
2
+ import { InjectionToken, makeEnvironmentProviders, inject, PLATFORM_ID, Injectable, Inject, RendererFactory2, afterNextRender, signal, EnvironmentInjector, runInInjectionContext, Component, ChangeDetectorRef, HostListener, CUSTOM_ELEMENTS_SCHEMA, Input, Pipe, Injector, EventEmitter, Output, forwardRef, afterRender, ViewChild, computed, Renderer2, ChangeDetectionStrategy, Directive } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
- import { DOCUMENT, isPlatformBrowser, AsyncPipe, CommonModule, TitleCasePipe, JsonPipe, UpperCasePipe, Location } from '@angular/common';
4
+ import { isPlatformServer, DOCUMENT, isPlatformBrowser, AsyncPipe, CommonModule, TitleCasePipe, JsonPipe, UpperCasePipe, Location } from '@angular/common';
5
5
  import { take, BehaviorSubject, shareReplay, map, catchError, of, filter, ReplaySubject, firstValueFrom, concatMap, throwError, switchMap, combineLatest } from 'rxjs';
6
6
  import { HttpClient, HttpHeaders } from '@angular/common/http';
7
7
  import * as i1$1 from '@ngx-translate/core';
@@ -44,89 +44,82 @@ const provideEnvironment = (environment) => {
44
44
  };
45
45
 
46
46
  /**
47
- * Servicio que provee de datos que estan relacionado con las peticiones a la API
48
- * @export
49
- * @class ApiConstantsService
47
+ * Servicio que provee de datos relacionados con las peticiones a la API
50
48
  */
51
49
  class ApiConstantsService {
50
+ ssrApiUrl;
52
51
  _localStorage = inject(LocalStorageService);
53
52
  _translate = inject(TranslateService);
54
- /**
55
- * Contiene los datos provisto por el frontend en el archivo environment.ts
56
- */
57
53
  environment = inject(ENVIRONMENT_TOKEN);
54
+ platformId = inject(PLATFORM_ID);
55
+ _channel;
56
+ LOCALE;
57
+ SHOP_API_URL = 'shop-api/';
58
+ CMS_URL = 'cms/';
59
+ constructor(ssrApiUrl) {
60
+ this.ssrApiUrl = ssrApiUrl;
61
+ this._channel = this.environment.channel;
62
+ this.LOCALE = this.environment.locale;
63
+ }
58
64
  /**
59
65
  * Canal actual del frontend
60
66
  */
61
67
  get CHANNEL() {
62
- // Verificar si estamos en el navegador (no en SSR)
63
68
  if (typeof window !== 'undefined') {
64
- // Primero intenta leer de window.__env (configurado por Docker)
65
69
  const windowEnv = window.__env;
66
- if (windowEnv?.channel) {
70
+ if (windowEnv?.channel)
67
71
  return windowEnv.channel;
68
- }
69
72
  }
70
- // Fallback al environment
71
73
  return this._channel;
72
74
  }
73
75
  set CHANNEL(value) {
74
76
  this._channel = value;
75
77
  }
76
- _channel;
77
- /**
78
- * Locale actual del frontend
79
- */
80
- LOCALE;
81
- /**
82
- * URL para las peticiones a shop-api
83
- */
84
- SHOP_API_URL = 'shop-api/';
85
- /**
86
- * URL para las peticiones a cms
87
- */
88
- CMS_URL = 'cms/';
89
- constructor() {
90
- this._channel = this.environment.channel;
91
- this.LOCALE = this.environment.locale;
92
- }
93
78
  /**
94
79
  * URL del backend para realizar las peticiones
95
80
  */
96
81
  get API_URL() {
97
- // Verificar si estamos en el navegador (no en SSR)
82
+ // Browser runtime-config
98
83
  if (typeof window !== 'undefined') {
99
- // Primero intenta leer de window.__env (configurado por Docker)
100
84
  const windowEnv = window.__env;
101
- if (windowEnv?.apiUrl) {
102
- return windowEnv.apiUrl;
103
- }
85
+ if (windowEnv?.apiBaseUrl)
86
+ return windowEnv.apiBaseUrl;
87
+ }
88
+ // SSR
89
+ if (isPlatformServer(this.platformId)) {
90
+ return this.ssrApiUrl;
104
91
  }
105
- // Fallback al environment (para SSR y como backup)
92
+ // Fallback environment
106
93
  return this.environment.apiUrl ?? '';
107
94
  }
108
95
  /**
109
- * Retorna la url base
110
- * @returns {string}
96
+ * URL base completa para shop-api con channel y locale
97
+ */
98
+ getShopApiBase() {
99
+ const channel = this.CHANNEL || 'undefined';
100
+ const locale = this.LOCALE || 'undefined';
101
+ return `${this.API_URL}/${this.SHOP_API_URL}${channel}/?locale=${locale}`;
102
+ }
103
+ /**
104
+ * Retorna la url base general (sin shop-api)
111
105
  */
112
106
  getUrlBase() {
113
107
  return this.API_URL;
114
108
  }
115
109
  /**
116
110
  * Cambia el canal actual
117
- * @param code
118
- * @returns
119
111
  */
120
- setChannel(code) { this.CHANNEL = code; }
112
+ setChannel(code) {
113
+ this.CHANNEL = code;
114
+ }
121
115
  setLocale(locale) {
122
116
  this._localStorage.setItem(this.LOCALE_KEY, locale);
123
117
  this._translate.use(locale.split('_')[0]);
124
118
  this.LOCALE = locale;
125
119
  }
126
- //Storage key
127
120
  LOCALE_KEY = 'LOCALE';
128
121
  CHANNEL_KEY = 'CHANNEL';
129
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ApiConstantsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
122
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ApiConstantsService, deps: [{ token: 'API_URL' }], target: i0.ɵɵFactoryTarget.Injectable });
130
123
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ApiConstantsService, providedIn: 'root' });
131
124
  }
132
125
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ApiConstantsService, decorators: [{
@@ -134,7 +127,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
134
127
  args: [{
135
128
  providedIn: 'root'
136
129
  }]
137
- }], ctorParameters: () => [] });
130
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
131
+ type: Inject,
132
+ args: ['API_URL']
133
+ }] }] });
138
134
 
139
135
  /**
140
136
  * Servicio que funciona como abstracción para manejar la conexión con la API
@@ -533,6 +529,10 @@ class OptionsService {
533
529
  * Maneja las peticiones a la API
534
530
  */
535
531
  connection = inject(ConnectionService);
532
+ /**
533
+ * Platform ID para verificar si estamos en el navegador
534
+ */
535
+ platformId = inject(PLATFORM_ID);
536
536
  /**
537
537
  * Constantes del core
538
538
  */
@@ -643,7 +643,26 @@ class OptionsService {
643
643
  * @returns
644
644
  */
645
645
  removeAccents(str) {
646
- return str.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
646
+ if (isPlatformBrowser(this.platformId) && typeof String.prototype.normalize === 'function') {
647
+ return str.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
648
+ }
649
+ // Fallback para SSR - remover acentos manualmente
650
+ return str.replace(/[àáâãäå]/g, 'a')
651
+ .replace(/[èéêë]/g, 'e')
652
+ .replace(/[ìíîï]/g, 'i')
653
+ .replace(/[òóôõö]/g, 'o')
654
+ .replace(/[ùúûü]/g, 'u')
655
+ .replace(/[ýÿ]/g, 'y')
656
+ .replace(/[ñ]/g, 'n')
657
+ .replace(/[ç]/g, 'c')
658
+ .replace(/[ÀÁÂÃÄÅ]/g, 'A')
659
+ .replace(/[ÈÉÊË]/g, 'E')
660
+ .replace(/[ÌÍÎÏ]/g, 'I')
661
+ .replace(/[ÒÓÔÕÖ]/g, 'O')
662
+ .replace(/[ÙÚÛÜ]/g, 'U')
663
+ .replace(/[ÝŸ]/g, 'Y')
664
+ .replace(/[Ñ]/g, 'N')
665
+ .replace(/[Ç]/g, 'C');
647
666
  }
648
667
  /**
649
668
  * Realiza un mapeo de los datos para darle un formato mas entendible a la
@@ -1026,7 +1045,9 @@ class FacebookPixelService {
1026
1045
  this.renderer.appendChild(this.document?.body, new_analityc_script);
1027
1046
  this.enabled = true;
1028
1047
  }
1029
- setTimeout(() => this.callEvent('initialize'), 1000);
1048
+ if (isPlatformBrowser(this.platformId)) {
1049
+ setTimeout(() => this.callEvent('initialize'), 1000);
1050
+ }
1030
1051
  }
1031
1052
  /**
1032
1053
  * Ejecuta el evento pasado por parametro.
@@ -1243,7 +1264,9 @@ class GoogleAnalyticsService {
1243
1264
  this.renderer.appendChild(this.document?.head, declaration);
1244
1265
  this.enabled = true;
1245
1266
  }
1246
- setTimeout(() => this.startListeningPageViews(gtm_id), 1000);
1267
+ if (isPlatformBrowser(this.platformId)) {
1268
+ setTimeout(() => this.startListeningPageViews(gtm_id), 1000);
1269
+ }
1247
1270
  }
1248
1271
  /**
1249
1272
  *
@@ -2644,6 +2667,31 @@ class User {
2644
2667
  }
2645
2668
  }
2646
2669
 
2670
+ /**
2671
+ * Función auxiliar para remover acentos de forma segura para SSR
2672
+ */
2673
+ function safeRemoveAccents(str) {
2674
+ if (typeof window !== 'undefined' && typeof String.prototype.normalize === 'function') {
2675
+ return str.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
2676
+ }
2677
+ // Fallback para SSR - remover acentos manualmente
2678
+ return str.replace(/[àáâãäå]/g, 'a')
2679
+ .replace(/[èéêë]/g, 'e')
2680
+ .replace(/[ìíîï]/g, 'i')
2681
+ .replace(/[òóôõö]/g, 'o')
2682
+ .replace(/[ùúûü]/g, 'u')
2683
+ .replace(/[ýÿ]/g, 'y')
2684
+ .replace(/[ñ]/g, 'n')
2685
+ .replace(/[ç]/g, 'c')
2686
+ .replace(/[ÀÁÂÃÄÅ]/g, 'A')
2687
+ .replace(/[ÈÉÊË]/g, 'E')
2688
+ .replace(/[ÌÍÎÏ]/g, 'I')
2689
+ .replace(/[ÒÓÔÕÖ]/g, 'O')
2690
+ .replace(/[ÙÚÛÜ]/g, 'U')
2691
+ .replace(/[ÝŸ]/g, 'Y')
2692
+ .replace(/[Ñ]/g, 'N')
2693
+ .replace(/[Ç]/g, 'C');
2694
+ }
2647
2695
  class Filter {
2648
2696
  data = [];
2649
2697
  multi = false;
@@ -2663,7 +2711,7 @@ class Filter {
2663
2711
  throw new Error("Method not implemented.");
2664
2712
  }
2665
2713
  removeAccents = (str) => {
2666
- return str.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
2714
+ return safeRemoveAccents(str);
2667
2715
  };
2668
2716
  setSelected(element, value) {
2669
2717
  //console.log(element, value);
@@ -6172,7 +6220,6 @@ class HeaderEcComponent extends MenuEcComponent {
6172
6220
  _channelService = inject(ChannelService);
6173
6221
  changeDetector = inject(ChangeDetectorRef);
6174
6222
  appRouter = inject(Router);
6175
- platformId = inject(PLATFORM_ID);
6176
6223
  // Observable del estado de autenticación
6177
6224
  logged$;
6178
6225
  isAuthenticated$ = this.__authService.isAuthenticated();
@@ -6188,6 +6235,7 @@ class HeaderEcComponent extends MenuEcComponent {
6188
6235
  coreConstantsService = inject(CoreConstantsService);
6189
6236
  router = inject(Router);
6190
6237
  cdr = inject(ChangeDetectorRef); // Inyectamos ChangeDetectorRef para forzar la actualización
6238
+ platformId = inject(PLATFORM_ID);
6191
6239
  ngOnInit() {
6192
6240
  this.channel = this.coreConstantsService.getChannel();
6193
6241
  this.onWindowScroll();
@@ -6226,17 +6274,21 @@ class HeaderEcComponent extends MenuEcComponent {
6226
6274
  });
6227
6275
  }
6228
6276
  onWindowScroll() {
6229
- const scrollTop = window.scrollY;
6230
- this.isScrolled = scrollTop > 80;
6277
+ if (isPlatformBrowser(this.platformId)) {
6278
+ const scrollTop = window.scrollY;
6279
+ this.isScrolled = scrollTop > 80;
6280
+ }
6231
6281
  }
6232
6282
  isHomeFunction() {
6233
- const headerElement = document.querySelector('header');
6234
- if (headerElement) {
6235
- if (this.router.url !== '/home') {
6236
- headerElement.classList.add('show-menu');
6237
- }
6238
- else {
6239
- headerElement.classList.remove('show-menu');
6283
+ if (isPlatformBrowser(this.platformId)) {
6284
+ const headerElement = document.querySelector('header');
6285
+ if (headerElement) {
6286
+ if (this.router.url !== '/home') {
6287
+ headerElement.classList.add('show-menu');
6288
+ }
6289
+ else {
6290
+ headerElement.classList.remove('show-menu');
6291
+ }
6240
6292
  }
6241
6293
  }
6242
6294
  }
@@ -6260,26 +6312,30 @@ class HeaderEcComponent extends MenuEcComponent {
6260
6312
  }
6261
6313
  };
6262
6314
  borrarInput(inputId) {
6263
- if (inputId) {
6264
- const input = document.getElementById(inputId);
6265
- if (input) {
6266
- input.value = '';
6267
- }
6268
- }
6269
- else {
6270
- const inputs = ['searchInput1'];
6271
- inputs.forEach((id) => {
6272
- const input = document.getElementById(id);
6315
+ if (isPlatformBrowser(this.platformId)) {
6316
+ if (inputId) {
6317
+ const input = document.getElementById(inputId);
6273
6318
  if (input) {
6274
6319
  input.value = '';
6275
6320
  }
6276
- });
6321
+ }
6322
+ else {
6323
+ const inputs = ['searchInput1'];
6324
+ inputs.forEach((id) => {
6325
+ const input = document.getElementById(id);
6326
+ if (input) {
6327
+ input.value = '';
6328
+ }
6329
+ });
6330
+ }
6277
6331
  }
6278
6332
  this.searchValue = '';
6279
6333
  this.coreConstantsService.searchValue = '';
6280
6334
  this.getCollectionSearch();
6281
6335
  }
6282
6336
  setupMobileMenu() {
6337
+ if (!isPlatformBrowser(this.platformId))
6338
+ return;
6283
6339
  // console.log('setupMobileMenu called');
6284
6340
  const menuMobile = document.querySelector('.menuMobile');
6285
6341
  if (!(menuMobile instanceof HTMLElement))
@@ -6315,6 +6371,8 @@ class HeaderEcComponent extends MenuEcComponent {
6315
6371
  });
6316
6372
  }
6317
6373
  setupSearchInputs() {
6374
+ if (!isPlatformBrowser(this.platformId))
6375
+ return;
6318
6376
  const inputs = ['searchInput1', 'searchInput2'];
6319
6377
  inputs.forEach(id => {
6320
6378
  const input = document.getElementById(id);
@@ -7150,7 +7208,7 @@ class BlockProductsEcComponent extends BlockEcComponent {
7150
7208
  * Permite personalización de las imágenes de las flechas mediante @Input.
7151
7209
  */
7152
7210
  setupSwiperNavigation() {
7153
- if (this.meta?.styles?.carrousel !== false) {
7211
+ if (this.meta?.styles?.carrousel !== false && isPlatformBrowser(this.platformId)) {
7154
7212
  // Usar setTimeout para asegurar que el swiper esté inicializado
7155
7213
  setTimeout(() => {
7156
7214
  this.initializeSwiperWithCustomNavigation();
@@ -7162,6 +7220,8 @@ class BlockProductsEcComponent extends BlockEcComponent {
7162
7220
  * Esta función puede ser movida al componente base para reutilización.
7163
7221
  */
7164
7222
  initializeSwiperWithCustomNavigation() {
7223
+ if (!isPlatformBrowser(this.platformId))
7224
+ return;
7165
7225
  const prevButton = document.getElementById(`${this.meta?.code}-prev`);
7166
7226
  const nextButton = document.getElementById(`${this.meta?.code}-next`);
7167
7227
  const swiperElement = document.getElementById(this.meta?.code);
@@ -7521,7 +7581,9 @@ class MagnizoomEcComponent {
7521
7581
  this.image = this.document.createElement('img');
7522
7582
  this.image.onload = () => {
7523
7583
  this.lensSize = { width: this.image.width / 2, height: this.image.height / 2 };
7524
- setTimeout(() => this.render());
7584
+ if (isPlatformBrowser(this.platformId)) {
7585
+ setTimeout(() => this.render());
7586
+ }
7525
7587
  };
7526
7588
  this.image.src = src;
7527
7589
  }
@@ -10853,9 +10915,11 @@ class RelatedProductsEcComponent extends BlockEcComponent {
10853
10915
  this._relatedProductsSubject.next(relatedProducts);
10854
10916
  res.map((products) => this._analyticsService.callEvent('view_item_list', { products: products.items, item_list_name: products.title || 'Related Products', item_list_id: products.id || 'related-products' }));
10855
10917
  // Inicializar swiper después de que los datos estén disponibles
10856
- setTimeout(() => {
10857
- this.initSwiper();
10858
- }, 100);
10918
+ if (isPlatformBrowser(this.platformId)) {
10919
+ setTimeout(() => {
10920
+ this.initSwiper();
10921
+ }, 100);
10922
+ }
10859
10923
  });
10860
10924
  }
10861
10925
  initSwiper() {