ng-easycommerce-v18 0.3.18-beta.1 → 0.3.18-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.
@@ -2,10 +2,10 @@ import * as i0 from '@angular/core';
2
2
  import { InjectionToken, makeEnvironmentProviders, PLATFORM_ID, Injectable, Inject, APP_INITIALIZER, 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$1 from '@angular/common';
4
4
  import { isPlatformBrowser, DOCUMENT, AsyncPipe, CommonModule, TitleCasePipe, JsonPipe, UpperCasePipe, Location } from '@angular/common';
5
- import { BehaviorSubject, of, take, shareReplay, map, catchError as catchError$1, filter, ReplaySubject, firstValueFrom, concatMap, throwError, switchMap, combineLatest } from 'rxjs';
5
+ import { BehaviorSubject, of, take, shareReplay as shareReplay$1, map, catchError as catchError$1, filter, ReplaySubject, firstValueFrom, concatMap, throwError, switchMap, combineLatest } from 'rxjs';
6
6
  import * as i1 from '@angular/common/http';
7
7
  import { HttpClient, HttpHeaders } from '@angular/common/http';
8
- import { tap, catchError, filter as filter$1, skipWhile } from 'rxjs/operators';
8
+ import { tap, shareReplay, catchError, filter as filter$1, skipWhile, take as take$1, switchMap as switchMap$1 } from 'rxjs/operators';
9
9
  import * as i1$2 from '@ngx-translate/core';
10
10
  import { TranslateService, TranslateModule } from '@ngx-translate/core';
11
11
  import { CookieService } from 'ngx-cookie-service';
@@ -50,34 +50,71 @@ class RuntimeConfigService {
50
50
  configSubject = new BehaviorSubject(null);
51
51
  config$ = this.configSubject.asObservable();
52
52
  _config = null;
53
+ _loadPromise = null;
54
+ _isLoaded = false;
53
55
  constructor(platformId, http) {
54
56
  this.platformId = platformId;
55
57
  this.http = http;
58
+ // En SSR o browser, intentar cargar inmediatamente desde window si está disponible
59
+ if (typeof window !== 'undefined' && window.__RUNTIME_CONFIG__ && !this._isLoaded) {
60
+ this._config = window.__RUNTIME_CONFIG__;
61
+ this._isLoaded = true;
62
+ this.configSubject.next(this._config);
63
+ }
56
64
  }
57
65
  /**
58
- * Carga la configuración en runtime
66
+ * Inicialización única - llamada por APP_INITIALIZER
67
+ * Garantiza que la configuración se carga solo una vez al inicio
68
+ */
69
+ initialize() {
70
+ if (this._isLoaded && this._config) {
71
+ return Promise.resolve(this._config);
72
+ }
73
+ return new Promise((resolve, reject) => {
74
+ this.loadConfig().subscribe({
75
+ next: (config) => {
76
+ this._isLoaded = true;
77
+ resolve(config);
78
+ },
79
+ error: (error) => {
80
+ reject(error);
81
+ }
82
+ });
83
+ });
84
+ }
85
+ /**
86
+ * Carga la configuración en runtime (optimizada para una sola carga)
59
87
  * - En SSR: Lee desde el objeto window inyectado por el servidor
60
- * - En Browser: Hace petición HTTP a /runtime-config.json
88
+ * - En Browser: Hace petición HTTP a /runtime-config.json (solo si no está en window)
61
89
  */
62
90
  loadConfig() {
63
- // Si ya tenemos la config cargada, la devolvemos
64
- if (this._config) {
91
+ // Si ya tenemos la config cargada, la devolvemos inmediatamente
92
+ if (this._isLoaded && this._config) {
65
93
  return of(this._config);
66
94
  }
95
+ // Si ya hay una carga en progreso, reutilizamos esa petición
96
+ if (this._loadPromise) {
97
+ return this._loadPromise;
98
+ }
67
99
  if (isPlatformBrowser(this.platformId)) {
68
100
  // En el navegador, primero intentamos obtener la config desde window
69
- if (window.__RUNTIME_CONFIG__) {
101
+ if (typeof window !== 'undefined' && window.__RUNTIME_CONFIG__ && !this._isLoaded) {
70
102
  this._config = window.__RUNTIME_CONFIG__;
103
+ this._isLoaded = true;
71
104
  this.configSubject.next(this._config);
72
105
  return of(this._config);
73
106
  }
74
- // Si no está en window, hacemos petición HTTP
75
- return this.http.get('/runtime-config.json').pipe(tap(config => {
107
+ // Si no está en window, hacemos petición HTTP (solo una vez)
108
+ this._loadPromise = this.http.get('/runtime-config.json').pipe(tap(config => {
76
109
  this._config = config;
110
+ this._isLoaded = true;
77
111
  this.configSubject.next(config);
78
112
  // Guardamos en window para siguientes accesos
79
- window.__RUNTIME_CONFIG__ = config;
80
- }), catchError(error => {
113
+ if (typeof window !== 'undefined') {
114
+ window.__RUNTIME_CONFIG__ = config;
115
+ }
116
+ }), shareReplay(1), // Cache la respuesta para múltiples suscripciones
117
+ catchError(error => {
81
118
  console.error('Error loading runtime config:', error);
82
119
  // Fallback config si falla la carga
83
120
  const fallbackConfig = {
@@ -88,14 +125,17 @@ class RuntimeConfigService {
88
125
  channel: 'minorista'
89
126
  };
90
127
  this._config = fallbackConfig;
128
+ this._isLoaded = true;
91
129
  this.configSubject.next(fallbackConfig);
92
130
  return of(fallbackConfig);
93
131
  }));
132
+ return this._loadPromise;
94
133
  }
95
134
  else {
96
135
  // En SSR, leemos desde window que fue inyectado por el servidor
97
- if (typeof window !== 'undefined' && window.__RUNTIME_CONFIG__) {
136
+ if (typeof window !== 'undefined' && window.__RUNTIME_CONFIG__ && !this._isLoaded) {
98
137
  this._config = window.__RUNTIME_CONFIG__;
138
+ this._isLoaded = true;
99
139
  this.configSubject.next(this._config);
100
140
  return of(this._config);
101
141
  }
@@ -109,6 +149,7 @@ class RuntimeConfigService {
109
149
  channel: 'minorista'
110
150
  };
111
151
  this._config = fallbackConfig;
152
+ this._isLoaded = true;
112
153
  this.configSubject.next(fallbackConfig);
113
154
  return of(fallbackConfig);
114
155
  }
@@ -188,23 +229,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
188
229
  }] }, { type: i1.HttpClient }] });
189
230
 
190
231
  /**
191
- * Factory function para APP_INITIALIZER
192
- * Carga la configuración runtime antes de que Angular bootstrap la aplicación
232
+ * Factory function para APP_INITIALIZER (OPTIMIZADA)
233
+ * Carga la configuración runtime UNA SOLA VEZ antes de que Angular bootstrap la aplicación
234
+ * Evita múltiples cargas y mejora el rendimiento
193
235
  */
194
236
  function initializeRuntimeConfig(runtimeConfigService) {
195
237
  return () => {
196
- return new Promise((resolve, reject) => {
197
- runtimeConfigService.loadConfig().subscribe({
198
- next: (config) => {
199
- console.log('🔧 Runtime config loaded:', config);
200
- resolve(config);
201
- },
202
- error: (error) => {
203
- console.error('❌ Failed to load runtime config:', error);
204
- // Aún en caso de error, resolvemos para no bloquear la app
205
- resolve(null);
206
- }
238
+ console.log('🚀 Inicializando Runtime Config...');
239
+ return runtimeConfigService.initialize()
240
+ .then((config) => {
241
+ console.log(' Runtime config inicializado correctamente:', {
242
+ apiUrl: config.apiUrl,
243
+ appEnv: config.appEnv,
244
+ production: config.production
207
245
  });
246
+ return config;
247
+ })
248
+ .catch((error) => {
249
+ console.error('❌ Error al inicializar runtime config:', error);
250
+ // Aún en caso de error, continuamos para no bloquear la app
251
+ return null;
208
252
  });
209
253
  };
210
254
  }
@@ -773,7 +817,7 @@ class OptionsService {
773
817
  */
774
818
  getCategories() {
775
819
  if (this.categoriesSubject.getValue().length === 0) {
776
- this.connection.get(this.taxonsApi()).pipe(shareReplay(1), map((response) => {
820
+ this.connection.get(this.taxonsApi()).pipe(shareReplay$1(1), map((response) => {
777
821
  const categories = this.appendPaths(true, response);
778
822
  this.categoriesSubject.next(categories);
779
823
  return categories;
@@ -791,7 +835,7 @@ class OptionsService {
791
835
  */
792
836
  getSections() {
793
837
  if (this.sectionsSubject.getValue().length === 0) {
794
- this.connection.get(this.sectionsApi()).pipe(shareReplay(1), map((response) => {
838
+ this.connection.get(this.sectionsApi()).pipe(shareReplay$1(1), map((response) => {
795
839
  let sections = response.filter((section) => section.code != 'home');
796
840
  sections = sections.map((section) => this.appendSection(section));
797
841
  this.sectionsSubject.next(sections);
@@ -807,7 +851,7 @@ class OptionsService {
807
851
  */
808
852
  getAttributes(params) {
809
853
  if (this.attributesSubject.getValue().length === 0) {
810
- this.connection.get(this.attributesApi(params)).pipe(shareReplay(1), map((response) => {
854
+ this.connection.get(this.attributesApi(params)).pipe(shareReplay$1(1), map((response) => {
811
855
  const attributes = this.appendPaths(false, (response.attributes[0] || response));
812
856
  this.attributesSubject.next(attributes);
813
857
  return attributes;
@@ -1039,7 +1083,7 @@ class ParametersService {
1039
1083
  */
1040
1084
  getParameters() {
1041
1085
  if (this.parametersSubject.getValue() === null) {
1042
- this.connection.get(this.getAllParametersAPI()).pipe(shareReplay(1), map((response) => {
1086
+ this.connection.get(this.getAllParametersAPI()).pipe(shareReplay$1(1), map((response) => {
1043
1087
  this.parametersSubject.next(response);
1044
1088
  return response;
1045
1089
  }), catchError$1((error) => {
@@ -1103,7 +1147,7 @@ class BlocksRepositoryService {
1103
1147
  */
1104
1148
  getBlocks(section) {
1105
1149
  //if(this.blocksSubject.getValue() != null){
1106
- this.connection.get(this.blocksAPI(section)).pipe(shareReplay(1), map((response) => {
1150
+ this.connection.get(this.blocksAPI(section)).pipe(shareReplay$1(1), map((response) => {
1107
1151
  //console.log(response)
1108
1152
  this.blocksSubject.next(response.items);
1109
1153
  return response;
@@ -2285,7 +2329,7 @@ class ChannelService {
2285
2329
  * @returns Observable con el canal.
2286
2330
  */
2287
2331
  getChannel = () => {
2288
- this.connection.get(this.channelApi()).pipe(shareReplay(1), map((response) => {
2332
+ this.connection.get(this.channelApi()).pipe(shareReplay$1(1), map((response) => {
2289
2333
  this.setChannelInfo(response);
2290
2334
  this.channelSubject.next(response);
2291
2335
  this.channelType = response.type;
@@ -2725,7 +2769,7 @@ class FormService {
2725
2769
  * @returns
2726
2770
  */
2727
2771
  getCountriesData() {
2728
- this.connection.get(this.countriesApi()).pipe(shareReplay(1), map((response) => {
2772
+ this.connection.get(this.countriesApi()).pipe(shareReplay$1(1), map((response) => {
2729
2773
  //console.log(response);
2730
2774
  const data = response._embedded.items;
2731
2775
  this.countriesSubject.next(data);
@@ -4011,7 +4055,7 @@ class PaginationService {
4011
4055
  _connectionService = inject(ConnectionService);
4012
4056
  _filtersService = inject(FiltersService);
4013
4057
  _constants = inject(CoreConstantsService);
4014
- paginationData$ = this._filtersService.filters$.pipe(shareReplay(1), filter(filters => filters && filters.length > 0), switchMap((filters) => {
4058
+ paginationData$ = this._filtersService.filters$.pipe(shareReplay$1(1), filter(filters => filters && filters.length > 0), switchMap((filters) => {
4015
4059
  const url = this.buildUrl(filters);
4016
4060
  return this.getData(url);
4017
4061
  }));
@@ -6342,6 +6386,22 @@ class MenuEcComponent {
6342
6386
  hasVisibleProperty(category) {
6343
6387
  return category.isVisible === true;
6344
6388
  }
6389
+ filterVisibleTree(list) {
6390
+ return (list ?? [])
6391
+ .filter((n) => n?.isVisible === true)
6392
+ .map(n => ({ ...n, children: this.filterVisibleTree(n.children) }));
6393
+ }
6394
+ // Exponé streams ya filtrados
6395
+ categoriesVisible$ = this.categories$.pipe(map((list) => this.filterVisibleTree(list)));
6396
+ sectionsVisible$ = this.sections$.pipe(map((list) => this.filterVisibleTree(list)));
6397
+ attributesVisible$ = this.attributes$.pipe(map((list) => this.filterVisibleTree(list)));
6398
+ // Helpers de conveniencia opcionales
6399
+ getVisibleChildren(node) {
6400
+ return this.filterVisibleTree(node?.children);
6401
+ }
6402
+ hasVisibleChildren(node) {
6403
+ return this.getVisibleChildren(node).length > 0;
6404
+ }
6345
6405
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MenuEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6346
6406
  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 });
6347
6407
  }
@@ -9102,6 +9162,8 @@ class FiltersEcComponent {
9102
9162
  console.error('Filter or selected element is undefined:', { filter, selected });
9103
9163
  return;
9104
9164
  }
9165
+ if (selected.isVisible !== true)
9166
+ return;
9105
9167
  if (typeof filter.setSelected !== 'function') {
9106
9168
  console.error('filter.setSelected is not a function. Filter might not be an instance of the expected class:', filter);
9107
9169
  return;
@@ -9171,13 +9233,36 @@ class FiltersEcComponent {
9171
9233
  }) ?? false;
9172
9234
  }
9173
9235
  /**
9174
- * Verifica si una categoría tiene la propiedad isVisible y está marcada como visible
9175
- * @param category - La categoría a verificar
9176
- * @returns true si la categoría es visible, false en caso contrario
9177
- */
9236
+ * Verifica si una categoría tiene la propiedad isVisible y está marcada como visible
9237
+ * @param category - La categoría a verificar
9238
+ * @returns true si la categoría es visible, false en caso contrario
9239
+ */
9178
9240
  hasVisibleProperty(category) {
9179
9241
  return category.isVisible === true;
9180
9242
  }
9243
+ /** Lista visible (filtra recursivo por isVisible) */
9244
+ getVisibleData(filter) {
9245
+ if (!filter)
9246
+ return [];
9247
+ return this.filterVisibleTree(filter.data);
9248
+ }
9249
+ /** Children visibles de un nodo */
9250
+ getVisibleChildren(node) {
9251
+ return this.filterVisibleTree(node?.children ?? []);
9252
+ }
9253
+ /** Tiene hijos visibles? */
9254
+ hasVisibleChildren(node) {
9255
+ return this.getVisibleChildren(node).length > 0;
9256
+ }
9257
+ /** Utilidad recursiva */
9258
+ filterVisibleTree(list = []) {
9259
+ return (list ?? [])
9260
+ .filter(n => n.isVisible === true)
9261
+ .map(n => ({
9262
+ ...n,
9263
+ children: this.filterVisibleTree(n.children ?? [])
9264
+ }));
9265
+ }
9181
9266
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FiltersEcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9182
9267
  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: [""] });
9183
9268
  }
@@ -12246,6 +12331,44 @@ const authInterceptor = (req, next) => {
12246
12331
  return next(req);
12247
12332
  };
12248
12333
 
12334
+ /**
12335
+ * Interceptor que garantiza que las peticiones HTTP no se hagan hasta que
12336
+ * el runtime config esté completamente cargado
12337
+ * Evita que se hagan peticiones con URLs incorrectas
12338
+ */
12339
+ const runtimeConfigInterceptor = (req, next) => {
12340
+ const runtimeConfigService = inject(RuntimeConfigService);
12341
+ // Si la petición es para obtener el runtime config, la dejamos pasar inmediatamente
12342
+ if (req.url.includes('/runtime-config.json')) {
12343
+ return next(req);
12344
+ }
12345
+ // Si la petición es para assets estáticos, la dejamos pasar
12346
+ if (req.url.includes('/assets/') || req.url.includes('.json') || req.url.includes('.css') || req.url.includes('.js')) {
12347
+ return next(req);
12348
+ }
12349
+ // Para las demás peticiones, esperamos a que el config esté listo
12350
+ return runtimeConfigService.config$.pipe(filter$1(config => config !== null), // Esperamos hasta que haya config
12351
+ take$1(1), // Solo tomamos el primer valor válido
12352
+ switchMap$1(config => {
12353
+ // Si la URL ya es completa (empieza con http), la dejamos como está
12354
+ if (req.url.startsWith('http')) {
12355
+ return next(req);
12356
+ }
12357
+ // Si es una URL relativa que debería ir al API, la completamos
12358
+ if (req.url.startsWith('/api/') || req.url.startsWith('api/')) {
12359
+ const apiUrl = config.apiUrl;
12360
+ const cleanUrl = req.url.startsWith('/') ? req.url.substring(1) : req.url;
12361
+ const fullUrl = `${apiUrl}${cleanUrl}`;
12362
+ const modifiedReq = req.clone({
12363
+ url: fullUrl
12364
+ });
12365
+ return next(modifiedReq);
12366
+ }
12367
+ // Para otras URLs, las dejamos pasar sin modificar
12368
+ return next(req);
12369
+ }));
12370
+ };
12371
+
12249
12372
  class ProductStockDirective {
12250
12373
  templateRef;
12251
12374
  viewContainer;
@@ -12447,5 +12570,5 @@ const directives = [
12447
12570
  * Generated bundle index. Do not edit.
12448
12571
  */
12449
12572
 
12450
- export { AccountEcComponent, AddressingService, AnalyticsService, AuthEcComponent, AuthService, AuthStorageService, BaseApiService, 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, RuntimeConfigService, SectionContainerEcComponent, ShareEcComponent, ShipmentService, SidebarEcComponent, StoresEcComponent, SuccessEcComponent, TestService, ToastService, VariantsEcComponent, authGuard, authInterceptor, directives, initializeRuntimeConfig, provideEnvironment, provideRuntimeConfig };
12573
+ export { AccountEcComponent, AddressingService, AnalyticsService, AuthEcComponent, AuthService, AuthStorageService, BaseApiService, 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, RuntimeConfigService, SectionContainerEcComponent, ShareEcComponent, ShipmentService, SidebarEcComponent, StoresEcComponent, SuccessEcComponent, TestService, ToastService, VariantsEcComponent, authGuard, authInterceptor, directives, initializeRuntimeConfig, provideEnvironment, provideRuntimeConfig, runtimeConfigInterceptor };
12451
12574
  //# sourceMappingURL=ng-easycommerce-v18.mjs.map