valtech-components 2.0.498 → 2.0.500

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,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { EventEmitter, Component, Input, Output, Injectable, HostListener, inject, Pipe, ChangeDetectionStrategy, ViewChild, signal, computed, makeEnvironmentProviders, APP_INITIALIZER, ChangeDetectorRef, ElementRef, InjectionToken, Inject, PLATFORM_ID, Optional, runInInjectionContext, effect } from '@angular/core';
2
+ import { EventEmitter, Component, Input, Output, Injectable, HostListener, inject, Pipe, ChangeDetectionStrategy, ViewChild, signal, computed, makeEnvironmentProviders, APP_INITIALIZER, ChangeDetectorRef, ElementRef, PLATFORM_ID, Inject, ErrorHandler, DestroyRef, InjectionToken, Optional, runInInjectionContext, effect } from '@angular/core';
3
3
  import * as i2$1 from '@ionic/angular/standalone';
4
4
  import { IonAvatar, IonCard, IonIcon, IonButton, IonSpinner, IonText, IonModal, IonHeader, IonToolbar, IonContent, IonButtons, IonTitle, IonProgressBar, IonSkeletonText, IonFab, IonFabButton, IonFabList, IonLabel, IonCardContent, IonCardHeader, IonCardTitle, IonCardSubtitle, IonCheckbox, IonTextarea, IonDatetime, IonDatetimeButton, IonInput, IonSelect, IonSelectOption, IonRadioGroup, IonRadio, IonRange, IonSearchbar, IonSegment, IonSegmentButton, IonToggle, IonAccordion, IonAccordionGroup, IonItem, IonTabBar, IonTabButton, IonBadge, IonBreadcrumb, IonBreadcrumbs, IonChip, IonPopover, IonList, IonNote, ToastController as ToastController$1, IonCol, IonRow, IonMenuButton, IonFooter, IonListHeader, IonInfiniteScroll, IonInfiniteScrollContent, IonGrid, MenuController, IonMenu, IonMenuToggle, AlertController } from '@ionic/angular/standalone';
5
5
  import * as i1 from '@angular/common';
@@ -13,7 +13,7 @@ import * as i1$2 from '@angular/platform-browser';
13
13
  import QRCodeStyling from 'qr-code-styling';
14
14
  import * as i1$3 from '@angular/forms';
15
15
  import { ReactiveFormsModule, FormsModule, FormControl, Validators } from '@angular/forms';
16
- import { BehaviorSubject, filter, map, distinctUntilChanged, Subject, throwError, firstValueFrom, of, from } from 'rxjs';
16
+ import { BehaviorSubject, filter, map, distinctUntilChanged, Subject, throwError, Observable, firstValueFrom, of, from } from 'rxjs';
17
17
  import * as i1$4 from 'ng-otp-input';
18
18
  import { NgOtpInputComponent, NgOtpInputModule } from 'ng-otp-input';
19
19
  import * as i2 from '@ionic/angular';
@@ -27,6 +27,7 @@ import 'prismjs/components/prism-typescript';
27
27
  import 'prismjs/components/prism-bash';
28
28
  import Swiper from 'swiper';
29
29
  import { Navigation, Pagination, EffectFade, EffectCube, EffectCoverflow, EffectFlip, Autoplay } from 'swiper/modules';
30
+ import { Analytics, logEvent, setUserId, setUserProperties, provideAnalytics, getAnalytics } from '@angular/fire/analytics';
30
31
  import { provideFirebaseApp, initializeApp } from '@angular/fire/app';
31
32
  import * as i1$5 from '@angular/fire/auth';
32
33
  import { provideAuth, getAuth, connectAuthEmulator, authState, signInWithCustomToken, signOut } from '@angular/fire/auth';
@@ -35,7 +36,8 @@ import { provideFirestore, getFirestore, connectFirestoreEmulator, enableIndexed
35
36
  import { provideMessaging, getMessaging, Messaging, getToken, deleteToken, onMessage } from '@angular/fire/messaging';
36
37
  import * as i1$7 from '@angular/fire/storage';
37
38
  import { provideStorage, getStorage, connectStorageEmulator, ref, uploadBytesResumable, getDownloadURL, getMetadata, deleteObject, listAll } from '@angular/fire/storage';
38
- import { catchError, switchMap, finalize, filter as filter$1, take, tap, map as map$1 } from 'rxjs/operators';
39
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
40
+ import { filter as filter$1, catchError, switchMap, finalize, take, tap, map as map$1 } from 'rxjs/operators';
39
41
  import * as i1$8 from '@angular/common/http';
40
42
  import { provideHttpClient, withInterceptors } from '@angular/common/http';
41
43
 
@@ -21481,6 +21483,828 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
21481
21483
  * Todos los modelos de Firestore deben extender FirestoreDocument.
21482
21484
  */
21483
21485
 
21486
+ /**
21487
+ * Analytics Service (Firebase GA4)
21488
+ *
21489
+ * Servicio para tracking de eventos, page views y errores con Firebase Analytics.
21490
+ * Integra con el sistema de auth para user properties y respeta consent mode GDPR.
21491
+ */
21492
+ /** Key por defecto para persistir consent en localStorage */
21493
+ const DEFAULT_CONSENT_STORAGE_KEY = 'analytics_consent';
21494
+ /** Máximo de eventos en historial de debug */
21495
+ const MAX_DEBUG_HISTORY = 100;
21496
+ /**
21497
+ * Servicio de Firebase Analytics (GA4).
21498
+ *
21499
+ * Proporciona tracking de eventos, page views, errores y métricas de performance.
21500
+ * Soporta GDPR Consent Mode y modo debug para desarrollo.
21501
+ *
21502
+ * @example
21503
+ * ```typescript
21504
+ * @Component({...})
21505
+ * export class ProductComponent {
21506
+ * private analytics = inject(AnalyticsService);
21507
+ *
21508
+ * onPurchase(product: Product) {
21509
+ * this.analytics.logEvent('purchase', {
21510
+ * transaction_id: order.id,
21511
+ * value: order.total,
21512
+ * currency: 'EUR'
21513
+ * });
21514
+ * }
21515
+ * }
21516
+ * ```
21517
+ */
21518
+ class AnalyticsService {
21519
+ constructor(injector, config, platformId) {
21520
+ this.injector = injector;
21521
+ this.config = config;
21522
+ this.platformId = platformId;
21523
+ // ===========================================================================
21524
+ // ESTADO (Signals)
21525
+ // ===========================================================================
21526
+ this._consentState = signal({
21527
+ settings: {},
21528
+ updatedAt: null,
21529
+ hasDecided: false,
21530
+ });
21531
+ this._isDebugMode = signal(false);
21532
+ this._debugHistory = signal([]);
21533
+ /** Estado de consentimiento actual (readonly) */
21534
+ this.consentState = this._consentState.asReadonly();
21535
+ /** Indica si está en modo debug */
21536
+ this.isDebugMode = this._isDebugMode.asReadonly();
21537
+ /** Indica si analytics está habilitado y funcionando */
21538
+ this.isEnabled = computed(() => {
21539
+ return this.isAnalyticsSupported() && this._consentState().settings.analytics === true;
21540
+ });
21541
+ this.analyticsConfig = config.analyticsConfig ?? {};
21542
+ this.consentStorageKey =
21543
+ this.analyticsConfig.consentStorageKey ?? DEFAULT_CONSENT_STORAGE_KEY;
21544
+ this.eventPrefix = this.analyticsConfig.eventPrefix ?? '';
21545
+ this.samplingRate = this.analyticsConfig.samplingRate ?? 1.0;
21546
+ this.initializeAnalytics();
21547
+ }
21548
+ // ===========================================================================
21549
+ // INICIALIZACIÓN
21550
+ // ===========================================================================
21551
+ /**
21552
+ * Inicializa el servicio de analytics
21553
+ */
21554
+ initializeAnalytics() {
21555
+ if (!isPlatformBrowser(this.platformId)) {
21556
+ return;
21557
+ }
21558
+ // Cargar consent desde localStorage
21559
+ this.loadConsentFromStorage();
21560
+ // Configurar debug mode
21561
+ const debugMode = this.analyticsConfig.debugMode ?? false;
21562
+ this._isDebugMode.set(debugMode);
21563
+ // Aplicar consent inicial a gtag
21564
+ this.applyConsentToGtag(this._consentState().settings);
21565
+ // Setear user properties por defecto
21566
+ if (this.analyticsConfig.defaultUserProperties) {
21567
+ this.setUserProperties(this.analyticsConfig.defaultUserProperties);
21568
+ }
21569
+ if (debugMode) {
21570
+ console.log('[Analytics] Inicializado en modo debug - eventos NO se envían a Firebase');
21571
+ }
21572
+ }
21573
+ /**
21574
+ * Obtiene la instancia de Analytics de forma perezosa.
21575
+ * Esto evita el error de APP_INITIALIZER de AngularFire.
21576
+ */
21577
+ getAnalyticsInstance() {
21578
+ if (!this.config.enableAnalytics) {
21579
+ return null;
21580
+ }
21581
+ try {
21582
+ return this.injector.get(Analytics, null);
21583
+ }
21584
+ catch {
21585
+ return null;
21586
+ }
21587
+ }
21588
+ /**
21589
+ * Verifica si Analytics está soportado
21590
+ */
21591
+ isAnalyticsSupported() {
21592
+ if (!isPlatformBrowser(this.platformId)) {
21593
+ return false;
21594
+ }
21595
+ if (!this.config.enableAnalytics) {
21596
+ return false;
21597
+ }
21598
+ if (!this.config.firebase.measurementId) {
21599
+ console.warn('[Analytics] measurementId no configurado en firebase config');
21600
+ return false;
21601
+ }
21602
+ return true;
21603
+ }
21604
+ /**
21605
+ * Verifica si debe enviar el evento (sampling)
21606
+ */
21607
+ shouldSample() {
21608
+ if (this.samplingRate >= 1.0) {
21609
+ return true;
21610
+ }
21611
+ return Math.random() < this.samplingRate;
21612
+ }
21613
+ // ===========================================================================
21614
+ // PAGE VIEWS
21615
+ // ===========================================================================
21616
+ /**
21617
+ * Registra un page view.
21618
+ * Normalmente se usa automáticamente via AnalyticsRouterTracker.
21619
+ *
21620
+ * @param pagePath - Ruta de la página (ej: '/products/123')
21621
+ * @param pageTitle - Título de la página (opcional)
21622
+ */
21623
+ logPageView(pagePath, pageTitle) {
21624
+ this.logEvent('page_view', {
21625
+ page_path: pagePath,
21626
+ page_title: pageTitle ?? document?.title,
21627
+ page_location: window?.location?.href,
21628
+ });
21629
+ }
21630
+ /**
21631
+ * Registra un screen view (para apps tipo SPA).
21632
+ *
21633
+ * @param screenName - Nombre del screen
21634
+ * @param screenClass - Clase del screen (opcional)
21635
+ */
21636
+ logScreenView(screenName, screenClass) {
21637
+ this.logEvent('screen_view', {
21638
+ screen_name: screenName,
21639
+ screen_class: screenClass,
21640
+ });
21641
+ }
21642
+ // ===========================================================================
21643
+ // EVENTOS
21644
+ // ===========================================================================
21645
+ /**
21646
+ * Registra un evento tipado GA4.
21647
+ *
21648
+ * @param eventName - Nombre del evento (tipado)
21649
+ * @param params - Parámetros del evento (tipados según el nombre)
21650
+ *
21651
+ * @example
21652
+ * ```typescript
21653
+ * // Evento tipado con autocompletado
21654
+ * analytics.logEvent('add_to_cart', {
21655
+ * item_id: '123',
21656
+ * item_name: 'Producto',
21657
+ * value: 99.99,
21658
+ * currency: 'EUR'
21659
+ * });
21660
+ * ```
21661
+ */
21662
+ logEvent(eventName, params) {
21663
+ this.trackEvent(eventName, params);
21664
+ }
21665
+ /**
21666
+ * Registra un evento custom con parámetros libres.
21667
+ * Usar cuando el evento no está en el catálogo tipado.
21668
+ *
21669
+ * @param eventName - Nombre del evento custom
21670
+ * @param params - Parámetros libres
21671
+ */
21672
+ logCustomEvent(eventName, params) {
21673
+ const prefixedName = this.eventPrefix + eventName;
21674
+ this.trackEvent(prefixedName, params);
21675
+ }
21676
+ /**
21677
+ * Lógica común para enviar eventos
21678
+ */
21679
+ trackEvent(eventName, params) {
21680
+ // Verificar consent
21681
+ if (!this._consentState().settings.analytics) {
21682
+ this.addToDebugHistory('event', eventName, params, false);
21683
+ return;
21684
+ }
21685
+ // Aplicar sampling
21686
+ if (!this.shouldSample()) {
21687
+ return;
21688
+ }
21689
+ // Debug mode: solo log, no enviar
21690
+ if (this._isDebugMode()) {
21691
+ this.addToDebugHistory('event', eventName, params, false);
21692
+ console.log(`[Analytics] Event: ${eventName}`, params);
21693
+ return;
21694
+ }
21695
+ // Enviar a Firebase
21696
+ const analytics = this.getAnalyticsInstance();
21697
+ if (analytics) {
21698
+ try {
21699
+ logEvent(analytics, eventName, params);
21700
+ this.addToDebugHistory('event', eventName, params, true);
21701
+ }
21702
+ catch (error) {
21703
+ console.error('[Analytics] Error enviando evento:', error);
21704
+ }
21705
+ }
21706
+ }
21707
+ // ===========================================================================
21708
+ // ECOMMERCE
21709
+ // ===========================================================================
21710
+ /**
21711
+ * Registra vista de item
21712
+ */
21713
+ logViewItem(item) {
21714
+ this.logEvent('view_item', {
21715
+ item_id: item.item_id,
21716
+ item_name: item.item_name,
21717
+ value: item.price,
21718
+ currency: item.currency,
21719
+ });
21720
+ }
21721
+ /**
21722
+ * Registra agregar al carrito
21723
+ */
21724
+ logAddToCart(item, quantity = 1) {
21725
+ this.logEvent('add_to_cart', {
21726
+ item_id: item.item_id,
21727
+ item_name: item.item_name,
21728
+ value: (item.price ?? 0) * quantity,
21729
+ currency: item.currency,
21730
+ quantity,
21731
+ });
21732
+ }
21733
+ /**
21734
+ * Registra inicio de checkout
21735
+ */
21736
+ logBeginCheckout(items, value, currency = 'EUR') {
21737
+ this.logEvent('begin_checkout', {
21738
+ value,
21739
+ currency,
21740
+ items,
21741
+ });
21742
+ }
21743
+ /**
21744
+ * Registra compra completada
21745
+ */
21746
+ logPurchase(transactionId, items, value, currency = 'EUR') {
21747
+ this.logEvent('purchase', {
21748
+ transaction_id: transactionId,
21749
+ value,
21750
+ currency,
21751
+ items,
21752
+ });
21753
+ }
21754
+ // ===========================================================================
21755
+ // USER PROPERTIES
21756
+ // ===========================================================================
21757
+ /**
21758
+ * Setea el userId para asociar eventos con el usuario.
21759
+ * Llamado automáticamente si enableAuthIntegration=true.
21760
+ *
21761
+ * @param userId - ID del usuario o null para limpiar
21762
+ */
21763
+ setUserId(userId) {
21764
+ if (!this.isAnalyticsSupported()) {
21765
+ return;
21766
+ }
21767
+ if (this._isDebugMode()) {
21768
+ console.log(`[Analytics] Set userId: ${userId}`);
21769
+ this.addToDebugHistory('user_property', 'user_id', { userId }, false);
21770
+ return;
21771
+ }
21772
+ const analytics = this.getAnalyticsInstance();
21773
+ if (analytics) {
21774
+ try {
21775
+ setUserId(analytics, userId);
21776
+ }
21777
+ catch (error) {
21778
+ console.error('[Analytics] Error seteando userId:', error);
21779
+ }
21780
+ }
21781
+ }
21782
+ /**
21783
+ * Setea propiedades del usuario para segmentación.
21784
+ *
21785
+ * @param properties - Propiedades key-value
21786
+ *
21787
+ * @example
21788
+ * ```typescript
21789
+ * analytics.setUserProperties({
21790
+ * subscription_tier: 'premium',
21791
+ * preferred_language: 'es'
21792
+ * });
21793
+ * ```
21794
+ */
21795
+ setUserProperties(properties) {
21796
+ if (!this.isAnalyticsSupported()) {
21797
+ return;
21798
+ }
21799
+ if (this._isDebugMode()) {
21800
+ console.log('[Analytics] Set user properties:', properties);
21801
+ this.addToDebugHistory('user_property', 'properties', properties, false);
21802
+ return;
21803
+ }
21804
+ const analytics = this.getAnalyticsInstance();
21805
+ if (analytics) {
21806
+ try {
21807
+ // Convertir a Record<string, string> para Firebase
21808
+ const stringProps = {};
21809
+ for (const [key, value] of Object.entries(properties)) {
21810
+ if (value !== undefined) {
21811
+ stringProps[key] = String(value);
21812
+ }
21813
+ }
21814
+ setUserProperties(analytics, stringProps);
21815
+ }
21816
+ catch (error) {
21817
+ console.error('[Analytics] Error seteando user properties:', error);
21818
+ }
21819
+ }
21820
+ }
21821
+ /**
21822
+ * Setea la organización activa (multi-tenant).
21823
+ * Llamado automáticamente si enableAuthIntegration=true.
21824
+ *
21825
+ * @param orgId - ID de la organización o null
21826
+ */
21827
+ setActiveOrganization(orgId) {
21828
+ if (orgId) {
21829
+ this.setUserProperties({ active_organization: orgId });
21830
+ }
21831
+ }
21832
+ // ===========================================================================
21833
+ // ERROR TRACKING
21834
+ // ===========================================================================
21835
+ /**
21836
+ * Registra un error para tracking.
21837
+ * Integra automáticamente con Angular ErrorHandler si enableErrorTracking=true.
21838
+ *
21839
+ * @param error - Error o mensaje de error
21840
+ * @param context - Contexto adicional
21841
+ *
21842
+ * @example
21843
+ * ```typescript
21844
+ * try {
21845
+ * await riskyOperation();
21846
+ * } catch (error) {
21847
+ * analytics.logError(error, { context: 'checkout_flow' });
21848
+ * }
21849
+ * ```
21850
+ */
21851
+ logError(error, context) {
21852
+ const errorMessage = error instanceof Error ? error.message : error;
21853
+ const errorStack = error instanceof Error ? error.stack : undefined;
21854
+ const errorType = error instanceof Error ? error.name : 'Error';
21855
+ this.logEvent('error_occurred', {
21856
+ error_type: errorType,
21857
+ error_message: errorMessage.substring(0, 100), // Limitar longitud
21858
+ error_stack: errorStack?.substring(0, 500),
21859
+ context: context ? JSON.stringify(context) : undefined,
21860
+ });
21861
+ }
21862
+ /**
21863
+ * Registra un error fatal (crash-level).
21864
+ */
21865
+ logFatalError(error, context) {
21866
+ this.logError(error, { ...context, severity: 'fatal' });
21867
+ }
21868
+ // ===========================================================================
21869
+ // CONSENT MODE (GDPR)
21870
+ // ===========================================================================
21871
+ /**
21872
+ * Actualiza el estado de consentimiento del usuario.
21873
+ * Afecta qué datos se recolectan y envían.
21874
+ *
21875
+ * @param consent - Settings de consentimiento
21876
+ *
21877
+ * @example
21878
+ * ```typescript
21879
+ * // Usuario acepta todo
21880
+ * analytics.updateConsent({ analytics: true, advertising: true });
21881
+ *
21882
+ * // Usuario rechaza publicidad
21883
+ * analytics.updateConsent({ analytics: true, advertising: false });
21884
+ * ```
21885
+ */
21886
+ updateConsent(consent) {
21887
+ const newState = {
21888
+ settings: { ...this._consentState().settings, ...consent },
21889
+ updatedAt: new Date(),
21890
+ hasDecided: true,
21891
+ };
21892
+ this._consentState.set(newState);
21893
+ this.saveConsentToStorage(newState);
21894
+ this.applyConsentToGtag(newState.settings);
21895
+ this.addToDebugHistory('consent', 'update', consent, false);
21896
+ }
21897
+ /**
21898
+ * Deniega todo consentimiento.
21899
+ */
21900
+ denyAllConsent() {
21901
+ this.updateConsent({
21902
+ analytics: false,
21903
+ advertising: false,
21904
+ functionality: false,
21905
+ security: true, // Siempre permitido
21906
+ });
21907
+ }
21908
+ /**
21909
+ * Acepta todo consentimiento.
21910
+ */
21911
+ grantAllConsent() {
21912
+ this.updateConsent({
21913
+ analytics: true,
21914
+ advertising: true,
21915
+ functionality: true,
21916
+ security: true,
21917
+ });
21918
+ }
21919
+ /**
21920
+ * Obtiene el estado actual de consentimiento.
21921
+ */
21922
+ getConsentState() {
21923
+ return this._consentState();
21924
+ }
21925
+ /**
21926
+ * Aplica consent settings a gtag (GA4 Consent Mode v2)
21927
+ */
21928
+ applyConsentToGtag(settings) {
21929
+ if (!isPlatformBrowser(this.platformId)) {
21930
+ return;
21931
+ }
21932
+ const gtag = window.gtag;
21933
+ if (typeof gtag !== 'function') {
21934
+ return;
21935
+ }
21936
+ try {
21937
+ gtag('consent', 'update', {
21938
+ analytics_storage: settings.analytics ? 'granted' : 'denied',
21939
+ ad_storage: settings.advertising ? 'granted' : 'denied',
21940
+ ad_user_data: settings.advertising ? 'granted' : 'denied',
21941
+ ad_personalization: settings.advertising ? 'granted' : 'denied',
21942
+ functionality_storage: settings.functionality ? 'granted' : 'denied',
21943
+ security_storage: settings.security !== false ? 'granted' : 'denied',
21944
+ });
21945
+ }
21946
+ catch (error) {
21947
+ console.warn('[Analytics] Error aplicando consent a gtag:', error);
21948
+ }
21949
+ }
21950
+ /**
21951
+ * Carga consent desde localStorage
21952
+ */
21953
+ loadConsentFromStorage() {
21954
+ if (!isPlatformBrowser(this.platformId)) {
21955
+ return;
21956
+ }
21957
+ try {
21958
+ const stored = localStorage.getItem(this.consentStorageKey);
21959
+ if (stored) {
21960
+ const parsed = JSON.parse(stored);
21961
+ this._consentState.set({
21962
+ ...parsed,
21963
+ updatedAt: parsed.updatedAt ? new Date(parsed.updatedAt) : null,
21964
+ });
21965
+ }
21966
+ else if (this.analyticsConfig.defaultConsent) {
21967
+ // Aplicar consent por defecto si no hay guardado
21968
+ this._consentState.set({
21969
+ settings: this.analyticsConfig.defaultConsent,
21970
+ updatedAt: null,
21971
+ hasDecided: false,
21972
+ });
21973
+ }
21974
+ }
21975
+ catch (error) {
21976
+ console.warn('[Analytics] Error cargando consent:', error);
21977
+ }
21978
+ }
21979
+ /**
21980
+ * Guarda consent en localStorage
21981
+ */
21982
+ saveConsentToStorage(state) {
21983
+ if (!isPlatformBrowser(this.platformId)) {
21984
+ return;
21985
+ }
21986
+ try {
21987
+ localStorage.setItem(this.consentStorageKey, JSON.stringify(state));
21988
+ }
21989
+ catch (error) {
21990
+ console.warn('[Analytics] Error guardando consent:', error);
21991
+ }
21992
+ }
21993
+ // ===========================================================================
21994
+ // TIMING / PERFORMANCE
21995
+ // ===========================================================================
21996
+ /**
21997
+ * Registra una métrica de timing/performance.
21998
+ *
21999
+ * @param name - Nombre de la métrica
22000
+ * @param valueMs - Valor en milisegundos
22001
+ * @param params - Parámetros adicionales
22002
+ *
22003
+ * @example
22004
+ * ```typescript
22005
+ * const start = performance.now();
22006
+ * await loadData();
22007
+ * analytics.logTiming('data_load', performance.now() - start, {
22008
+ * category: 'api',
22009
+ * endpoint: '/products'
22010
+ * });
22011
+ * ```
22012
+ */
22013
+ logTiming(name, valueMs, params) {
22014
+ this.logEvent('performance_metric', {
22015
+ metric_name: name,
22016
+ value: Math.round(valueMs),
22017
+ unit: 'ms',
22018
+ ...params,
22019
+ });
22020
+ }
22021
+ // ===========================================================================
22022
+ // DEBUG
22023
+ // ===========================================================================
22024
+ /**
22025
+ * Habilita/deshabilita modo debug.
22026
+ * En debug: logea a consola, no envía a Firebase.
22027
+ */
22028
+ setDebugMode(enabled) {
22029
+ this._isDebugMode.set(enabled);
22030
+ console.log(`[Analytics] Debug mode: ${enabled ? 'ON' : 'OFF'}`);
22031
+ }
22032
+ /**
22033
+ * Obtiene historial de eventos (solo en debug mode).
22034
+ * Útil para testing y desarrollo.
22035
+ */
22036
+ getDebugHistory() {
22037
+ return this._debugHistory();
22038
+ }
22039
+ /**
22040
+ * Limpia historial de debug.
22041
+ */
22042
+ clearDebugHistory() {
22043
+ this._debugHistory.set([]);
22044
+ }
22045
+ /**
22046
+ * Agrega evento al historial de debug
22047
+ */
22048
+ addToDebugHistory(type, name, params, sent = false) {
22049
+ if (!this._isDebugMode()) {
22050
+ return;
22051
+ }
22052
+ const event = {
22053
+ timestamp: new Date(),
22054
+ type,
22055
+ name,
22056
+ params,
22057
+ sent,
22058
+ };
22059
+ this._debugHistory.update((history) => {
22060
+ const newHistory = [event, ...history];
22061
+ return newHistory.slice(0, MAX_DEBUG_HISTORY);
22062
+ });
22063
+ }
22064
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AnalyticsService, deps: [{ token: i0.Injector }, { token: VALTECH_FIREBASE_CONFIG }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); }
22065
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AnalyticsService, providedIn: 'root' }); }
22066
+ }
22067
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AnalyticsService, decorators: [{
22068
+ type: Injectable,
22069
+ args: [{ providedIn: 'root' }]
22070
+ }], ctorParameters: () => [{ type: i0.Injector }, { type: undefined, decorators: [{
22071
+ type: Inject,
22072
+ args: [VALTECH_FIREBASE_CONFIG]
22073
+ }] }, { type: Object, decorators: [{
22074
+ type: Inject,
22075
+ args: [PLATFORM_ID]
22076
+ }] }] });
22077
+
22078
+ /**
22079
+ * Analytics Error Handler
22080
+ *
22081
+ * ErrorHandler personalizado que envía errores no capturados a Firebase Analytics.
22082
+ * Se activa si enableErrorTracking=true en analyticsConfig.
22083
+ */
22084
+ /**
22085
+ * ErrorHandler que trackea errores en Firebase Analytics.
22086
+ *
22087
+ * Captura errores no manejados de la aplicación y los envía a GA4
22088
+ * como eventos 'error_occurred'. También delega al ErrorHandler
22089
+ * default para mantener el comportamiento de console.error.
22090
+ *
22091
+ * @example
22092
+ * ```typescript
22093
+ * // Se activa automáticamente si enableErrorTracking=true
22094
+ * provideValtechFirebase({
22095
+ * firebase: environment.firebase,
22096
+ * enableAnalytics: true,
22097
+ * analyticsConfig: {
22098
+ * enableErrorTracking: true,
22099
+ * },
22100
+ * });
22101
+ * ```
22102
+ */
22103
+ class AnalyticsErrorHandler {
22104
+ constructor() {
22105
+ this.analytics = inject(AnalyticsService);
22106
+ this.defaultHandler = new ErrorHandler();
22107
+ }
22108
+ /**
22109
+ * Maneja un error no capturado.
22110
+ * Envía el error a Analytics y luego al handler default.
22111
+ */
22112
+ handleError(error) {
22113
+ // Enviar a Analytics
22114
+ try {
22115
+ this.trackError(error);
22116
+ }
22117
+ catch (trackingError) {
22118
+ // No fallar si el tracking falla
22119
+ console.warn('[AnalyticsErrorHandler] Error tracking failed:', trackingError);
22120
+ }
22121
+ // Delegar al handler default (console.error)
22122
+ this.defaultHandler.handleError(error);
22123
+ }
22124
+ /**
22125
+ * Trackea el error en Analytics
22126
+ */
22127
+ trackError(error) {
22128
+ // Extraer información del error
22129
+ const errorInfo = this.extractErrorInfo(error);
22130
+ this.analytics.logError(errorInfo.error, {
22131
+ source: 'uncaught',
22132
+ url: this.getCurrentUrl(),
22133
+ ...errorInfo.context,
22134
+ });
22135
+ }
22136
+ /**
22137
+ * Extrae información útil del error
22138
+ */
22139
+ extractErrorInfo(error) {
22140
+ const context = {};
22141
+ // Error estándar
22142
+ if (error instanceof Error) {
22143
+ // Detectar errores de chunk loading (lazy loading)
22144
+ if (error.message.includes('Loading chunk')) {
22145
+ context['error_category'] = 'chunk_loading';
22146
+ }
22147
+ // Detectar errores de red
22148
+ if (error.message.includes('NetworkError') || error.message.includes('Failed to fetch')) {
22149
+ context['error_category'] = 'network';
22150
+ }
22151
+ return { error, context };
22152
+ }
22153
+ // ErrorEvent (ej: errores de script)
22154
+ if (typeof ErrorEvent !== 'undefined' && error instanceof ErrorEvent) {
22155
+ return {
22156
+ error: new Error(error.message || 'Script error'),
22157
+ context: {
22158
+ filename: error.filename || 'unknown',
22159
+ lineno: String(error.lineno || 0),
22160
+ colno: String(error.colno || 0),
22161
+ },
22162
+ };
22163
+ }
22164
+ // PromiseRejection
22165
+ if (this.isPromiseRejection(error)) {
22166
+ const reason = error.reason;
22167
+ if (reason instanceof Error) {
22168
+ return {
22169
+ error: reason,
22170
+ context: { error_category: 'unhandled_promise' },
22171
+ };
22172
+ }
22173
+ return {
22174
+ error: new Error(String(reason) || 'Unhandled promise rejection'),
22175
+ context: { error_category: 'unhandled_promise' },
22176
+ };
22177
+ }
22178
+ // Objeto con message
22179
+ if (error && typeof error === 'object' && 'message' in error) {
22180
+ return {
22181
+ error: new Error(String(error.message)),
22182
+ context,
22183
+ };
22184
+ }
22185
+ // Fallback: convertir a string
22186
+ return {
22187
+ error: new Error(String(error) || 'Unknown error'),
22188
+ context,
22189
+ };
22190
+ }
22191
+ /**
22192
+ * Verifica si es un PromiseRejectionEvent
22193
+ */
22194
+ isPromiseRejection(error) {
22195
+ return (typeof PromiseRejectionEvent !== 'undefined' &&
22196
+ error instanceof PromiseRejectionEvent);
22197
+ }
22198
+ /**
22199
+ * Obtiene la URL actual de forma segura
22200
+ */
22201
+ getCurrentUrl() {
22202
+ try {
22203
+ return window?.location?.href || 'unknown';
22204
+ }
22205
+ catch {
22206
+ return 'unknown';
22207
+ }
22208
+ }
22209
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AnalyticsErrorHandler, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
22210
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AnalyticsErrorHandler }); }
22211
+ }
22212
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AnalyticsErrorHandler, decorators: [{
22213
+ type: Injectable
22214
+ }] });
22215
+
22216
+ /**
22217
+ * Analytics Router Tracker
22218
+ *
22219
+ * Servicio que trackea automáticamente page views cuando el usuario navega.
22220
+ * Se activa automáticamente si enablePageViewTracking=true en analyticsConfig.
22221
+ */
22222
+ /**
22223
+ * Tracker automático de page views via Router.
22224
+ *
22225
+ * Este servicio escucha eventos de navegación del Router y registra
22226
+ * page views automáticamente en Firebase Analytics.
22227
+ *
22228
+ * Se excluyen rutas configuradas en `analyticsConfig.excludeRoutes`.
22229
+ *
22230
+ * @example
22231
+ * ```typescript
22232
+ * // Se activa automáticamente si enablePageViewTracking=true
22233
+ * provideValtechFirebase({
22234
+ * firebase: environment.firebase,
22235
+ * enableAnalytics: true,
22236
+ * analyticsConfig: {
22237
+ * enablePageViewTracking: true,
22238
+ * excludeRoutes: ['/admin/*', '/debug/*'],
22239
+ * },
22240
+ * });
22241
+ * ```
22242
+ */
22243
+ class AnalyticsRouterTracker {
22244
+ constructor(config) {
22245
+ this.config = config;
22246
+ this.analytics = inject(AnalyticsService);
22247
+ this.router = inject(Router);
22248
+ this.destroyRef = inject(DestroyRef);
22249
+ const analyticsConfig = config.analyticsConfig ?? {};
22250
+ this.enabled = analyticsConfig.enablePageViewTracking !== false;
22251
+ this.excludePatterns = this.compileExcludePatterns(analyticsConfig.excludeRoutes ?? []);
22252
+ if (this.enabled && config.enableAnalytics) {
22253
+ this.startTracking();
22254
+ }
22255
+ }
22256
+ /**
22257
+ * Inicia el tracking de navegación
22258
+ */
22259
+ startTracking() {
22260
+ this.router.events
22261
+ .pipe(filter$1((event) => event instanceof NavigationEnd), filter$1((event) => !this.isExcluded(event.urlAfterRedirects)), takeUntilDestroyed(this.destroyRef))
22262
+ .subscribe((event) => {
22263
+ this.analytics.logPageView(event.urlAfterRedirects);
22264
+ });
22265
+ }
22266
+ /**
22267
+ * Compila patrones de exclusión a RegExp
22268
+ */
22269
+ compileExcludePatterns(patterns) {
22270
+ return patterns.map((pattern) => {
22271
+ // Convertir glob pattern a regex
22272
+ // Ej: '/admin/*' -> /^\/admin\/.*$/
22273
+ const regexPattern = pattern
22274
+ .replace(/[.+?^${}()|[\]\\]/g, '\\$&') // Escapar caracteres especiales
22275
+ .replace(/\*/g, '.*'); // Convertir * a .*
22276
+ return new RegExp(`^${regexPattern}$`);
22277
+ });
22278
+ }
22279
+ /**
22280
+ * Verifica si una URL debe ser excluida del tracking
22281
+ */
22282
+ isExcluded(url) {
22283
+ // Remover query params para la comparación
22284
+ const path = url.split('?')[0];
22285
+ return this.excludePatterns.some((pattern) => pattern.test(path));
22286
+ }
22287
+ /**
22288
+ * Registra un page view manualmente.
22289
+ * Útil para casos donde necesitas trackear manualmente.
22290
+ */
22291
+ trackPageView(path, title) {
22292
+ if (this.isExcluded(path)) {
22293
+ return;
22294
+ }
22295
+ this.analytics.logPageView(path, title);
22296
+ }
22297
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AnalyticsRouterTracker, deps: [{ token: VALTECH_FIREBASE_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable }); }
22298
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AnalyticsRouterTracker, providedIn: 'root' }); }
22299
+ }
22300
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AnalyticsRouterTracker, decorators: [{
22301
+ type: Injectable,
22302
+ args: [{ providedIn: 'root' }]
22303
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
22304
+ type: Inject,
22305
+ args: [VALTECH_FIREBASE_CONFIG]
22306
+ }] }] });
22307
+
21484
22308
  /**
21485
22309
  * Firebase Configuration
21486
22310
  *
@@ -21575,6 +22399,22 @@ function provideValtechFirebase(config) {
21575
22399
  }
21576
22400
  providers.push(provideMessaging(() => getMessaging()));
21577
22401
  }
22402
+ // Analytics (GA4) - solo si está explícitamente habilitado
22403
+ // Requiere measurementId en firebase config
22404
+ if (config.enableAnalytics && config.firebase.measurementId) {
22405
+ providers.push(provideAnalytics(() => getAnalytics()));
22406
+ // Router tracker para page views automáticos (por defecto habilitado)
22407
+ if (config.analyticsConfig?.enablePageViewTracking !== false) {
22408
+ providers.push(AnalyticsRouterTracker);
22409
+ }
22410
+ // Error handler para tracking automático de errores
22411
+ if (config.analyticsConfig?.enableErrorTracking) {
22412
+ providers.push({
22413
+ provide: ErrorHandler,
22414
+ useClass: AnalyticsErrorHandler,
22415
+ });
22416
+ }
22417
+ }
21578
22418
  return makeEnvironmentProviders(providers);
21579
22419
  }
21580
22420
  /**
@@ -25255,6 +26095,250 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
25255
26095
  args: [VALTECH_AUTH_CONFIG]
25256
26096
  }] }] });
25257
26097
 
26098
+ /**
26099
+ * Servicio de OAuth para login social.
26100
+ *
26101
+ * Implementa flujo OAuth server-side con popup:
26102
+ * 1. Frontend abre popup hacia backend
26103
+ * 2. Backend redirige a provider (Google, Apple, Microsoft)
26104
+ * 3. Usuario autoriza
26105
+ * 4. Backend intercambia code, genera JWT, redirige con tokens
26106
+ * 5. Popup envía tokens a ventana padre via postMessage
26107
+ *
26108
+ * @example
26109
+ * ```typescript
26110
+ * import { OAuthService, AuthService } from 'valtech-components';
26111
+ *
26112
+ * @Component({...})
26113
+ * export class LoginComponent {
26114
+ * private oauth = inject(OAuthService);
26115
+ * private auth = inject(AuthService);
26116
+ *
26117
+ * async loginWithGoogle() {
26118
+ * this.oauth.startFlow('google').subscribe({
26119
+ * next: (result) => {
26120
+ * // Tokens recibidos, guardar en auth state
26121
+ * this.auth.handleOAuthSuccess(result);
26122
+ * this.router.navigate(['/']);
26123
+ * },
26124
+ * error: (error) => {
26125
+ * console.error('OAuth failed:', error);
26126
+ * }
26127
+ * });
26128
+ * }
26129
+ * }
26130
+ * ```
26131
+ */
26132
+ class OAuthService {
26133
+ constructor(config, http, ngZone) {
26134
+ this.config = config;
26135
+ this.http = http;
26136
+ this.ngZone = ngZone;
26137
+ this.popup = null;
26138
+ this.messageHandler = null;
26139
+ this.checkClosedInterval = null;
26140
+ }
26141
+ /**
26142
+ * Inicia flujo OAuth en popup.
26143
+ * Retorna Observable que emite cuando el usuario completa el flujo.
26144
+ *
26145
+ * @param provider - Proveedor OAuth ('google', 'apple', 'microsoft')
26146
+ * @returns Observable que emite OAuthResult o error
26147
+ */
26148
+ startFlow(provider) {
26149
+ return new Observable(observer => {
26150
+ // Construir URL de inicio
26151
+ const redirectUri = `${window.location.origin}/auth/oauth/callback`;
26152
+ const startUrl = `${this.config.apiUrl}/v2/auth/oauth/${provider}/start?redirect_uri=${encodeURIComponent(redirectUri)}`;
26153
+ // Abrir popup centrado
26154
+ const width = 500;
26155
+ const height = 600;
26156
+ const left = window.screenX + (window.outerWidth - width) / 2;
26157
+ const top = window.screenY + (window.outerHeight - height) / 2;
26158
+ const features = `width=${width},height=${height},left=${left},top=${top},popup=yes`;
26159
+ this.popup = window.open(startUrl, 'oauth', features);
26160
+ if (!this.popup) {
26161
+ observer.error({
26162
+ code: 'POPUP_BLOCKED',
26163
+ message: 'El navegador bloqueó la ventana emergente. Por favor, permite popups para este sitio.',
26164
+ });
26165
+ return () => { };
26166
+ }
26167
+ // Escuchar mensajes del popup
26168
+ this.messageHandler = (event) => {
26169
+ // Validar origen
26170
+ if (event.origin !== window.location.origin) {
26171
+ return;
26172
+ }
26173
+ // Validar tipo de mensaje
26174
+ const data = event.data;
26175
+ if (data?.type !== 'oauth-callback') {
26176
+ return;
26177
+ }
26178
+ // Limpiar
26179
+ this.cleanup();
26180
+ // Emitir resultado dentro de NgZone para trigger change detection
26181
+ this.ngZone.run(() => {
26182
+ if (data.error) {
26183
+ observer.error(data.error);
26184
+ }
26185
+ else if (data.tokens) {
26186
+ observer.next(data.tokens);
26187
+ observer.complete();
26188
+ }
26189
+ else {
26190
+ observer.error({
26191
+ code: 'INVALID_RESPONSE',
26192
+ message: 'Respuesta inválida del servidor de autenticación',
26193
+ });
26194
+ }
26195
+ });
26196
+ };
26197
+ window.addEventListener('message', this.messageHandler);
26198
+ // Verificar si popup se cierra manualmente
26199
+ this.checkClosedInterval = setInterval(() => {
26200
+ if (this.popup?.closed) {
26201
+ this.cleanup();
26202
+ this.ngZone.run(() => {
26203
+ observer.error({
26204
+ code: 'POPUP_CLOSED',
26205
+ message: 'Se cerró la ventana de autenticación',
26206
+ });
26207
+ });
26208
+ }
26209
+ }, 500);
26210
+ // Cleanup cuando el observable se destruye
26211
+ return () => this.cleanup();
26212
+ });
26213
+ }
26214
+ /**
26215
+ * Inicia flujo de linking para vincular un proveedor adicional.
26216
+ * Requiere que el usuario esté autenticado.
26217
+ *
26218
+ * @param provider - Proveedor OAuth a vincular
26219
+ * @returns Observable que emite cuando se completa el linking
26220
+ */
26221
+ startLinkFlow(provider) {
26222
+ return new Observable(observer => {
26223
+ const redirectUri = `${window.location.origin}/auth/oauth/callback`;
26224
+ const startUrl = `${this.config.apiUrl}/v2/auth/oauth/link/${provider}/start?redirect_uri=${encodeURIComponent(redirectUri)}`;
26225
+ const width = 500;
26226
+ const height = 600;
26227
+ const left = window.screenX + (window.outerWidth - width) / 2;
26228
+ const top = window.screenY + (window.outerHeight - height) / 2;
26229
+ const features = `width=${width},height=${height},left=${left},top=${top},popup=yes`;
26230
+ this.popup = window.open(startUrl, 'oauth-link', features);
26231
+ if (!this.popup) {
26232
+ observer.error({
26233
+ code: 'POPUP_BLOCKED',
26234
+ message: 'El navegador bloqueó la ventana emergente',
26235
+ });
26236
+ return () => { }; // cleanup function
26237
+ }
26238
+ this.messageHandler = (event) => {
26239
+ if (event.origin !== window.location.origin)
26240
+ return;
26241
+ const data = event.data;
26242
+ if (data?.type !== 'oauth-callback')
26243
+ return;
26244
+ this.cleanup();
26245
+ this.ngZone.run(() => {
26246
+ if (data.error) {
26247
+ observer.error(data.error);
26248
+ }
26249
+ else {
26250
+ observer.next(data.tokens || {});
26251
+ observer.complete();
26252
+ }
26253
+ });
26254
+ };
26255
+ window.addEventListener('message', this.messageHandler);
26256
+ this.checkClosedInterval = setInterval(() => {
26257
+ if (this.popup?.closed) {
26258
+ this.cleanup();
26259
+ this.ngZone.run(() => {
26260
+ observer.error({
26261
+ code: 'POPUP_CLOSED',
26262
+ message: 'Se cerró la ventana de autenticación',
26263
+ });
26264
+ });
26265
+ }
26266
+ }, 500);
26267
+ return () => this.cleanup();
26268
+ });
26269
+ }
26270
+ /**
26271
+ * Obtiene los proveedores OAuth vinculados al usuario.
26272
+ */
26273
+ getLinkedProviders() {
26274
+ return this.http
26275
+ .get(`${this.config.apiUrl}/v2/auth/oauth/providers`)
26276
+ .pipe(catchError(error => throwError(() => ({
26277
+ code: error.error?.code || 'FETCH_ERROR',
26278
+ message: error.error?.message || 'Error al obtener proveedores vinculados',
26279
+ }))));
26280
+ }
26281
+ /**
26282
+ * Desvincula un proveedor OAuth.
26283
+ */
26284
+ unlinkProvider(provider) {
26285
+ return this.http
26286
+ .post(`${this.config.apiUrl}/v2/auth/oauth/unlink`, { provider })
26287
+ .pipe(catchError(error => throwError(() => ({
26288
+ code: error.error?.code || 'UNLINK_ERROR',
26289
+ message: error.error?.message || 'Error al desvincular proveedor',
26290
+ }))));
26291
+ }
26292
+ /**
26293
+ * Establece contraseña para usuarios que solo tienen OAuth.
26294
+ */
26295
+ setPassword(password) {
26296
+ return this.http
26297
+ .post(`${this.config.apiUrl}/v2/auth/oauth/set-password`, { password })
26298
+ .pipe(catchError(error => throwError(() => ({
26299
+ code: error.error?.code || 'SET_PASSWORD_ERROR',
26300
+ message: error.error?.message || 'Error al establecer contraseña',
26301
+ }))));
26302
+ }
26303
+ /**
26304
+ * Verifica si el usuario tiene contraseña establecida.
26305
+ */
26306
+ hasPassword() {
26307
+ return this.http
26308
+ .get(`${this.config.apiUrl}/v2/auth/oauth/has-password`)
26309
+ .pipe(catchError(error => throwError(() => ({
26310
+ code: error.error?.code || 'CHECK_PASSWORD_ERROR',
26311
+ message: error.error?.message || 'Error al verificar contraseña',
26312
+ }))));
26313
+ }
26314
+ /**
26315
+ * Limpia recursos del popup.
26316
+ */
26317
+ cleanup() {
26318
+ if (this.messageHandler) {
26319
+ window.removeEventListener('message', this.messageHandler);
26320
+ this.messageHandler = null;
26321
+ }
26322
+ if (this.checkClosedInterval) {
26323
+ clearInterval(this.checkClosedInterval);
26324
+ this.checkClosedInterval = null;
26325
+ }
26326
+ if (this.popup && !this.popup.closed) {
26327
+ this.popup.close();
26328
+ }
26329
+ this.popup = null;
26330
+ }
26331
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OAuthService, deps: [{ token: VALTECH_AUTH_CONFIG }, { token: i1$8.HttpClient }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); }
26332
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OAuthService, providedIn: 'root' }); }
26333
+ }
26334
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OAuthService, decorators: [{
26335
+ type: Injectable,
26336
+ args: [{ providedIn: 'root' }]
26337
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
26338
+ type: Inject,
26339
+ args: [VALTECH_AUTH_CONFIG]
26340
+ }] }, { type: i1$8.HttpClient }, { type: i0.NgZone }] });
26341
+
25258
26342
  /**
25259
26343
  * Servicio principal de autenticación.
25260
26344
  *
@@ -25278,7 +26362,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
25278
26362
  * ```
25279
26363
  */
25280
26364
  class AuthService {
25281
- constructor(config, http, router, stateService, tokenService, storageService, syncService, firebaseService, messagingService, i18nService) {
26365
+ constructor(config, http, router, stateService, tokenService, storageService, syncService, firebaseService, oauthService, messagingService, i18nService) {
25282
26366
  this.config = config;
25283
26367
  this.http = http;
25284
26368
  this.router = router;
@@ -25287,6 +26371,7 @@ class AuthService {
25287
26371
  this.storageService = storageService;
25288
26372
  this.syncService = syncService;
25289
26373
  this.firebaseService = firebaseService;
26374
+ this.oauthService = oauthService;
25290
26375
  this.messagingService = messagingService;
25291
26376
  this.i18nService = i18nService;
25292
26377
  // Timer para refresh proactivo
@@ -25400,6 +26485,101 @@ class AuthService {
25400
26485
  }
25401
26486
  }), catchError(error => this.handleAuthError(error)));
25402
26487
  }
26488
+ // =============================================
26489
+ // OAUTH (Login social)
26490
+ // =============================================
26491
+ /**
26492
+ * Inicia sesión con OAuth (Google, Apple, Microsoft).
26493
+ * Abre un popup para el flujo de autenticación.
26494
+ *
26495
+ * @param provider - Proveedor OAuth ('google', 'apple', 'microsoft')
26496
+ * @returns Observable que emite SigninResponse cuando se completa
26497
+ *
26498
+ * @example
26499
+ * ```typescript
26500
+ * this.auth.signinWithOAuth('google').subscribe({
26501
+ * next: () => this.router.navigate(['/']),
26502
+ * error: (err) => console.error('OAuth failed:', err)
26503
+ * });
26504
+ * ```
26505
+ */
26506
+ signinWithOAuth(provider) {
26507
+ this.stateService.clearError();
26508
+ return this.oauthService.startFlow(provider).pipe(tap(result => {
26509
+ // Convertir OAuthResult a SigninResponse compatible
26510
+ const response = {
26511
+ operationId: 'oauth',
26512
+ accessToken: result.accessToken,
26513
+ refreshToken: result.refreshToken,
26514
+ firebaseToken: result.firebaseToken,
26515
+ expiresIn: result.expiresIn,
26516
+ roles: result.roles,
26517
+ permissions: result.permissions,
26518
+ };
26519
+ this.handleSuccessfulAuth(response);
26520
+ }), map$1(result => ({
26521
+ operationId: 'oauth',
26522
+ accessToken: result.accessToken,
26523
+ refreshToken: result.refreshToken,
26524
+ firebaseToken: result.firebaseToken,
26525
+ expiresIn: result.expiresIn,
26526
+ roles: result.roles,
26527
+ permissions: result.permissions,
26528
+ })), catchError(error => {
26529
+ const authError = {
26530
+ code: error.code || 'OAUTH_ERROR',
26531
+ message: error.message || 'Error de autenticación OAuth',
26532
+ };
26533
+ this.stateService.setError(authError);
26534
+ return throwError(() => authError);
26535
+ }));
26536
+ }
26537
+ /**
26538
+ * Vincula un proveedor OAuth adicional a la cuenta actual.
26539
+ * Requiere que el usuario esté autenticado.
26540
+ *
26541
+ * @param provider - Proveedor OAuth a vincular
26542
+ */
26543
+ linkOAuthProvider(provider) {
26544
+ return this.oauthService.startLinkFlow(provider).pipe(map$1(() => ({ success: true })), catchError(error => {
26545
+ const authError = {
26546
+ code: error.code || 'LINK_ERROR',
26547
+ message: error.message || 'Error al vincular proveedor',
26548
+ };
26549
+ this.stateService.setError(authError);
26550
+ return throwError(() => authError);
26551
+ }));
26552
+ }
26553
+ /**
26554
+ * Obtiene los proveedores OAuth vinculados al usuario.
26555
+ */
26556
+ getLinkedProviders() {
26557
+ return this.oauthService.getLinkedProviders();
26558
+ }
26559
+ /**
26560
+ * Desvincula un proveedor OAuth de la cuenta.
26561
+ *
26562
+ * @param provider - Proveedor a desvincular
26563
+ */
26564
+ unlinkOAuthProvider(provider) {
26565
+ return this.oauthService.unlinkProvider(provider);
26566
+ }
26567
+ /**
26568
+ * Establece contraseña para usuarios que solo tienen OAuth.
26569
+ * Permite que usuarios OAuth-only puedan también usar email/password.
26570
+ *
26571
+ * @param password - Nueva contraseña
26572
+ */
26573
+ setPasswordForOAuthUser(password) {
26574
+ return this.oauthService.setPassword(password);
26575
+ }
26576
+ /**
26577
+ * Verifica si el usuario tiene contraseña establecida.
26578
+ * Útil para mostrar/ocultar opciones de cambio de contraseña.
26579
+ */
26580
+ checkHasPassword() {
26581
+ return this.oauthService.hasPassword();
26582
+ }
25403
26583
  /**
25404
26584
  * Registra un nuevo usuario.
25405
26585
  * El usuario queda en estado PENDING hasta verificar su email.
@@ -26093,7 +27273,7 @@ class AuthService {
26093
27273
  }
26094
27274
  return { platform: 'web', browser, os };
26095
27275
  }
26096
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthService, deps: [{ token: VALTECH_AUTH_CONFIG }, { token: i1$8.HttpClient }, { token: i1$1.Router }, { token: AuthStateService }, { token: TokenService }, { token: AuthStorageService }, { token: AuthSyncService }, { token: FirebaseService }, { token: MessagingService, optional: true }, { token: I18nService, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
27276
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthService, deps: [{ token: VALTECH_AUTH_CONFIG }, { token: i1$8.HttpClient }, { token: i1$1.Router }, { token: AuthStateService }, { token: TokenService }, { token: AuthStorageService }, { token: AuthSyncService }, { token: FirebaseService }, { token: OAuthService }, { token: MessagingService, optional: true }, { token: I18nService, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
26097
27277
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthService, providedIn: 'root' }); }
26098
27278
  }
26099
27279
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthService, decorators: [{
@@ -26102,7 +27282,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
26102
27282
  }], ctorParameters: () => [{ type: undefined, decorators: [{
26103
27283
  type: Inject,
26104
27284
  args: [VALTECH_AUTH_CONFIG]
26105
- }] }, { type: i1$8.HttpClient }, { type: i1$1.Router }, { type: AuthStateService }, { type: TokenService }, { type: AuthStorageService }, { type: AuthSyncService }, { type: FirebaseService }, { type: MessagingService, decorators: [{
27285
+ }] }, { type: i1$8.HttpClient }, { type: i1$1.Router }, { type: AuthStateService }, { type: TokenService }, { type: AuthStorageService }, { type: AuthSyncService }, { type: FirebaseService }, { type: OAuthService }, { type: MessagingService, decorators: [{
26106
27286
  type: Optional
26107
27287
  }] }, { type: I18nService, decorators: [{
26108
27288
  type: Optional
@@ -26301,6 +27481,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
26301
27481
  type: Optional
26302
27482
  }] }] });
26303
27483
 
27484
+ /**
27485
+ * Analytics Types
27486
+ *
27487
+ * Tipos e interfaces para el servicio de Firebase Analytics (GA4).
27488
+ */
27489
+
26304
27490
  /**
26305
27491
  * Firebase Services
26306
27492
  *
@@ -26725,6 +27911,144 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
26725
27911
  args: [VALTECH_AUTH_CONFIG]
26726
27912
  }] }, { type: i1$8.HttpClient }] });
26727
27913
 
27914
+ /**
27915
+ * Componente de callback para OAuth.
27916
+ *
27917
+ * Este componente procesa la respuesta del servidor OAuth y envía
27918
+ * los tokens a la ventana padre via postMessage.
27919
+ *
27920
+ * Debe agregarse a las rutas de la aplicación:
27921
+ * ```typescript
27922
+ * // app.routes.ts
27923
+ * import { OAuthCallbackComponent } from 'valtech-components';
27924
+ *
27925
+ * export const routes: Routes = [
27926
+ * { path: 'auth/oauth/callback', component: OAuthCallbackComponent },
27927
+ * // ... otras rutas
27928
+ * ];
27929
+ * ```
27930
+ *
27931
+ * El backend redirige a esta ruta con los tokens en query params:
27932
+ * `/auth/oauth/callback?access_token=xxx&refresh_token=xxx&expires_in=900`
27933
+ *
27934
+ * O con error:
27935
+ * `/auth/oauth/callback?error=INVALID_CODE&error_description=...`
27936
+ */
27937
+ class OAuthCallbackComponent {
27938
+ constructor() {
27939
+ this.message = 'Procesando autenticación...';
27940
+ }
27941
+ ngOnInit() {
27942
+ this.processCallback();
27943
+ }
27944
+ processCallback() {
27945
+ const params = new URLSearchParams(window.location.search);
27946
+ // Verificar si hay error
27947
+ const error = params.get('error');
27948
+ if (error) {
27949
+ this.sendToParent({
27950
+ type: 'oauth-callback',
27951
+ error: {
27952
+ code: error,
27953
+ message: params.get('error_description') || 'Error de autenticación',
27954
+ },
27955
+ });
27956
+ this.message = 'Error de autenticación';
27957
+ this.closeAfterDelay();
27958
+ return;
27959
+ }
27960
+ // Extraer tokens
27961
+ const accessToken = params.get('access_token');
27962
+ const refreshToken = params.get('refresh_token');
27963
+ const expiresIn = params.get('expires_in');
27964
+ const firebaseToken = params.get('firebase_token');
27965
+ if (!accessToken || !refreshToken) {
27966
+ this.sendToParent({
27967
+ type: 'oauth-callback',
27968
+ error: {
27969
+ code: 'MISSING_TOKENS',
27970
+ message: 'No se recibieron los tokens de autenticación',
27971
+ },
27972
+ });
27973
+ this.message = 'Error: tokens no recibidos';
27974
+ this.closeAfterDelay();
27975
+ return;
27976
+ }
27977
+ // Extraer roles y permisos (pueden venir como JSON en base64)
27978
+ let roles;
27979
+ let permissions;
27980
+ const rolesParam = params.get('roles');
27981
+ const permissionsParam = params.get('permissions');
27982
+ if (rolesParam) {
27983
+ try {
27984
+ roles = JSON.parse(atob(rolesParam));
27985
+ }
27986
+ catch {
27987
+ roles = rolesParam.split(',');
27988
+ }
27989
+ }
27990
+ if (permissionsParam) {
27991
+ try {
27992
+ permissions = JSON.parse(atob(permissionsParam));
27993
+ }
27994
+ catch {
27995
+ permissions = permissionsParam.split(',');
27996
+ }
27997
+ }
27998
+ // Enviar tokens a la ventana padre
27999
+ const result = {
28000
+ accessToken,
28001
+ refreshToken,
28002
+ expiresIn: expiresIn ? parseInt(expiresIn, 10) : 900,
28003
+ firebaseToken: firebaseToken || undefined,
28004
+ roles,
28005
+ permissions,
28006
+ isNewUser: params.get('is_new_user') === 'true',
28007
+ linked: params.get('linked') === 'true',
28008
+ };
28009
+ this.sendToParent({
28010
+ type: 'oauth-callback',
28011
+ tokens: result,
28012
+ });
28013
+ this.message = 'Autenticación exitosa';
28014
+ this.closeAfterDelay();
28015
+ }
28016
+ sendToParent(data) {
28017
+ if (window.opener) {
28018
+ // Enviar al opener (ventana que abrió el popup)
28019
+ window.opener.postMessage(data, window.location.origin);
28020
+ }
28021
+ else if (window.parent !== window) {
28022
+ // Enviar al parent (si estamos en iframe)
28023
+ window.parent.postMessage(data, window.location.origin);
28024
+ }
28025
+ }
28026
+ closeAfterDelay() {
28027
+ // Dar tiempo para que el mensaje se envíe antes de cerrar
28028
+ setTimeout(() => {
28029
+ if (window.opener) {
28030
+ window.close();
28031
+ }
28032
+ }, 500);
28033
+ }
28034
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OAuthCallbackComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
28035
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: OAuthCallbackComponent, isStandalone: true, selector: "val-oauth-callback", ngImport: i0, template: `
28036
+ <div class="oauth-callback">
28037
+ <div class="oauth-callback__spinner"></div>
28038
+ <p class="oauth-callback__text">{{ message }}</p>
28039
+ </div>
28040
+ `, isInline: true, styles: [".oauth-callback{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100vh;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.oauth-callback__spinner{width:40px;height:40px;border:3px solid #f3f3f3;border-top:3px solid #3498db;border-radius:50%;animation:spin 1s linear infinite;margin-bottom:16px}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.oauth-callback__text{color:#666;font-size:14px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
28041
+ }
28042
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OAuthCallbackComponent, decorators: [{
28043
+ type: Component,
28044
+ args: [{ selector: 'val-oauth-callback', standalone: true, imports: [CommonModule], template: `
28045
+ <div class="oauth-callback">
28046
+ <div class="oauth-callback__spinner"></div>
28047
+ <p class="oauth-callback__text">{{ message }}</p>
28048
+ </div>
28049
+ `, styles: [".oauth-callback{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100vh;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.oauth-callback__spinner{width:40px;height:40px;border:3px solid #f3f3f3;border-top:3px solid #3498db;border-radius:50%;animation:spin 1s linear infinite;margin-bottom:16px}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.oauth-callback__text{color:#666;font-size:14px}\n"] }]
28050
+ }] });
28051
+
26728
28052
  /**
26729
28053
  * Valtech Auth Service
26730
28054
  *
@@ -26953,5 +28277,5 @@ function provideValtechPresets(presets) {
26953
28277
  * Generated bundle index. Do not edit.
26954
28278
  */
26955
28279
 
26956
- export { ARTICLE_SPACING, AccordionComponent, ActionHeaderComponent, ActionType, AlertBoxComponent, ArticleBuilder, ArticleComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, BannerComponent, BaseDefault, BoxComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, CheckInputComponent, ChipGroupComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContentLoaderComponent, CountdownComponent, CurrencyInputComponent, DEFAULT_AUTH_CONFIG, DEFAULT_CANCEL_BUTTON, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_EMPTY_STATE, DEFAULT_LEGEND_LABELS, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PAYMENT_STATUS_COLORS, DEFAULT_PAYMENT_STATUS_LABELS, DEFAULT_PLATFORMS, DEFAULT_STATUS_COLORS, DEFAULT_STATUS_LABELS, DEFAULT_WINNER_LABELS, DataTableComponent, DateInputComponent, DateRangeInputComponent, DeviceService, DisplayComponent, DividerComponent, DownloadService, EmailInputComponent, ExpandableTextComponent, FabComponent, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FooterComponent, FooterLinksComponent, FormComponent, FormFooterComponent, FunHeaderComponent, GlowCardComponent, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, I18nService, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, Icon, IconComponent, IconService, ImageComponent, InAppBrowserService, InfoComponent, InputType, ItemListComponent, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LanguageSelectorComponent, LayeredCardComponent, LayoutComponent, LinkComponent, LinkProcessorService, LinksAccordionComponent, LinksCakeComponent, LocalStorageService, LocaleService, MODAL_SIZES, MOTION, MenuComponent, MessagingService, ModalService, MultiSelectSearchComponent, NavigationService, NoContentComponent, NotesBoxComponent, NotificationsService, NumberFromToComponent, NumberInputComponent, NumberStepperComponent, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PLATFORM_CONFIGS, PageContentComponent, PageTemplateComponent, PageWrapperComponent, PaginationComponent, ParticipantCardComponent, PasswordInputComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PresetService, PriceTagComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QueryBuilder, QuoteBoxComponent, RadioInputComponent, RaffleStatusCardComponent, RangeInputComponent, RatingComponent, RecapCardComponent, RightsFooterComponent, SKELETON_PRESETS, SearchSelectorComponent, SearchbarComponent, SecondarySolidBlockButton, SecondarySolidBlockHrefButton, SecondarySolidBlockIconButton, SecondarySolidBlockIconHrefButton, SecondarySolidDefaultRoundButton, SecondarySolidDefaultRoundHrefButton, SecondarySolidDefaultRoundIconButton, SecondarySolidDefaultRoundIconHrefButton, SecondarySolidFullButton, SecondarySolidFullHrefButton, SecondarySolidFullIconButton, SecondarySolidFullIconHrefButton, SecondarySolidLargeRoundButton, SecondarySolidLargeRoundHrefButton, SecondarySolidLargeRoundIconButton, SecondarySolidLargeRoundIconHrefButton, SecondarySolidSmallRoundButton, SecondarySolidSmallRoundHrefButton, SecondarySolidSmallRoundIconButton, SecondarySolidSmallRoundIconHrefButton, SegmentControlComponent, SelectSearchComponent, SessionService, ShareButtonsComponent, SimpleComponent, SkeletonComponent, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, TabbedContentComponent, TabsComponent, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TicketGridComponent, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TranslatePipe, TypedCollection, VALTECH_AUTH_CONFIG, VALTECH_FIREBASE_CONFIG, WinnerDisplayComponent, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, buildPath, collections, createFirebaseConfig, createGlowCardProps, createNumberFromToField, createTitleProps, extractPathParams, getCollectionPath, getDocumentId, goToTop, guestGuard, hasEmulators, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isValidPath, joinPath, maxLength, permissionGuard, permissionGuardFromRoute, provideValtechAuth, provideValtechAuthInterceptor, provideValtechFirebase, provideValtechI18n, provideValtechPresets, query, replaceSpecialChars, resolveColor, resolveInputDefaultValue, roleGuard, storagePaths, superAdminGuard };
28280
+ export { ARTICLE_SPACING, AccordionComponent, ActionHeaderComponent, ActionType, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, ArticleBuilder, ArticleComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, BannerComponent, BaseDefault, BoxComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, CheckInputComponent, ChipGroupComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContentLoaderComponent, CountdownComponent, CurrencyInputComponent, DEFAULT_AUTH_CONFIG, DEFAULT_CANCEL_BUTTON, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_EMPTY_STATE, DEFAULT_LEGEND_LABELS, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PAYMENT_STATUS_COLORS, DEFAULT_PAYMENT_STATUS_LABELS, DEFAULT_PLATFORMS, DEFAULT_STATUS_COLORS, DEFAULT_STATUS_LABELS, DEFAULT_WINNER_LABELS, DataTableComponent, DateInputComponent, DateRangeInputComponent, DeviceService, DisplayComponent, DividerComponent, DownloadService, EmailInputComponent, ExpandableTextComponent, FabComponent, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FooterComponent, FooterLinksComponent, FormComponent, FormFooterComponent, FunHeaderComponent, GlowCardComponent, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, I18nService, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, Icon, IconComponent, IconService, ImageComponent, InAppBrowserService, InfoComponent, InputType, ItemListComponent, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LanguageSelectorComponent, LayeredCardComponent, LayoutComponent, LinkComponent, LinkProcessorService, LinksAccordionComponent, LinksCakeComponent, LocalStorageService, LocaleService, MODAL_SIZES, MOTION, MenuComponent, MessagingService, ModalService, MultiSelectSearchComponent, NavigationService, NoContentComponent, NotesBoxComponent, NotificationsService, NumberFromToComponent, NumberInputComponent, NumberStepperComponent, OAuthCallbackComponent, OAuthService, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PLATFORM_CONFIGS, PageContentComponent, PageTemplateComponent, PageWrapperComponent, PaginationComponent, ParticipantCardComponent, PasswordInputComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PresetService, PriceTagComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QueryBuilder, QuoteBoxComponent, RadioInputComponent, RaffleStatusCardComponent, RangeInputComponent, RatingComponent, RecapCardComponent, RightsFooterComponent, SKELETON_PRESETS, SearchSelectorComponent, SearchbarComponent, SecondarySolidBlockButton, SecondarySolidBlockHrefButton, SecondarySolidBlockIconButton, SecondarySolidBlockIconHrefButton, SecondarySolidDefaultRoundButton, SecondarySolidDefaultRoundHrefButton, SecondarySolidDefaultRoundIconButton, SecondarySolidDefaultRoundIconHrefButton, SecondarySolidFullButton, SecondarySolidFullHrefButton, SecondarySolidFullIconButton, SecondarySolidFullIconHrefButton, SecondarySolidLargeRoundButton, SecondarySolidLargeRoundHrefButton, SecondarySolidLargeRoundIconButton, SecondarySolidLargeRoundIconHrefButton, SecondarySolidSmallRoundButton, SecondarySolidSmallRoundHrefButton, SecondarySolidSmallRoundIconButton, SecondarySolidSmallRoundIconHrefButton, SegmentControlComponent, SelectSearchComponent, SessionService, ShareButtonsComponent, SimpleComponent, SkeletonComponent, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, TabbedContentComponent, TabsComponent, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TicketGridComponent, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TranslatePipe, TypedCollection, VALTECH_AUTH_CONFIG, VALTECH_FIREBASE_CONFIG, WinnerDisplayComponent, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, buildPath, collections, createFirebaseConfig, createGlowCardProps, createNumberFromToField, createTitleProps, extractPathParams, getCollectionPath, getDocumentId, goToTop, guestGuard, hasEmulators, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isValidPath, joinPath, maxLength, permissionGuard, permissionGuardFromRoute, provideValtechAuth, provideValtechAuthInterceptor, provideValtechFirebase, provideValtechI18n, provideValtechPresets, query, replaceSpecialChars, resolveColor, resolveInputDefaultValue, roleGuard, storagePaths, superAdminGuard };
26957
28281
  //# sourceMappingURL=valtech-components.mjs.map