valtech-components 2.0.428 → 2.0.430

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.
Files changed (28) hide show
  1. package/esm2022/lib/components/organisms/data-table/data-table.component.mjs +17 -3
  2. package/esm2022/lib/components/organisms/data-table/types.mjs +1 -1
  3. package/esm2022/lib/services/auth/auth-state.service.mjs +173 -0
  4. package/esm2022/lib/services/auth/auth.service.mjs +432 -0
  5. package/esm2022/lib/services/auth/config.mjs +76 -0
  6. package/esm2022/lib/services/auth/guards.mjs +194 -0
  7. package/esm2022/lib/services/auth/index.mjs +70 -0
  8. package/esm2022/lib/services/auth/interceptor.mjs +98 -0
  9. package/esm2022/lib/services/auth/storage.service.mjs +138 -0
  10. package/esm2022/lib/services/auth/sync.service.mjs +146 -0
  11. package/esm2022/lib/services/auth/token.service.mjs +113 -0
  12. package/esm2022/lib/services/auth/types.mjs +29 -0
  13. package/esm2022/public-api.mjs +4 -1
  14. package/fesm2022/valtech-components.mjs +1465 -8
  15. package/fesm2022/valtech-components.mjs.map +1 -1
  16. package/lib/components/organisms/data-table/types.d.ts +8 -0
  17. package/lib/services/auth/auth-state.service.d.ts +85 -0
  18. package/lib/services/auth/auth.service.d.ts +123 -0
  19. package/lib/services/auth/config.d.ts +38 -0
  20. package/lib/services/auth/guards.d.ts +123 -0
  21. package/lib/services/auth/index.d.ts +63 -0
  22. package/lib/services/auth/interceptor.d.ts +22 -0
  23. package/lib/services/auth/storage.service.d.ts +48 -0
  24. package/lib/services/auth/sync.service.d.ts +49 -0
  25. package/lib/services/auth/token.service.d.ts +51 -0
  26. package/lib/services/auth/types.d.ts +264 -0
  27. package/package.json +1 -9
  28. package/public-api.d.ts +1 -0
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { EventEmitter, Component, Input, Output, Injectable, inject, HostListener, Pipe, ChangeDetectionStrategy, ViewChild, ChangeDetectorRef, ElementRef, InjectionToken, makeEnvironmentProviders, PLATFORM_ID, NgZone } from '@angular/core';
2
+ import { EventEmitter, Component, Input, Output, Injectable, inject, HostListener, Pipe, ChangeDetectionStrategy, ViewChild, ChangeDetectorRef, ElementRef, InjectionToken, makeEnvironmentProviders, PLATFORM_ID, NgZone, signal, computed, APP_INITIALIZER } 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, ModalController } from '@ionic/angular/standalone';
5
5
  import * as i1 from '@angular/common';
@@ -13,7 +13,7 @@ import * as i1$1 from '@angular/platform-browser';
13
13
  import QRCodeStyling from 'qr-code-styling';
14
14
  import * as i1$2 from '@angular/forms';
15
15
  import { ReactiveFormsModule, FormsModule, FormControl, Validators } from '@angular/forms';
16
- import { BehaviorSubject, filter, map, distinctUntilChanged, Subject } from 'rxjs';
16
+ import { BehaviorSubject, filter, map, distinctUntilChanged, Subject, firstValueFrom, throwError, of } from 'rxjs';
17
17
  import * as i1$3 from 'ng-otp-input';
18
18
  import { NgOtpInputComponent, NgOtpInputModule } from 'ng-otp-input';
19
19
  import * as i2 from '@ionic/angular';
@@ -32,6 +32,8 @@ import { provideAuth, getAuth, connectAuthEmulator, Auth, authState, signInWithC
32
32
  import { provideFirestore, getFirestore, connectFirestoreEmulator, enableIndexedDbPersistence, Firestore, doc, getDoc, collection, query as query$1, getDocs, limit, docData, collectionData, serverTimestamp, addDoc, setDoc, updateDoc, deleteDoc, writeBatch, arrayUnion, arrayRemove, increment, where, orderBy, startAfter, startAt, endBefore, endAt, Timestamp } from '@angular/fire/firestore';
33
33
  import { provideMessaging, getMessaging, Messaging, getToken, deleteToken, onMessage } from '@angular/fire/messaging';
34
34
  import { provideStorage, getStorage, connectStorageEmulator, Storage, ref, uploadBytesResumable, getDownloadURL, getMetadata, deleteObject, listAll } from '@angular/fire/storage';
35
+ import { HttpClient, provideHttpClient, withInterceptors } from '@angular/common/http';
36
+ import { tap, catchError, switchMap, finalize, filter as filter$1, take } from 'rxjs/operators';
35
37
 
36
38
  /**
37
39
  * val-avatar
@@ -18280,6 +18282,13 @@ class DataTableComponent {
18280
18282
  [class.hoverable]="props.hoverable !== false"
18281
18283
  [class.sticky-header]="props.stickyHeader"
18282
18284
  [class.responsive-cards]="props.responsiveMode === 'cards'"
18285
+ [class.elevation-none]="props.elevation === 'none'"
18286
+ [class.elevation-low]="props.elevation === 'low'"
18287
+ [class.elevation-high]="props.elevation === 'high'"
18288
+ [class.header-gradient]="props.headerGradient"
18289
+ [class.checkbox-circular]="props.checkboxStyle === 'circular'"
18290
+ [class.row-highlight-border]="props.rowHighlightStyle === 'border-left'"
18291
+ [class.row-highlight-both]="props.rowHighlightStyle === 'both'"
18283
18292
  [style.--max-height]="props.maxHeight"
18284
18293
  >
18285
18294
  <!-- Toolbar slot -->
@@ -18602,7 +18611,7 @@ class DataTableComponent {
18602
18611
  </div>
18603
18612
  }
18604
18613
  </div>
18605
- `, isInline: true, styles: [":host{display:block}.data-table-container{position:relative;background:var(--ion-background-color);border-radius:12px;box-shadow:0 1px 3px #00000014,0 1px 2px #0000000f;border:1px solid var(--ion-color-light-shade);overflow:hidden}.loading-overlay{position:absolute;inset:0;background:#fffc;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;z-index:10}.loading-message{font-size:14px;color:var(--ion-color-medium-shade)}.table-wrapper{overflow-x:auto;max-height:var(--max-height)}.table-wrapper.is-loading{opacity:.6;pointer-events:none}table{width:100%;border-collapse:collapse;font-size:14px}th,td{padding:12px 16px;text-align:left;vertical-align:middle}thead{background:var(--ion-color-light)}thead th{font-weight:500;font-size:12px;text-transform:uppercase;letter-spacing:.5px;color:var(--ion-color-medium-shade);white-space:nowrap;position:relative;border-bottom:2px solid var(--ion-color-light-shade)}thead th.sortable{cursor:pointer;-webkit-user-select:none;user-select:none;transition:background .15s ease}thead th.sortable:hover{background:var(--ion-color-light-tint)}thead th.sorted{color:var(--ion-color-primary);background:transparent}.header-content{display:flex;align-items:center;gap:8px}.sort-icons{display:flex;flex-direction:column;gap:0}.sort-icons ion-icon{font-size:12px;color:var(--ion-color-medium);margin:-2px 0}.sort-icons ion-icon.active{color:var(--ion-color-primary)}tbody tr{border-bottom:1px solid var(--ion-color-light-tint);transition:background .15s ease}tbody tr:last-child{border-bottom:none}tbody tr.clickable{cursor:pointer}tbody tr.selected{background:rgba(var(--ion-color-primary-rgb),.08)}tbody td{color:var(--ion-color-dark);font-size:14px}.align-left{text-align:left}.align-center{text-align:center}.align-right{text-align:right}.selection-cell{width:48px;text-align:center;padding:8px}.selection-cell ion-checkbox{margin:0}.selection-cell input[type=radio]{width:18px;height:18px;cursor:pointer}.row-number-cell{width:60px;text-align:center;color:var(--ion-color-medium);font-size:12px}.actions-cell{text-align:center;white-space:nowrap}.sticky-start{position:sticky;left:0;background:inherit;z-index:1}.sticky-end{position:sticky;right:0;background:inherit;z-index:1}.empty-row td{padding:48px 16px}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;color:var(--ion-color-medium)}.empty-icon{font-size:48px;margin-bottom:16px;opacity:.5}.empty-title{font-size:16px;font-weight:600;margin:0 0 8px;color:var(--ion-color-dark)}.empty-description{font-size:14px;margin:0;max-width:300px}.pagination-container{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-top:1px solid var(--ion-color-light-shade);background:var(--ion-color-light);flex-wrap:wrap;gap:12px}.pagination-info{display:flex;align-items:center;gap:16px;font-size:13px;color:var(--ion-color-medium-shade)}.page-size-select{--padding-start: 8px;--padding-end: 8px;font-size:13px;min-width:120px}.pagination-controls{display:flex;align-items:center;gap:4px}.pagination-controls ion-button{--padding-start: 8px;--padding-end: 8px}.page-indicator{padding:0 12px;font-size:13px;color:var(--ion-color-dark);font-weight:500}.bordered table,.bordered th,.bordered td{border:1px solid var(--ion-color-medium-tint)}.striped tbody tr:nth-child(2n){background:var(--ion-color-light-shade)}.striped tbody tr:nth-child(2n).selected{background:var(--ion-color-primary-tint)}.hoverable tbody tr:hover:not(.empty-row){background:var(--ion-color-light-tint)}.hoverable tbody tr:hover:not(.empty-row).selected{background:rgba(var(--ion-color-primary-rgb),.12)}.sticky-header .table-wrapper{overflow-y:auto}.sticky-header thead{position:sticky;top:0;z-index:5}.size-small th,.size-small td{padding:8px 12px;font-size:12px}.size-small .selection-cell{width:40px;padding:6px}.size-small .row-number-cell{width:48px;font-size:11px}.size-small .pagination-container{padding:8px 12px}.size-small .pagination-info,.size-small .page-indicator{font-size:12px}.size-large th,.size-large td{padding:16px 20px;font-size:15px}.size-large .selection-cell{width:56px;padding:12px}.size-large .row-number-cell{width:72px;font-size:14px}.size-large .pagination-container{padding:16px 20px}.size-large .pagination-info,.size-large .page-indicator{font-size:14px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media (max-width: 768px){.pagination-container{flex-direction:column;align-items:stretch}.pagination-info{justify-content:space-between}.pagination-controls{justify-content:center}}.table-toolbar{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:16px;border-bottom:1px solid var(--ion-color-light-shade);background:var(--ion-background-color);flex-wrap:wrap}.table-toolbar:empty{display:none}@media (max-width: 576px){.table-toolbar{flex-direction:column;align-items:stretch}}.status-badge{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:9999px;font-size:12px;font-weight:500;white-space:nowrap}.status-badge--success{background:rgba(var(--ion-color-success-rgb),.15);color:var(--ion-color-success-shade)}.status-badge--warning{background:rgba(var(--ion-color-warning-rgb),.15);color:var(--ion-color-warning-shade)}.status-badge--danger{background:rgba(var(--ion-color-danger-rgb),.15);color:var(--ion-color-danger-shade)}.status-badge--primary{background:rgba(var(--ion-color-primary-rgb),.15);color:var(--ion-color-primary-shade)}.status-badge--secondary{background:rgba(var(--ion-color-secondary-rgb),.15);color:var(--ion-color-secondary-shade)}.status-badge--medium{background:rgba(var(--ion-color-medium-rgb),.15);color:var(--ion-color-medium-shade)}.status-badge--tertiary{background:rgba(var(--ion-color-tertiary-rgb),.15);color:var(--ion-color-tertiary-shade)}.action-buttons{display:flex;gap:4px;justify-content:center}.action-buttons ion-button{--padding-start: 6px;--padding-end: 6px;margin:0}.action-buttons ion-button ion-icon{font-size:18px}.card-list{display:none;padding:8px;gap:12px}.data-card{background:var(--ion-background-color);border:1px solid var(--ion-color-light-shade);border-radius:12px;padding:16px;margin-bottom:12px}.data-card.selected{border-color:var(--ion-color-primary);background:rgba(var(--ion-color-primary-rgb),.04)}.data-card.clickable{cursor:pointer;transition:box-shadow .15s ease,transform .15s ease}.data-card.clickable:hover{box-shadow:0 4px 12px #0000001a;transform:translateY(-2px)}.card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid var(--ion-color-light-shade)}.card-selection{display:flex;align-items:center}.card-body{display:flex;flex-direction:column;gap:8px}.card-field{display:flex;justify-content:space-between;align-items:flex-start;gap:12px}.card-field__label{font-size:12px;font-weight:500;text-transform:uppercase;letter-spacing:.5px;color:var(--ion-color-medium-shade);flex-shrink:0}.card-field__value{font-size:14px;color:var(--ion-color-dark);text-align:right;word-break:break-word}.card-actions{display:flex;justify-content:flex-end;margin-top:12px;padding-top:12px;border-top:1px solid var(--ion-color-light-shade)}@media (max-width: 768px){.responsive-cards .table-wrapper{display:none}.responsive-cards .card-list{display:block}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonCheckbox, selector: "ion-checkbox", inputs: ["checked", "color", "disabled", "errorText", "helperText", "indeterminate", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonSelect, selector: "ion-select", inputs: ["cancelText", "color", "compareWith", "disabled", "errorText", "expandedIcon", "fill", "helperText", "interface", "interfaceOptions", "justify", "label", "labelPlacement", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "shape", "toggleIcon", "value"] }, { kind: "component", type: IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
18614
+ `, isInline: true, styles: [":host{display:block}.data-table-container{--dt-elevation-none: none;--dt-elevation-low: 0 1px 3px rgba(0, 0, 0, .08), 0 1px 2px rgba(0, 0, 0, .04);--dt-elevation-medium: 0 4px 6px -1px rgba(0, 0, 0, .1), 0 2px 4px -1px rgba(0, 0, 0, .06);--dt-elevation-high: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -2px rgba(0, 0, 0, .05);--dt-primary: var(--ion-color-primary, #4f46e5);--dt-primary-rgb: var(--ion-color-primary-rgb, 79, 70, 229);--dt-surface: var(--ion-background-color, #ffffff);--dt-surface-variant: #f8fafc;--dt-border: #e2e8f0;--dt-text-primary: #1e293b;--dt-text-secondary: #64748b;--dt-text-muted: #94a3b8;--dt-gradient-start: #6366f1;--dt-gradient-end: #8b5cf6;--dt-border-radius: 16px;--dt-cell-padding-x: 16px;--dt-cell-padding-y: 14px;--dt-header-padding-y: 12px}.data-table-container{position:relative;background:var(--dt-surface);border-radius:var(--dt-border-radius);box-shadow:var(--dt-elevation-medium);border:1px solid var(--dt-border);overflow:hidden}.data-table-container.elevation-none{box-shadow:var(--dt-elevation-none)}.data-table-container.elevation-low{box-shadow:var(--dt-elevation-low)}.data-table-container.elevation-high{box-shadow:var(--dt-elevation-high)}.data-table-container.header-gradient:before{content:\"\";position:absolute;top:0;left:0;right:0;height:4px;background:linear-gradient(90deg,var(--dt-gradient-start),var(--dt-gradient-end));border-radius:var(--dt-border-radius) var(--dt-border-radius) 0 0;z-index:2}.loading-overlay{position:absolute;inset:0;background:#ffffffe6;backdrop-filter:blur(2px);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;z-index:10}.loading-overlay ion-spinner{--color: var(--dt-primary);width:32px;height:32px}.loading-message{font-size:14px;font-weight:500;color:var(--dt-text-secondary)}.table-wrapper{overflow-x:auto;max-height:var(--max-height)}.table-wrapper.is-loading{opacity:.5;pointer-events:none}.table-wrapper::-webkit-scrollbar{height:8px;width:8px}.table-wrapper::-webkit-scrollbar-track{background:var(--dt-surface-variant);border-radius:4px}.table-wrapper::-webkit-scrollbar-thumb{background:var(--dt-border);border-radius:4px}.table-wrapper::-webkit-scrollbar-thumb:hover{background:var(--dt-text-muted)}table{width:100%;border-collapse:collapse;font-size:14px}th,td{padding:var(--dt-cell-padding-y) var(--dt-cell-padding-x);text-align:left;vertical-align:middle}thead{background:var(--dt-surface-variant)}thead th{font-weight:600;font-size:13px;color:var(--dt-text-secondary);white-space:nowrap;position:relative;border-bottom:1px solid var(--dt-border);padding:var(--dt-header-padding-y) var(--dt-cell-padding-x);transition:all .2s ease}thead th.sortable{cursor:pointer;-webkit-user-select:none;user-select:none}thead th.sortable:hover{background:#00000008;color:var(--dt-text-primary)}thead th.sorted{color:var(--dt-primary);background:rgba(var(--dt-primary-rgb),.04)}.header-content{display:flex;align-items:center;gap:8px}.sort-icons{display:flex;flex-direction:column;gap:0;opacity:.4;transition:opacity .2s ease}.sortable:hover .sort-icons{opacity:.7}.sorted .sort-icons{opacity:1}.sort-icons ion-icon{font-size:12px;color:var(--dt-text-muted);margin:-3px 0;transition:all .2s ease}.sort-icons ion-icon.active{color:var(--dt-primary);transform:scale(1.2)}tbody tr{border-bottom:1px solid var(--dt-border);transition:all .2s ease;position:relative}tbody tr:last-child{border-bottom:none}tbody tr.clickable{cursor:pointer}tbody tr.selected{background:rgba(var(--dt-primary-rgb),.06)}tbody tr.selected:before{content:\"\";position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--dt-primary)}tbody td{color:var(--dt-text-primary);font-size:14px}.row-highlight-border tbody tr.selected{background:transparent}.row-highlight-border tbody tr.selected:before{width:4px}.row-highlight-both tbody tr.selected:before{width:4px}.hoverable tbody tr:hover:not(.empty-row){background:var(--dt-surface-variant)}.hoverable tbody tr:hover:not(.empty-row).selected{background:rgba(var(--dt-primary-rgb),.08)}.align-left{text-align:left}.align-center{text-align:center}.align-right{text-align:right}.selection-cell{width:52px;text-align:center;padding:8px 12px}.selection-cell ion-checkbox{--size: 20px;--border-radius: 50%;--border-width: 2px;--border-color: var(--dt-border);--border-color-checked: var(--dt-primary);--background: transparent;--background-checked: var(--dt-primary);--checkmark-color: white;--checkmark-width: 2px;margin:0;transition:transform .15s ease}.selection-cell ion-checkbox:hover{transform:scale(1.1)}.selection-cell ion-checkbox::part(container){border-radius:50%}.selection-cell input[type=radio]{width:20px;height:20px;cursor:pointer;accent-color:var(--dt-primary)}.checkbox-circular .selection-cell ion-checkbox{--border-radius: 50%}.checkbox-circular .selection-cell ion-checkbox::part(container){border-radius:50%}.row-number-cell{width:60px;text-align:center;color:var(--dt-text-muted);font-size:12px;font-weight:500}.actions-cell{text-align:center;white-space:nowrap}.sticky-start{position:sticky;left:0;background:inherit;z-index:1;box-shadow:2px 0 4px #0000000d}.sticky-end{position:sticky;right:0;background:inherit;z-index:1;box-shadow:-2px 0 4px #0000000d}.empty-row td{padding:64px 16px}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;color:var(--dt-text-secondary)}.empty-icon{font-size:56px;margin-bottom:20px;opacity:.4;color:var(--dt-text-muted)}.empty-title{font-size:18px;font-weight:600;margin:0 0 8px;color:var(--dt-text-primary)}.empty-description{font-size:14px;margin:0;max-width:320px;color:var(--dt-text-secondary);line-height:1.5}.pagination-container{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-top:1px solid var(--dt-border);background:var(--dt-surface);flex-wrap:wrap;gap:16px}.pagination-info{display:flex;align-items:center;gap:20px;font-size:14px;color:var(--dt-text-secondary)}.pagination-info span{font-weight:500}.page-size-select{--padding-start: 12px;--padding-end: 12px;font-size:14px;min-width:140px;--background: var(--dt-surface-variant);--border-radius: 8px}.pagination-controls{display:flex;align-items:center;gap:8px}.pagination-controls ion-button{--padding-start: 10px;--padding-end: 10px;--border-radius: 8px;--background: var(--dt-surface-variant);--background-hover: var(--dt-border);--color: var(--dt-text-secondary);--color-hover: var(--dt-text-primary);margin:0;height:36px;min-width:36px}.pagination-controls ion-button:disabled{opacity:.4}.pagination-controls ion-button ion-icon{font-size:16px}.page-indicator{padding:0 16px;font-size:14px;color:var(--dt-text-primary);font-weight:600;background:var(--dt-surface-variant);border-radius:8px;height:36px;display:flex;align-items:center;min-width:80px;justify-content:center}.bordered th,.bordered td{border:1px solid var(--dt-border)}.striped tbody tr:nth-child(2n){background:var(--dt-surface-variant)}.striped tbody tr:nth-child(2n).selected{background:rgba(var(--dt-primary-rgb),.08)}.sticky-header .table-wrapper{overflow-y:auto}.sticky-header thead{position:sticky;top:0;z-index:5;box-shadow:0 1px 0 var(--dt-border)}.size-small{--dt-cell-padding-x: 12px;--dt-cell-padding-y: 10px;--dt-header-padding-y: 10px}.size-small th,.size-small td{font-size:13px}.size-small thead th{font-size:12px}.size-small .selection-cell{width:44px;padding:6px 8px}.size-small .selection-cell ion-checkbox{--size: 18px}.size-small .row-number-cell{width:48px;font-size:11px}.size-small .pagination-container{padding:12px 16px}.size-small .pagination-info,.size-small .page-indicator{font-size:13px}.size-small .pagination-controls ion-button{height:32px;min-width:32px}.size-small .page-indicator{height:32px;min-width:70px}.size-large{--dt-cell-padding-x: 20px;--dt-cell-padding-y: 18px;--dt-header-padding-y: 16px}.size-large th,.size-large td{font-size:15px}.size-large thead th{font-size:14px}.size-large .selection-cell{width:60px;padding:12px 16px}.size-large .selection-cell ion-checkbox{--size: 24px}.size-large .row-number-cell{width:72px;font-size:14px}.size-large .pagination-container{padding:20px 24px}.size-large .pagination-info,.size-large .page-indicator{font-size:15px}.size-large .pagination-controls ion-button{height:40px;min-width:40px}.size-large .page-indicator{height:40px;min-width:90px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media (max-width: 768px){.data-table-container{--dt-border-radius: 12px}.pagination-container{flex-direction:column;align-items:stretch;gap:12px}.pagination-info{justify-content:space-between}.pagination-controls{justify-content:center}}.table-toolbar{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:20px;border-bottom:1px solid var(--dt-border);background:var(--dt-surface);flex-wrap:wrap}.table-toolbar:empty{display:none}@media (max-width: 576px){.table-toolbar{flex-direction:column;align-items:stretch;padding:16px}}.status-badge{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border-radius:9999px;font-size:12px;font-weight:600;white-space:nowrap;letter-spacing:.025em}.status-badge--success{background:#dcfce7;color:#15803d}.status-badge--warning{background:#fef3c7;color:#b45309}.status-badge--danger{background:#fee2e2;color:#dc2626}.status-badge--primary{background:#e0e7ff;color:#4338ca}.status-badge--secondary{background:#f1f5f9;color:#475569}.status-badge--medium{background:#f1f5f9;color:#64748b}.status-badge--tertiary{background:#f3e8ff;color:#7c3aed}.status-badge--filled.status-badge--success{background:#22c55e;color:#fff}.status-badge--filled.status-badge--warning{background:#f59e0b;color:#fff}.status-badge--filled.status-badge--danger{background:#ef4444;color:#fff}.status-badge--filled.status-badge--primary{background:var(--dt-primary);color:#fff}.status-badge--outlined{background:transparent;border:1.5px solid currentColor}.status-badge--outlined.status-badge--success{color:#16a34a}.status-badge--outlined.status-badge--warning{color:#d97706}.status-badge--outlined.status-badge--danger{color:#dc2626}.status-badge--outlined.status-badge--primary{color:var(--dt-primary)}.action-buttons{display:flex;gap:6px;justify-content:center}.action-buttons ion-button{--padding-start: 8px;--padding-end: 8px;--border-radius: 8px;margin:0}.action-buttons ion-button ion-icon{font-size:18px}.card-list{display:none;padding:12px;gap:12px}.data-card{background:var(--dt-surface);border:1px solid var(--dt-border);border-radius:12px;padding:16px;margin-bottom:12px;transition:all .2s ease}.data-card.selected{border-color:var(--dt-primary);background:rgba(var(--dt-primary-rgb),.04);box-shadow:0 0 0 1px var(--dt-primary)}.data-card.clickable{cursor:pointer}.data-card.clickable:hover{box-shadow:var(--dt-elevation-medium);transform:translateY(-2px)}.data-card.clickable:active{transform:translateY(0)}.card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;padding-bottom:12px;border-bottom:1px solid var(--dt-border)}.card-selection{display:flex;align-items:center}.card-body{display:flex;flex-direction:column;gap:12px}.card-field{display:flex;justify-content:space-between;align-items:flex-start;gap:16px}.card-field__label{font-size:12px;font-weight:600;color:var(--dt-text-muted);flex-shrink:0}.card-field__value{font-size:14px;color:var(--dt-text-primary);text-align:right;word-break:break-word;font-weight:500}.card-actions{display:flex;justify-content:flex-end;margin-top:16px;padding-top:12px;border-top:1px solid var(--dt-border)}@media (max-width: 768px){.responsive-cards .table-wrapper{display:none}.responsive-cards .card-list{display:block}}@media (prefers-color-scheme: dark){.data-table-container{--dt-surface: #1e293b;--dt-surface-variant: #334155;--dt-border: #475569;--dt-text-primary: #f1f5f9;--dt-text-secondary: #94a3b8;--dt-text-muted: #64748b}.loading-overlay{background:#1e293be6}.status-badge--success{background:#22c55e33;color:#4ade80}.status-badge--warning{background:#f59e0b33;color:#fbbf24}.status-badge--danger{background:#ef444433;color:#f87171}.status-badge--primary{background:#6366f133;color:#a5b4fc}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonCheckbox, selector: "ion-checkbox", inputs: ["checked", "color", "disabled", "errorText", "helperText", "indeterminate", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonSelect, selector: "ion-select", inputs: ["cancelText", "color", "compareWith", "disabled", "errorText", "expandedIcon", "fill", "helperText", "interface", "interfaceOptions", "justify", "label", "labelPlacement", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "shape", "toggleIcon", "value"] }, { kind: "component", type: IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
18606
18615
  }
18607
18616
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DataTableComponent, decorators: [{
18608
18617
  type: Component,
@@ -18627,6 +18636,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
18627
18636
  [class.hoverable]="props.hoverable !== false"
18628
18637
  [class.sticky-header]="props.stickyHeader"
18629
18638
  [class.responsive-cards]="props.responsiveMode === 'cards'"
18639
+ [class.elevation-none]="props.elevation === 'none'"
18640
+ [class.elevation-low]="props.elevation === 'low'"
18641
+ [class.elevation-high]="props.elevation === 'high'"
18642
+ [class.header-gradient]="props.headerGradient"
18643
+ [class.checkbox-circular]="props.checkboxStyle === 'circular'"
18644
+ [class.row-highlight-border]="props.rowHighlightStyle === 'border-left'"
18645
+ [class.row-highlight-both]="props.rowHighlightStyle === 'both'"
18630
18646
  [style.--max-height]="props.maxHeight"
18631
18647
  >
18632
18648
  <!-- Toolbar slot -->
@@ -18949,7 +18965,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
18949
18965
  </div>
18950
18966
  }
18951
18967
  </div>
18952
- `, styles: [":host{display:block}.data-table-container{position:relative;background:var(--ion-background-color);border-radius:12px;box-shadow:0 1px 3px #00000014,0 1px 2px #0000000f;border:1px solid var(--ion-color-light-shade);overflow:hidden}.loading-overlay{position:absolute;inset:0;background:#fffc;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;z-index:10}.loading-message{font-size:14px;color:var(--ion-color-medium-shade)}.table-wrapper{overflow-x:auto;max-height:var(--max-height)}.table-wrapper.is-loading{opacity:.6;pointer-events:none}table{width:100%;border-collapse:collapse;font-size:14px}th,td{padding:12px 16px;text-align:left;vertical-align:middle}thead{background:var(--ion-color-light)}thead th{font-weight:500;font-size:12px;text-transform:uppercase;letter-spacing:.5px;color:var(--ion-color-medium-shade);white-space:nowrap;position:relative;border-bottom:2px solid var(--ion-color-light-shade)}thead th.sortable{cursor:pointer;-webkit-user-select:none;user-select:none;transition:background .15s ease}thead th.sortable:hover{background:var(--ion-color-light-tint)}thead th.sorted{color:var(--ion-color-primary);background:transparent}.header-content{display:flex;align-items:center;gap:8px}.sort-icons{display:flex;flex-direction:column;gap:0}.sort-icons ion-icon{font-size:12px;color:var(--ion-color-medium);margin:-2px 0}.sort-icons ion-icon.active{color:var(--ion-color-primary)}tbody tr{border-bottom:1px solid var(--ion-color-light-tint);transition:background .15s ease}tbody tr:last-child{border-bottom:none}tbody tr.clickable{cursor:pointer}tbody tr.selected{background:rgba(var(--ion-color-primary-rgb),.08)}tbody td{color:var(--ion-color-dark);font-size:14px}.align-left{text-align:left}.align-center{text-align:center}.align-right{text-align:right}.selection-cell{width:48px;text-align:center;padding:8px}.selection-cell ion-checkbox{margin:0}.selection-cell input[type=radio]{width:18px;height:18px;cursor:pointer}.row-number-cell{width:60px;text-align:center;color:var(--ion-color-medium);font-size:12px}.actions-cell{text-align:center;white-space:nowrap}.sticky-start{position:sticky;left:0;background:inherit;z-index:1}.sticky-end{position:sticky;right:0;background:inherit;z-index:1}.empty-row td{padding:48px 16px}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;color:var(--ion-color-medium)}.empty-icon{font-size:48px;margin-bottom:16px;opacity:.5}.empty-title{font-size:16px;font-weight:600;margin:0 0 8px;color:var(--ion-color-dark)}.empty-description{font-size:14px;margin:0;max-width:300px}.pagination-container{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-top:1px solid var(--ion-color-light-shade);background:var(--ion-color-light);flex-wrap:wrap;gap:12px}.pagination-info{display:flex;align-items:center;gap:16px;font-size:13px;color:var(--ion-color-medium-shade)}.page-size-select{--padding-start: 8px;--padding-end: 8px;font-size:13px;min-width:120px}.pagination-controls{display:flex;align-items:center;gap:4px}.pagination-controls ion-button{--padding-start: 8px;--padding-end: 8px}.page-indicator{padding:0 12px;font-size:13px;color:var(--ion-color-dark);font-weight:500}.bordered table,.bordered th,.bordered td{border:1px solid var(--ion-color-medium-tint)}.striped tbody tr:nth-child(2n){background:var(--ion-color-light-shade)}.striped tbody tr:nth-child(2n).selected{background:var(--ion-color-primary-tint)}.hoverable tbody tr:hover:not(.empty-row){background:var(--ion-color-light-tint)}.hoverable tbody tr:hover:not(.empty-row).selected{background:rgba(var(--ion-color-primary-rgb),.12)}.sticky-header .table-wrapper{overflow-y:auto}.sticky-header thead{position:sticky;top:0;z-index:5}.size-small th,.size-small td{padding:8px 12px;font-size:12px}.size-small .selection-cell{width:40px;padding:6px}.size-small .row-number-cell{width:48px;font-size:11px}.size-small .pagination-container{padding:8px 12px}.size-small .pagination-info,.size-small .page-indicator{font-size:12px}.size-large th,.size-large td{padding:16px 20px;font-size:15px}.size-large .selection-cell{width:56px;padding:12px}.size-large .row-number-cell{width:72px;font-size:14px}.size-large .pagination-container{padding:16px 20px}.size-large .pagination-info,.size-large .page-indicator{font-size:14px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media (max-width: 768px){.pagination-container{flex-direction:column;align-items:stretch}.pagination-info{justify-content:space-between}.pagination-controls{justify-content:center}}.table-toolbar{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:16px;border-bottom:1px solid var(--ion-color-light-shade);background:var(--ion-background-color);flex-wrap:wrap}.table-toolbar:empty{display:none}@media (max-width: 576px){.table-toolbar{flex-direction:column;align-items:stretch}}.status-badge{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:9999px;font-size:12px;font-weight:500;white-space:nowrap}.status-badge--success{background:rgba(var(--ion-color-success-rgb),.15);color:var(--ion-color-success-shade)}.status-badge--warning{background:rgba(var(--ion-color-warning-rgb),.15);color:var(--ion-color-warning-shade)}.status-badge--danger{background:rgba(var(--ion-color-danger-rgb),.15);color:var(--ion-color-danger-shade)}.status-badge--primary{background:rgba(var(--ion-color-primary-rgb),.15);color:var(--ion-color-primary-shade)}.status-badge--secondary{background:rgba(var(--ion-color-secondary-rgb),.15);color:var(--ion-color-secondary-shade)}.status-badge--medium{background:rgba(var(--ion-color-medium-rgb),.15);color:var(--ion-color-medium-shade)}.status-badge--tertiary{background:rgba(var(--ion-color-tertiary-rgb),.15);color:var(--ion-color-tertiary-shade)}.action-buttons{display:flex;gap:4px;justify-content:center}.action-buttons ion-button{--padding-start: 6px;--padding-end: 6px;margin:0}.action-buttons ion-button ion-icon{font-size:18px}.card-list{display:none;padding:8px;gap:12px}.data-card{background:var(--ion-background-color);border:1px solid var(--ion-color-light-shade);border-radius:12px;padding:16px;margin-bottom:12px}.data-card.selected{border-color:var(--ion-color-primary);background:rgba(var(--ion-color-primary-rgb),.04)}.data-card.clickable{cursor:pointer;transition:box-shadow .15s ease,transform .15s ease}.data-card.clickable:hover{box-shadow:0 4px 12px #0000001a;transform:translateY(-2px)}.card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid var(--ion-color-light-shade)}.card-selection{display:flex;align-items:center}.card-body{display:flex;flex-direction:column;gap:8px}.card-field{display:flex;justify-content:space-between;align-items:flex-start;gap:12px}.card-field__label{font-size:12px;font-weight:500;text-transform:uppercase;letter-spacing:.5px;color:var(--ion-color-medium-shade);flex-shrink:0}.card-field__value{font-size:14px;color:var(--ion-color-dark);text-align:right;word-break:break-word}.card-actions{display:flex;justify-content:flex-end;margin-top:12px;padding-top:12px;border-top:1px solid var(--ion-color-light-shade)}@media (max-width: 768px){.responsive-cards .table-wrapper{display:none}.responsive-cards .card-list{display:block}}\n"] }]
18968
+ `, styles: [":host{display:block}.data-table-container{--dt-elevation-none: none;--dt-elevation-low: 0 1px 3px rgba(0, 0, 0, .08), 0 1px 2px rgba(0, 0, 0, .04);--dt-elevation-medium: 0 4px 6px -1px rgba(0, 0, 0, .1), 0 2px 4px -1px rgba(0, 0, 0, .06);--dt-elevation-high: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -2px rgba(0, 0, 0, .05);--dt-primary: var(--ion-color-primary, #4f46e5);--dt-primary-rgb: var(--ion-color-primary-rgb, 79, 70, 229);--dt-surface: var(--ion-background-color, #ffffff);--dt-surface-variant: #f8fafc;--dt-border: #e2e8f0;--dt-text-primary: #1e293b;--dt-text-secondary: #64748b;--dt-text-muted: #94a3b8;--dt-gradient-start: #6366f1;--dt-gradient-end: #8b5cf6;--dt-border-radius: 16px;--dt-cell-padding-x: 16px;--dt-cell-padding-y: 14px;--dt-header-padding-y: 12px}.data-table-container{position:relative;background:var(--dt-surface);border-radius:var(--dt-border-radius);box-shadow:var(--dt-elevation-medium);border:1px solid var(--dt-border);overflow:hidden}.data-table-container.elevation-none{box-shadow:var(--dt-elevation-none)}.data-table-container.elevation-low{box-shadow:var(--dt-elevation-low)}.data-table-container.elevation-high{box-shadow:var(--dt-elevation-high)}.data-table-container.header-gradient:before{content:\"\";position:absolute;top:0;left:0;right:0;height:4px;background:linear-gradient(90deg,var(--dt-gradient-start),var(--dt-gradient-end));border-radius:var(--dt-border-radius) var(--dt-border-radius) 0 0;z-index:2}.loading-overlay{position:absolute;inset:0;background:#ffffffe6;backdrop-filter:blur(2px);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;z-index:10}.loading-overlay ion-spinner{--color: var(--dt-primary);width:32px;height:32px}.loading-message{font-size:14px;font-weight:500;color:var(--dt-text-secondary)}.table-wrapper{overflow-x:auto;max-height:var(--max-height)}.table-wrapper.is-loading{opacity:.5;pointer-events:none}.table-wrapper::-webkit-scrollbar{height:8px;width:8px}.table-wrapper::-webkit-scrollbar-track{background:var(--dt-surface-variant);border-radius:4px}.table-wrapper::-webkit-scrollbar-thumb{background:var(--dt-border);border-radius:4px}.table-wrapper::-webkit-scrollbar-thumb:hover{background:var(--dt-text-muted)}table{width:100%;border-collapse:collapse;font-size:14px}th,td{padding:var(--dt-cell-padding-y) var(--dt-cell-padding-x);text-align:left;vertical-align:middle}thead{background:var(--dt-surface-variant)}thead th{font-weight:600;font-size:13px;color:var(--dt-text-secondary);white-space:nowrap;position:relative;border-bottom:1px solid var(--dt-border);padding:var(--dt-header-padding-y) var(--dt-cell-padding-x);transition:all .2s ease}thead th.sortable{cursor:pointer;-webkit-user-select:none;user-select:none}thead th.sortable:hover{background:#00000008;color:var(--dt-text-primary)}thead th.sorted{color:var(--dt-primary);background:rgba(var(--dt-primary-rgb),.04)}.header-content{display:flex;align-items:center;gap:8px}.sort-icons{display:flex;flex-direction:column;gap:0;opacity:.4;transition:opacity .2s ease}.sortable:hover .sort-icons{opacity:.7}.sorted .sort-icons{opacity:1}.sort-icons ion-icon{font-size:12px;color:var(--dt-text-muted);margin:-3px 0;transition:all .2s ease}.sort-icons ion-icon.active{color:var(--dt-primary);transform:scale(1.2)}tbody tr{border-bottom:1px solid var(--dt-border);transition:all .2s ease;position:relative}tbody tr:last-child{border-bottom:none}tbody tr.clickable{cursor:pointer}tbody tr.selected{background:rgba(var(--dt-primary-rgb),.06)}tbody tr.selected:before{content:\"\";position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--dt-primary)}tbody td{color:var(--dt-text-primary);font-size:14px}.row-highlight-border tbody tr.selected{background:transparent}.row-highlight-border tbody tr.selected:before{width:4px}.row-highlight-both tbody tr.selected:before{width:4px}.hoverable tbody tr:hover:not(.empty-row){background:var(--dt-surface-variant)}.hoverable tbody tr:hover:not(.empty-row).selected{background:rgba(var(--dt-primary-rgb),.08)}.align-left{text-align:left}.align-center{text-align:center}.align-right{text-align:right}.selection-cell{width:52px;text-align:center;padding:8px 12px}.selection-cell ion-checkbox{--size: 20px;--border-radius: 50%;--border-width: 2px;--border-color: var(--dt-border);--border-color-checked: var(--dt-primary);--background: transparent;--background-checked: var(--dt-primary);--checkmark-color: white;--checkmark-width: 2px;margin:0;transition:transform .15s ease}.selection-cell ion-checkbox:hover{transform:scale(1.1)}.selection-cell ion-checkbox::part(container){border-radius:50%}.selection-cell input[type=radio]{width:20px;height:20px;cursor:pointer;accent-color:var(--dt-primary)}.checkbox-circular .selection-cell ion-checkbox{--border-radius: 50%}.checkbox-circular .selection-cell ion-checkbox::part(container){border-radius:50%}.row-number-cell{width:60px;text-align:center;color:var(--dt-text-muted);font-size:12px;font-weight:500}.actions-cell{text-align:center;white-space:nowrap}.sticky-start{position:sticky;left:0;background:inherit;z-index:1;box-shadow:2px 0 4px #0000000d}.sticky-end{position:sticky;right:0;background:inherit;z-index:1;box-shadow:-2px 0 4px #0000000d}.empty-row td{padding:64px 16px}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;color:var(--dt-text-secondary)}.empty-icon{font-size:56px;margin-bottom:20px;opacity:.4;color:var(--dt-text-muted)}.empty-title{font-size:18px;font-weight:600;margin:0 0 8px;color:var(--dt-text-primary)}.empty-description{font-size:14px;margin:0;max-width:320px;color:var(--dt-text-secondary);line-height:1.5}.pagination-container{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-top:1px solid var(--dt-border);background:var(--dt-surface);flex-wrap:wrap;gap:16px}.pagination-info{display:flex;align-items:center;gap:20px;font-size:14px;color:var(--dt-text-secondary)}.pagination-info span{font-weight:500}.page-size-select{--padding-start: 12px;--padding-end: 12px;font-size:14px;min-width:140px;--background: var(--dt-surface-variant);--border-radius: 8px}.pagination-controls{display:flex;align-items:center;gap:8px}.pagination-controls ion-button{--padding-start: 10px;--padding-end: 10px;--border-radius: 8px;--background: var(--dt-surface-variant);--background-hover: var(--dt-border);--color: var(--dt-text-secondary);--color-hover: var(--dt-text-primary);margin:0;height:36px;min-width:36px}.pagination-controls ion-button:disabled{opacity:.4}.pagination-controls ion-button ion-icon{font-size:16px}.page-indicator{padding:0 16px;font-size:14px;color:var(--dt-text-primary);font-weight:600;background:var(--dt-surface-variant);border-radius:8px;height:36px;display:flex;align-items:center;min-width:80px;justify-content:center}.bordered th,.bordered td{border:1px solid var(--dt-border)}.striped tbody tr:nth-child(2n){background:var(--dt-surface-variant)}.striped tbody tr:nth-child(2n).selected{background:rgba(var(--dt-primary-rgb),.08)}.sticky-header .table-wrapper{overflow-y:auto}.sticky-header thead{position:sticky;top:0;z-index:5;box-shadow:0 1px 0 var(--dt-border)}.size-small{--dt-cell-padding-x: 12px;--dt-cell-padding-y: 10px;--dt-header-padding-y: 10px}.size-small th,.size-small td{font-size:13px}.size-small thead th{font-size:12px}.size-small .selection-cell{width:44px;padding:6px 8px}.size-small .selection-cell ion-checkbox{--size: 18px}.size-small .row-number-cell{width:48px;font-size:11px}.size-small .pagination-container{padding:12px 16px}.size-small .pagination-info,.size-small .page-indicator{font-size:13px}.size-small .pagination-controls ion-button{height:32px;min-width:32px}.size-small .page-indicator{height:32px;min-width:70px}.size-large{--dt-cell-padding-x: 20px;--dt-cell-padding-y: 18px;--dt-header-padding-y: 16px}.size-large th,.size-large td{font-size:15px}.size-large thead th{font-size:14px}.size-large .selection-cell{width:60px;padding:12px 16px}.size-large .selection-cell ion-checkbox{--size: 24px}.size-large .row-number-cell{width:72px;font-size:14px}.size-large .pagination-container{padding:20px 24px}.size-large .pagination-info,.size-large .page-indicator{font-size:15px}.size-large .pagination-controls ion-button{height:40px;min-width:40px}.size-large .page-indicator{height:40px;min-width:90px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media (max-width: 768px){.data-table-container{--dt-border-radius: 12px}.pagination-container{flex-direction:column;align-items:stretch;gap:12px}.pagination-info{justify-content:space-between}.pagination-controls{justify-content:center}}.table-toolbar{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:20px;border-bottom:1px solid var(--dt-border);background:var(--dt-surface);flex-wrap:wrap}.table-toolbar:empty{display:none}@media (max-width: 576px){.table-toolbar{flex-direction:column;align-items:stretch;padding:16px}}.status-badge{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border-radius:9999px;font-size:12px;font-weight:600;white-space:nowrap;letter-spacing:.025em}.status-badge--success{background:#dcfce7;color:#15803d}.status-badge--warning{background:#fef3c7;color:#b45309}.status-badge--danger{background:#fee2e2;color:#dc2626}.status-badge--primary{background:#e0e7ff;color:#4338ca}.status-badge--secondary{background:#f1f5f9;color:#475569}.status-badge--medium{background:#f1f5f9;color:#64748b}.status-badge--tertiary{background:#f3e8ff;color:#7c3aed}.status-badge--filled.status-badge--success{background:#22c55e;color:#fff}.status-badge--filled.status-badge--warning{background:#f59e0b;color:#fff}.status-badge--filled.status-badge--danger{background:#ef4444;color:#fff}.status-badge--filled.status-badge--primary{background:var(--dt-primary);color:#fff}.status-badge--outlined{background:transparent;border:1.5px solid currentColor}.status-badge--outlined.status-badge--success{color:#16a34a}.status-badge--outlined.status-badge--warning{color:#d97706}.status-badge--outlined.status-badge--danger{color:#dc2626}.status-badge--outlined.status-badge--primary{color:var(--dt-primary)}.action-buttons{display:flex;gap:6px;justify-content:center}.action-buttons ion-button{--padding-start: 8px;--padding-end: 8px;--border-radius: 8px;margin:0}.action-buttons ion-button ion-icon{font-size:18px}.card-list{display:none;padding:12px;gap:12px}.data-card{background:var(--dt-surface);border:1px solid var(--dt-border);border-radius:12px;padding:16px;margin-bottom:12px;transition:all .2s ease}.data-card.selected{border-color:var(--dt-primary);background:rgba(var(--dt-primary-rgb),.04);box-shadow:0 0 0 1px var(--dt-primary)}.data-card.clickable{cursor:pointer}.data-card.clickable:hover{box-shadow:var(--dt-elevation-medium);transform:translateY(-2px)}.data-card.clickable:active{transform:translateY(0)}.card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;padding-bottom:12px;border-bottom:1px solid var(--dt-border)}.card-selection{display:flex;align-items:center}.card-body{display:flex;flex-direction:column;gap:12px}.card-field{display:flex;justify-content:space-between;align-items:flex-start;gap:16px}.card-field__label{font-size:12px;font-weight:600;color:var(--dt-text-muted);flex-shrink:0}.card-field__value{font-size:14px;color:var(--dt-text-primary);text-align:right;word-break:break-word;font-weight:500}.card-actions{display:flex;justify-content:flex-end;margin-top:16px;padding-top:12px;border-top:1px solid var(--dt-border)}@media (max-width: 768px){.responsive-cards .table-wrapper{display:none}.responsive-cards .card-list{display:block}}@media (prefers-color-scheme: dark){.data-table-container{--dt-surface: #1e293b;--dt-surface-variant: #334155;--dt-border: #475569;--dt-text-primary: #f1f5f9;--dt-text-secondary: #94a3b8;--dt-text-muted: #64748b}.loading-overlay{background:#1e293be6}.status-badge--success{background:#22c55e33;color:#4ade80}.status-badge--warning{background:#f59e0b33;color:#fbbf24}.status-badge--danger{background:#ef444433;color:#f87171}.status-badge--primary{background:#6366f133;color:#a5b4fc}}\n"] }]
18953
18969
  }], propDecorators: { props: [{
18954
18970
  type: Input
18955
18971
  }], rowClick: [{
@@ -20824,7 +20840,7 @@ function hasEmulators(config) {
20824
20840
  * }
20825
20841
  * ```
20826
20842
  */
20827
- class FirebaseService {
20843
+ let FirebaseService$1 = class FirebaseService {
20828
20844
  constructor() {
20829
20845
  this.auth = inject(Auth);
20830
20846
  this.config = inject(VALTECH_FIREBASE_CONFIG);
@@ -21058,8 +21074,8 @@ class FirebaseService {
21058
21074
  }
21059
21075
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FirebaseService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
21060
21076
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FirebaseService, providedIn: 'root' }); }
21061
- }
21062
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FirebaseService, decorators: [{
21077
+ };
21078
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FirebaseService$1, decorators: [{
21063
21079
  type: Injectable,
21064
21080
  args: [{ providedIn: 'root' }]
21065
21081
  }], ctorParameters: () => [] });
@@ -23273,6 +23289,1447 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
23273
23289
  */
23274
23290
  // Tipos
23275
23291
 
23292
+ var index = /*#__PURE__*/Object.freeze({
23293
+ __proto__: null,
23294
+ FirebaseService: FirebaseService$1,
23295
+ FirestoreCollection: FirestoreCollection,
23296
+ FirestoreService: FirestoreService,
23297
+ MessagingService: MessagingService,
23298
+ QueryBuilder: QueryBuilder,
23299
+ StorageService: StorageService,
23300
+ VALTECH_FIREBASE_CONFIG: VALTECH_FIREBASE_CONFIG,
23301
+ buildPath: buildPath,
23302
+ extractPathParams: extractPathParams,
23303
+ getCollectionPath: getCollectionPath,
23304
+ getDocumentId: getDocumentId,
23305
+ hasEmulators: hasEmulators,
23306
+ isCollectionPath: isCollectionPath,
23307
+ isDocumentPath: isDocumentPath,
23308
+ isValidPath: isValidPath,
23309
+ joinPath: joinPath,
23310
+ provideValtechFirebase: provideValtechFirebase,
23311
+ query: query
23312
+ });
23313
+
23314
+ /**
23315
+ * Tipos e interfaces para el servicio de autenticación de Valtech.
23316
+ * Alineados con el backend AuthV2.
23317
+ */
23318
+ /**
23319
+ * Estado inicial de autenticación.
23320
+ */
23321
+ const INITIAL_AUTH_STATE = {
23322
+ isAuthenticated: false,
23323
+ isLoading: true,
23324
+ accessToken: null,
23325
+ refreshToken: null,
23326
+ userId: null,
23327
+ email: null,
23328
+ roles: [],
23329
+ permissions: [],
23330
+ isSuperAdmin: false,
23331
+ expiresAt: null,
23332
+ error: null,
23333
+ };
23334
+ /**
23335
+ * Estado inicial de MFA.
23336
+ */
23337
+ const INITIAL_MFA_STATE = {
23338
+ required: false,
23339
+ mfaToken: null,
23340
+ method: null,
23341
+ };
23342
+
23343
+ /**
23344
+ * Servicio para manejo de estado de autenticación con Angular Signals.
23345
+ * Proporciona estado reactivo inmutable.
23346
+ */
23347
+ class AuthStateService {
23348
+ constructor() {
23349
+ // Estado interno (mutable solo dentro del servicio)
23350
+ this._state = signal(INITIAL_AUTH_STATE);
23351
+ this._mfaPending = signal(INITIAL_MFA_STATE);
23352
+ // =============================================
23353
+ // Signals públicos (readonly)
23354
+ // =============================================
23355
+ /** Estado completo de autenticación */
23356
+ this.state = this._state.asReadonly();
23357
+ /** Estado de MFA pendiente */
23358
+ this.mfaPending = this._mfaPending.asReadonly();
23359
+ /** Usuario está autenticado */
23360
+ this.isAuthenticated = computed(() => this._state().isAuthenticated);
23361
+ /** Estado de carga */
23362
+ this.isLoading = computed(() => this._state().isLoading);
23363
+ /** Token de acceso */
23364
+ this.accessToken = computed(() => this._state().accessToken);
23365
+ /** Roles del usuario */
23366
+ this.roles = computed(() => this._state().roles);
23367
+ /** Permisos del usuario */
23368
+ this.permissions = computed(() => this._state().permissions);
23369
+ /** Usuario es super admin */
23370
+ this.isSuperAdmin = computed(() => this._state().isSuperAdmin);
23371
+ /** Error actual */
23372
+ this.error = computed(() => this._state().error);
23373
+ /** Información del usuario */
23374
+ this.user = computed(() => {
23375
+ const state = this._state();
23376
+ if (!state.isAuthenticated || !state.userId) {
23377
+ return null;
23378
+ }
23379
+ return {
23380
+ userId: state.userId,
23381
+ email: state.email || '',
23382
+ roles: state.roles,
23383
+ permissions: state.permissions,
23384
+ isSuperAdmin: state.isSuperAdmin,
23385
+ };
23386
+ });
23387
+ }
23388
+ // =============================================
23389
+ // Métodos de actualización
23390
+ // =============================================
23391
+ /**
23392
+ * Establece el estado de carga.
23393
+ */
23394
+ setLoading(isLoading) {
23395
+ this._state.update((s) => ({ ...s, isLoading }));
23396
+ }
23397
+ /**
23398
+ * Establece el estado de autenticación exitosa.
23399
+ */
23400
+ setAuthenticated(data) {
23401
+ this._state.set({
23402
+ isAuthenticated: true,
23403
+ isLoading: false,
23404
+ accessToken: data.accessToken,
23405
+ refreshToken: data.refreshToken,
23406
+ userId: data.userId || null,
23407
+ email: data.email || null,
23408
+ roles: data.roles,
23409
+ permissions: data.permissions,
23410
+ isSuperAdmin: data.isSuperAdmin,
23411
+ expiresAt: data.expiresAt,
23412
+ error: null,
23413
+ });
23414
+ }
23415
+ /**
23416
+ * Actualiza solo el access token (después de refresh).
23417
+ */
23418
+ updateAccessToken(accessToken, expiresIn) {
23419
+ const expiresAt = Date.now() + expiresIn * 1000;
23420
+ this._state.update((s) => ({
23421
+ ...s,
23422
+ accessToken,
23423
+ expiresAt,
23424
+ }));
23425
+ }
23426
+ /**
23427
+ * Actualiza los permisos.
23428
+ */
23429
+ updatePermissions(roles, permissions, isSuperAdmin) {
23430
+ this._state.update((s) => ({
23431
+ ...s,
23432
+ roles,
23433
+ permissions,
23434
+ isSuperAdmin,
23435
+ }));
23436
+ }
23437
+ /**
23438
+ * Establece un error de autenticación.
23439
+ */
23440
+ setError(error) {
23441
+ this._state.update((s) => ({
23442
+ ...s,
23443
+ error,
23444
+ isLoading: false,
23445
+ }));
23446
+ }
23447
+ /**
23448
+ * Limpia el error.
23449
+ */
23450
+ clearError() {
23451
+ this._state.update((s) => ({
23452
+ ...s,
23453
+ error: null,
23454
+ }));
23455
+ }
23456
+ /**
23457
+ * Establece estado de MFA pendiente.
23458
+ */
23459
+ setMFAPending(mfaState) {
23460
+ this._mfaPending.set(mfaState);
23461
+ }
23462
+ /**
23463
+ * Limpia el estado de MFA pendiente.
23464
+ */
23465
+ clearMFAPending() {
23466
+ this._mfaPending.set(INITIAL_MFA_STATE);
23467
+ }
23468
+ /**
23469
+ * Resetea todo el estado a valores iniciales.
23470
+ */
23471
+ reset() {
23472
+ this._state.set(INITIAL_AUTH_STATE);
23473
+ this._mfaPending.set(INITIAL_MFA_STATE);
23474
+ }
23475
+ /**
23476
+ * Restaura estado desde datos almacenados.
23477
+ */
23478
+ restoreFromStorage(stored) {
23479
+ if (stored.accessToken) {
23480
+ this._state.set({
23481
+ isAuthenticated: true,
23482
+ isLoading: false,
23483
+ accessToken: stored.accessToken,
23484
+ refreshToken: stored.refreshToken || null,
23485
+ userId: null, // Se extraerá del token
23486
+ email: null, // Se extraerá del token
23487
+ roles: stored.roles || [],
23488
+ permissions: stored.permissions || [],
23489
+ isSuperAdmin: stored.isSuperAdmin || false,
23490
+ expiresAt: stored.expiresAt || null,
23491
+ error: null,
23492
+ });
23493
+ }
23494
+ }
23495
+ /**
23496
+ * Actualiza el userId y email (después de parsear el token).
23497
+ */
23498
+ updateUserInfo(userId, email) {
23499
+ this._state.update((s) => ({
23500
+ ...s,
23501
+ userId,
23502
+ email,
23503
+ }));
23504
+ }
23505
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
23506
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthStateService, providedIn: 'root' }); }
23507
+ }
23508
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthStateService, decorators: [{
23509
+ type: Injectable,
23510
+ args: [{ providedIn: 'root' }]
23511
+ }] });
23512
+
23513
+ /**
23514
+ * Servicio para manejo de tokens JWT.
23515
+ * Parseo y validación de tokens sin dependencias externas.
23516
+ */
23517
+ class TokenService {
23518
+ /**
23519
+ * Parsea un token JWT y extrae los claims.
23520
+ * @param token - Token JWT
23521
+ * @returns Claims del token o null si es inválido
23522
+ */
23523
+ parseToken(token) {
23524
+ try {
23525
+ const parts = token.split('.');
23526
+ if (parts.length !== 3) {
23527
+ return null;
23528
+ }
23529
+ const payload = parts[1];
23530
+ const decoded = this.base64UrlDecode(payload);
23531
+ return JSON.parse(decoded);
23532
+ }
23533
+ catch {
23534
+ console.warn('[ValtechAuth] Error al parsear token JWT');
23535
+ return null;
23536
+ }
23537
+ }
23538
+ /**
23539
+ * Verifica si un token es válido (no expirado).
23540
+ * @param token - Token JWT
23541
+ * @returns true si el token es válido
23542
+ */
23543
+ isTokenValid(token) {
23544
+ const claims = this.parseToken(token);
23545
+ if (!claims) {
23546
+ return false;
23547
+ }
23548
+ // exp está en segundos, Date.now() en milisegundos
23549
+ const expirationMs = claims.exp * 1000;
23550
+ return Date.now() < expirationMs;
23551
+ }
23552
+ /**
23553
+ * Obtiene el tiempo restante del token en segundos.
23554
+ * @param token - Token JWT
23555
+ * @returns Segundos restantes o 0 si expirado
23556
+ */
23557
+ getTimeToExpiry(token) {
23558
+ const claims = this.parseToken(token);
23559
+ if (!claims) {
23560
+ return 0;
23561
+ }
23562
+ const expirationMs = claims.exp * 1000;
23563
+ const remaining = expirationMs - Date.now();
23564
+ return remaining > 0 ? Math.floor(remaining / 1000) : 0;
23565
+ }
23566
+ /**
23567
+ * Obtiene el timestamp de expiración del token.
23568
+ * @param token - Token JWT
23569
+ * @returns Timestamp en milisegundos o null
23570
+ */
23571
+ getExpirationTime(token) {
23572
+ const claims = this.parseToken(token);
23573
+ if (!claims) {
23574
+ return null;
23575
+ }
23576
+ return claims.exp * 1000;
23577
+ }
23578
+ /**
23579
+ * Extrae el user ID del token.
23580
+ * @param token - Token JWT
23581
+ * @returns User ID o null
23582
+ */
23583
+ getUserId(token) {
23584
+ const claims = this.parseToken(token);
23585
+ return claims?.uid || null;
23586
+ }
23587
+ /**
23588
+ * Extrae el email del token.
23589
+ * @param token - Token JWT
23590
+ * @returns Email o null
23591
+ */
23592
+ getEmail(token) {
23593
+ const claims = this.parseToken(token);
23594
+ return claims?.email || null;
23595
+ }
23596
+ /**
23597
+ * Decodifica base64url a string.
23598
+ * Base64url usa - y _ en lugar de + y /
23599
+ */
23600
+ base64UrlDecode(str) {
23601
+ // Reemplazar caracteres base64url por base64 estándar
23602
+ let base64 = str.replace(/-/g, '+').replace(/_/g, '/');
23603
+ // Agregar padding si es necesario
23604
+ const padding = base64.length % 4;
23605
+ if (padding) {
23606
+ base64 += '='.repeat(4 - padding);
23607
+ }
23608
+ // Decodificar
23609
+ const decoded = atob(base64);
23610
+ // Manejar caracteres UTF-8
23611
+ return decodeURIComponent(decoded
23612
+ .split('')
23613
+ .map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
23614
+ .join(''));
23615
+ }
23616
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TokenService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
23617
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TokenService, providedIn: 'root' }); }
23618
+ }
23619
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TokenService, decorators: [{
23620
+ type: Injectable,
23621
+ args: [{ providedIn: 'root' }]
23622
+ }] });
23623
+
23624
+ /**
23625
+ * Servicio para persistencia de estado de autenticación en localStorage.
23626
+ */
23627
+ class AuthStorageService {
23628
+ constructor() {
23629
+ this.config = inject(VALTECH_AUTH_CONFIG);
23630
+ const prefix = this.config.storagePrefix || 'valtech_auth_';
23631
+ this.keys = {
23632
+ ACCESS_TOKEN: `${prefix}access_token`,
23633
+ REFRESH_TOKEN: `${prefix}refresh_token`,
23634
+ ROLES: `${prefix}roles`,
23635
+ PERMISSIONS: `${prefix}permissions`,
23636
+ IS_SUPER_ADMIN: `${prefix}is_super_admin`,
23637
+ EXPIRES_AT: `${prefix}expires_at`,
23638
+ };
23639
+ }
23640
+ /**
23641
+ * Guarda el estado completo de autenticación.
23642
+ */
23643
+ saveState(state) {
23644
+ try {
23645
+ localStorage.setItem(this.keys.ACCESS_TOKEN, state.accessToken);
23646
+ localStorage.setItem(this.keys.REFRESH_TOKEN, state.refreshToken);
23647
+ localStorage.setItem(this.keys.ROLES, JSON.stringify(state.roles));
23648
+ localStorage.setItem(this.keys.PERMISSIONS, JSON.stringify(state.permissions));
23649
+ localStorage.setItem(this.keys.IS_SUPER_ADMIN, String(state.isSuperAdmin));
23650
+ if (state.expiresAt) {
23651
+ localStorage.setItem(this.keys.EXPIRES_AT, String(state.expiresAt));
23652
+ }
23653
+ }
23654
+ catch (e) {
23655
+ console.warn('[ValtechAuth] Error guardando estado en storage:', e);
23656
+ }
23657
+ }
23658
+ /**
23659
+ * Carga el estado de autenticación desde storage.
23660
+ */
23661
+ loadState() {
23662
+ try {
23663
+ const accessToken = localStorage.getItem(this.keys.ACCESS_TOKEN);
23664
+ const refreshToken = localStorage.getItem(this.keys.REFRESH_TOKEN);
23665
+ const rolesJson = localStorage.getItem(this.keys.ROLES);
23666
+ const permissionsJson = localStorage.getItem(this.keys.PERMISSIONS);
23667
+ const isSuperAdmin = localStorage.getItem(this.keys.IS_SUPER_ADMIN) === 'true';
23668
+ const expiresAtStr = localStorage.getItem(this.keys.EXPIRES_AT);
23669
+ return {
23670
+ accessToken: accessToken || undefined,
23671
+ refreshToken: refreshToken || undefined,
23672
+ roles: rolesJson ? JSON.parse(rolesJson) : [],
23673
+ permissions: permissionsJson ? JSON.parse(permissionsJson) : [],
23674
+ isSuperAdmin,
23675
+ expiresAt: expiresAtStr ? Number(expiresAtStr) : undefined,
23676
+ };
23677
+ }
23678
+ catch (e) {
23679
+ console.warn('[ValtechAuth] Error cargando estado desde storage:', e);
23680
+ return {};
23681
+ }
23682
+ }
23683
+ /**
23684
+ * Guarda solo el access token.
23685
+ */
23686
+ saveAccessToken(token, expiresAt) {
23687
+ try {
23688
+ localStorage.setItem(this.keys.ACCESS_TOKEN, token);
23689
+ if (expiresAt) {
23690
+ localStorage.setItem(this.keys.EXPIRES_AT, String(expiresAt));
23691
+ }
23692
+ }
23693
+ catch (e) {
23694
+ console.warn('[ValtechAuth] Error guardando access token:', e);
23695
+ }
23696
+ }
23697
+ /**
23698
+ * Guarda los permisos actualizados.
23699
+ */
23700
+ savePermissions(response) {
23701
+ try {
23702
+ localStorage.setItem(this.keys.ROLES, JSON.stringify(response.roles));
23703
+ localStorage.setItem(this.keys.PERMISSIONS, JSON.stringify(response.permissions));
23704
+ localStorage.setItem(this.keys.IS_SUPER_ADMIN, String(response.isSuperAdmin));
23705
+ }
23706
+ catch (e) {
23707
+ console.warn('[ValtechAuth] Error guardando permisos:', e);
23708
+ }
23709
+ }
23710
+ /**
23711
+ * Carga los permisos desde storage.
23712
+ */
23713
+ loadPermissions() {
23714
+ try {
23715
+ const rolesJson = localStorage.getItem(this.keys.ROLES);
23716
+ const permissionsJson = localStorage.getItem(this.keys.PERMISSIONS);
23717
+ const isSuperAdmin = localStorage.getItem(this.keys.IS_SUPER_ADMIN) === 'true';
23718
+ return {
23719
+ roles: rolesJson ? JSON.parse(rolesJson) : [],
23720
+ permissions: permissionsJson ? JSON.parse(permissionsJson) : [],
23721
+ isSuperAdmin,
23722
+ };
23723
+ }
23724
+ catch {
23725
+ return { roles: [], permissions: [], isSuperAdmin: false };
23726
+ }
23727
+ }
23728
+ /**
23729
+ * Obtiene el refresh token.
23730
+ */
23731
+ getRefreshToken() {
23732
+ return localStorage.getItem(this.keys.REFRESH_TOKEN);
23733
+ }
23734
+ /**
23735
+ * Limpia todo el estado de autenticación.
23736
+ */
23737
+ clear() {
23738
+ try {
23739
+ Object.values(this.keys).forEach((key) => localStorage.removeItem(key));
23740
+ }
23741
+ catch (e) {
23742
+ console.warn('[ValtechAuth] Error limpiando storage:', e);
23743
+ }
23744
+ }
23745
+ /**
23746
+ * Verifica si hay estado guardado.
23747
+ */
23748
+ hasStoredState() {
23749
+ return !!localStorage.getItem(this.keys.ACCESS_TOKEN);
23750
+ }
23751
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
23752
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthStorageService, providedIn: 'root' }); }
23753
+ }
23754
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthStorageService, decorators: [{
23755
+ type: Injectable,
23756
+ args: [{ providedIn: 'root' }]
23757
+ }], ctorParameters: () => [] });
23758
+
23759
+ /**
23760
+ * Servicio para sincronización de estado de autenticación entre pestañas.
23761
+ * Usa BroadcastChannel API con fallback a storage events.
23762
+ */
23763
+ class AuthSyncService {
23764
+ constructor() {
23765
+ this.config = inject(VALTECH_AUTH_CONFIG);
23766
+ this.channel = null;
23767
+ this.eventSubject = new Subject();
23768
+ this.storageListener = null;
23769
+ /** Observable de eventos de sincronización */
23770
+ this.onEvent$ = this.eventSubject.asObservable();
23771
+ const prefix = this.config.storagePrefix || 'valtech_auth_';
23772
+ this.channelName = `${prefix}sync_channel`;
23773
+ }
23774
+ /**
23775
+ * Inicia la sincronización entre pestañas.
23776
+ */
23777
+ start() {
23778
+ if (!this.config.enableTabSync) {
23779
+ return;
23780
+ }
23781
+ // Intentar usar BroadcastChannel API (mejor rendimiento)
23782
+ if (typeof BroadcastChannel !== 'undefined') {
23783
+ this.initBroadcastChannel();
23784
+ }
23785
+ else {
23786
+ // Fallback a storage events
23787
+ this.initStorageEvents();
23788
+ }
23789
+ }
23790
+ /**
23791
+ * Detiene la sincronización.
23792
+ */
23793
+ stop() {
23794
+ if (this.channel) {
23795
+ this.channel.close();
23796
+ this.channel = null;
23797
+ }
23798
+ if (this.storageListener) {
23799
+ window.removeEventListener('storage', this.storageListener);
23800
+ this.storageListener = null;
23801
+ }
23802
+ }
23803
+ /**
23804
+ * Envía un evento a otras pestañas.
23805
+ */
23806
+ broadcast(event) {
23807
+ if (!this.config.enableTabSync) {
23808
+ return;
23809
+ }
23810
+ const fullEvent = {
23811
+ ...event,
23812
+ timestamp: Date.now(),
23813
+ };
23814
+ if (this.channel) {
23815
+ this.channel.postMessage(fullEvent);
23816
+ }
23817
+ else {
23818
+ // Fallback: usar localStorage para notificar
23819
+ this.broadcastViaStorage(fullEvent);
23820
+ }
23821
+ }
23822
+ ngOnDestroy() {
23823
+ this.stop();
23824
+ this.eventSubject.complete();
23825
+ }
23826
+ /**
23827
+ * Inicializa BroadcastChannel API.
23828
+ */
23829
+ initBroadcastChannel() {
23830
+ try {
23831
+ this.channel = new BroadcastChannel(this.channelName);
23832
+ this.channel.onmessage = (event) => {
23833
+ this.handleEvent(event.data);
23834
+ };
23835
+ this.channel.onmessageerror = () => {
23836
+ console.warn('[ValtechAuth] Error en BroadcastChannel, usando fallback');
23837
+ this.channel?.close();
23838
+ this.channel = null;
23839
+ this.initStorageEvents();
23840
+ };
23841
+ }
23842
+ catch {
23843
+ // BroadcastChannel no disponible, usar fallback
23844
+ this.initStorageEvents();
23845
+ }
23846
+ }
23847
+ /**
23848
+ * Inicializa fallback con storage events.
23849
+ */
23850
+ initStorageEvents() {
23851
+ const storageKey = `${this.config.storagePrefix}sync_event`;
23852
+ this.storageListener = (event) => {
23853
+ if (event.key === storageKey && event.newValue) {
23854
+ try {
23855
+ const syncEvent = JSON.parse(event.newValue);
23856
+ this.handleEvent(syncEvent);
23857
+ }
23858
+ catch {
23859
+ // Ignorar eventos mal formados
23860
+ }
23861
+ }
23862
+ };
23863
+ window.addEventListener('storage', this.storageListener);
23864
+ }
23865
+ /**
23866
+ * Envía evento via localStorage (fallback).
23867
+ */
23868
+ broadcastViaStorage(event) {
23869
+ const storageKey = `${this.config.storagePrefix}sync_event`;
23870
+ try {
23871
+ // Escribir y luego limpiar para permitir múltiples eventos del mismo tipo
23872
+ localStorage.setItem(storageKey, JSON.stringify(event));
23873
+ // Usar setTimeout para permitir que otras pestañas lean el valor
23874
+ setTimeout(() => {
23875
+ localStorage.removeItem(storageKey);
23876
+ }, 100);
23877
+ }
23878
+ catch {
23879
+ console.warn('[ValtechAuth] Error enviando evento via storage');
23880
+ }
23881
+ }
23882
+ /**
23883
+ * Maneja un evento recibido.
23884
+ */
23885
+ handleEvent(event) {
23886
+ // Verificar que el evento no sea muy antiguo (más de 5 segundos)
23887
+ const age = Date.now() - event.timestamp;
23888
+ if (age > 5000) {
23889
+ return;
23890
+ }
23891
+ this.eventSubject.next(event);
23892
+ }
23893
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthSyncService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
23894
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthSyncService, providedIn: 'root' }); }
23895
+ }
23896
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthSyncService, decorators: [{
23897
+ type: Injectable,
23898
+ args: [{ providedIn: 'root' }]
23899
+ }], ctorParameters: () => [] });
23900
+
23901
+ // Importación opcional de FirebaseService
23902
+ let FirebaseService = null;
23903
+ try {
23904
+ // Intenta importar FirebaseService si está disponible
23905
+ Promise.resolve().then(function () { return index; }).then((m) => {
23906
+ FirebaseService = m.FirebaseService;
23907
+ });
23908
+ }
23909
+ catch {
23910
+ // FirebaseService no disponible
23911
+ }
23912
+ /**
23913
+ * Servicio principal de autenticación.
23914
+ *
23915
+ * @example
23916
+ * ```typescript
23917
+ * import { AuthService } from 'valtech-components';
23918
+ *
23919
+ * @Component({...})
23920
+ * export class LoginComponent {
23921
+ * private auth = inject(AuthService);
23922
+ *
23923
+ * async login() {
23924
+ * await firstValueFrom(this.auth.signin({ email, password }));
23925
+ * if (this.auth.mfaPending().required) {
23926
+ * // Mostrar UI de MFA
23927
+ * } else {
23928
+ * this.router.navigate(['/']);
23929
+ * }
23930
+ * }
23931
+ * }
23932
+ * ```
23933
+ */
23934
+ class AuthService {
23935
+ constructor() {
23936
+ this.config = inject(VALTECH_AUTH_CONFIG);
23937
+ this.http = inject(HttpClient);
23938
+ this.router = inject(Router);
23939
+ this.stateService = inject(AuthStateService);
23940
+ this.tokenService = inject(TokenService);
23941
+ this.storageService = inject(AuthStorageService);
23942
+ this.syncService = inject(AuthSyncService);
23943
+ // Timer para refresh proactivo
23944
+ this.refreshTimerId = null;
23945
+ this.syncSubscription = null;
23946
+ // =============================================
23947
+ // ESTADO PÚBLICO (Signals readonly)
23948
+ // =============================================
23949
+ /** Estado completo de autenticación */
23950
+ this.state = this.stateService.state;
23951
+ /** Usuario está autenticado */
23952
+ this.isAuthenticated = this.stateService.isAuthenticated;
23953
+ /** Estado de carga */
23954
+ this.isLoading = this.stateService.isLoading;
23955
+ /** Información del usuario */
23956
+ this.user = this.stateService.user;
23957
+ /** Token de acceso */
23958
+ this.accessToken = this.stateService.accessToken;
23959
+ /** Roles del usuario */
23960
+ this.roles = this.stateService.roles;
23961
+ /** Permisos del usuario */
23962
+ this.permissions = this.stateService.permissions;
23963
+ /** Usuario es super admin */
23964
+ this.isSuperAdmin = this.stateService.isSuperAdmin;
23965
+ /** Estado de MFA pendiente */
23966
+ this.mfaPending = this.stateService.mfaPending;
23967
+ /** Error actual */
23968
+ this.error = this.stateService.error;
23969
+ }
23970
+ // =============================================
23971
+ // INICIALIZACIÓN
23972
+ // =============================================
23973
+ /**
23974
+ * Inicializa el servicio de autenticación.
23975
+ * Llamado automáticamente por provideValtechAuth.
23976
+ */
23977
+ async initialize() {
23978
+ // 1. Cargar estado desde storage
23979
+ const storedState = this.storageService.loadState();
23980
+ if (storedState.accessToken) {
23981
+ // 2. Verificar si token es válido
23982
+ if (this.tokenService.isTokenValid(storedState.accessToken)) {
23983
+ this.stateService.restoreFromStorage(storedState);
23984
+ // Extraer info del token
23985
+ const claims = this.tokenService.parseToken(storedState.accessToken);
23986
+ if (claims) {
23987
+ this.stateService.updateUserInfo(claims.uid, claims.email);
23988
+ }
23989
+ // 3. Iniciar timer de refresco proactivo
23990
+ this.startRefreshTimer();
23991
+ }
23992
+ else if (storedState.refreshToken) {
23993
+ // 4. Token expirado pero hay refresh token - intentar refrescar
23994
+ try {
23995
+ await firstValueFrom(this.refreshAccessToken());
23996
+ }
23997
+ catch {
23998
+ this.clearState();
23999
+ }
24000
+ }
24001
+ else {
24002
+ this.clearState();
24003
+ }
24004
+ }
24005
+ // 5. Iniciar sincronización entre pestañas
24006
+ if (this.config.enableTabSync) {
24007
+ this.syncService.start();
24008
+ this.syncSubscription = this.syncService.onEvent$.subscribe((event) => this.handleSyncEvent(event));
24009
+ }
24010
+ this.stateService.setLoading(false);
24011
+ }
24012
+ ngOnDestroy() {
24013
+ this.stopRefreshTimer();
24014
+ this.syncSubscription?.unsubscribe();
24015
+ }
24016
+ // =============================================
24017
+ // AUTENTICACIÓN
24018
+ // =============================================
24019
+ /**
24020
+ * Inicia sesión con email y contraseña.
24021
+ */
24022
+ signin(request) {
24023
+ this.stateService.clearError();
24024
+ return this.http
24025
+ .post(`${this.baseUrl}/signin`, request)
24026
+ .pipe(tap((response) => {
24027
+ if (response.mfaRequired) {
24028
+ // MFA requerido - guardar estado temporal
24029
+ this.stateService.setMFAPending({
24030
+ required: true,
24031
+ mfaToken: response.mfaToken,
24032
+ method: response.mfaMethod,
24033
+ });
24034
+ }
24035
+ else if (response.accessToken) {
24036
+ // Login exitoso sin MFA
24037
+ this.handleSuccessfulAuth(response);
24038
+ }
24039
+ }), catchError((error) => this.handleAuthError(error)));
24040
+ }
24041
+ /**
24042
+ * Verifica código MFA.
24043
+ */
24044
+ verifyMFA(code) {
24045
+ const mfaState = this.mfaPending();
24046
+ if (!mfaState.mfaToken) {
24047
+ return throwError(() => ({
24048
+ code: 'MFA_NOT_PENDING',
24049
+ message: 'No hay verificación MFA pendiente',
24050
+ }));
24051
+ }
24052
+ return this.http
24053
+ .post(`${this.baseUrl}/mfa/verify`, {
24054
+ mfaToken: mfaState.mfaToken,
24055
+ code,
24056
+ })
24057
+ .pipe(tap((response) => {
24058
+ this.stateService.clearMFAPending();
24059
+ this.handleSuccessfulAuth(response);
24060
+ }), catchError((error) => this.handleAuthError(error)));
24061
+ }
24062
+ /**
24063
+ * Refresca el token de acceso.
24064
+ */
24065
+ refreshAccessToken() {
24066
+ const refreshToken = this.state().refreshToken;
24067
+ if (!refreshToken) {
24068
+ return throwError(() => ({
24069
+ code: 'NO_REFRESH_TOKEN',
24070
+ message: 'No hay token de refresco',
24071
+ }));
24072
+ }
24073
+ return this.http
24074
+ .post(`${this.baseUrl}/refresh`, { refreshToken })
24075
+ .pipe(tap((response) => {
24076
+ const expiresAt = Date.now() + response.expiresIn * 1000;
24077
+ this.stateService.updateAccessToken(response.accessToken, response.expiresIn);
24078
+ this.storageService.saveAccessToken(response.accessToken, expiresAt);
24079
+ this.startRefreshTimer();
24080
+ this.syncService.broadcast({
24081
+ type: 'TOKEN_REFRESH',
24082
+ payload: { accessToken: response.accessToken, expiresAt },
24083
+ });
24084
+ }), catchError((error) => {
24085
+ this.logout();
24086
+ return throwError(() => error);
24087
+ }));
24088
+ }
24089
+ /**
24090
+ * Cierra sesión.
24091
+ */
24092
+ logout() {
24093
+ const refreshToken = this.state().refreshToken;
24094
+ // Notificar al backend (fire and forget)
24095
+ if (refreshToken) {
24096
+ this.http
24097
+ .post(`${this.baseUrl}/logout`, { refreshToken })
24098
+ .pipe(catchError(() => of(null)))
24099
+ .subscribe();
24100
+ }
24101
+ // Cerrar sesión de Firebase si está integrado
24102
+ this.signOutFirebase();
24103
+ this.clearState();
24104
+ this.syncService.broadcast({ type: 'LOGOUT' });
24105
+ this.router.navigate([this.config.loginRoute]);
24106
+ }
24107
+ // =============================================
24108
+ // MFA SETUP (usuario autenticado)
24109
+ // =============================================
24110
+ /**
24111
+ * Configura MFA para el usuario.
24112
+ */
24113
+ setupMFA(method, phone) {
24114
+ return this.http
24115
+ .post(`${this.baseUrl}/mfa/setup`, { method, phone })
24116
+ .pipe(catchError((error) => this.handleAuthError(error)));
24117
+ }
24118
+ /**
24119
+ * Confirma la configuración de MFA.
24120
+ */
24121
+ confirmMFA(code) {
24122
+ return this.http
24123
+ .post(`${this.baseUrl}/mfa/confirm`, { code })
24124
+ .pipe(catchError((error) => this.handleAuthError(error)));
24125
+ }
24126
+ /**
24127
+ * Deshabilita MFA.
24128
+ */
24129
+ disableMFA(password) {
24130
+ return this.http
24131
+ .post(`${this.baseUrl}/mfa/disable`, { password })
24132
+ .pipe(catchError((error) => this.handleAuthError(error)));
24133
+ }
24134
+ // =============================================
24135
+ // PERMISOS
24136
+ // =============================================
24137
+ /**
24138
+ * Obtiene los permisos actualizados del backend.
24139
+ */
24140
+ fetchPermissions() {
24141
+ return this.http
24142
+ .get(`${this.baseUrl}/permissions`)
24143
+ .pipe(tap((response) => {
24144
+ this.stateService.updatePermissions(response.roles, response.permissions, response.isSuperAdmin);
24145
+ this.storageService.savePermissions(response);
24146
+ this.syncService.broadcast({ type: 'PERMISSIONS_UPDATE' });
24147
+ }), catchError((error) => this.handleAuthError(error)));
24148
+ }
24149
+ /**
24150
+ * Verifica si el usuario tiene un permiso específico.
24151
+ * Formato: "resource:action" (ej: "templates:edit")
24152
+ */
24153
+ hasPermission(permission) {
24154
+ if (this.isSuperAdmin())
24155
+ return true;
24156
+ const [resource, action] = permission.split(':');
24157
+ return this.permissions().some((p) => {
24158
+ const [pResource, pAction] = p.split(':');
24159
+ return ((pResource === '*' || pResource === resource) &&
24160
+ (pAction === '*' || pAction === action));
24161
+ });
24162
+ }
24163
+ /**
24164
+ * Verifica si el usuario tiene alguno de los permisos dados.
24165
+ */
24166
+ hasAnyPermission(permissions) {
24167
+ return permissions.some((p) => this.hasPermission(p));
24168
+ }
24169
+ /**
24170
+ * Verifica si el usuario tiene todos los permisos dados.
24171
+ */
24172
+ hasAllPermissions(permissions) {
24173
+ return permissions.every((p) => this.hasPermission(p));
24174
+ }
24175
+ /**
24176
+ * Verifica si el usuario tiene un rol específico.
24177
+ */
24178
+ hasRole(role) {
24179
+ return this.roles().some((r) => r.toLowerCase() === role.toLowerCase());
24180
+ }
24181
+ // =============================================
24182
+ // PRIVATE METHODS
24183
+ // =============================================
24184
+ get baseUrl() {
24185
+ return `${this.config.apiUrl}${this.config.authPrefix}`;
24186
+ }
24187
+ handleSuccessfulAuth(response) {
24188
+ const expiresAt = Date.now() + (response.expiresIn * 1000);
24189
+ const tokenData = this.tokenService.parseToken(response.accessToken);
24190
+ this.stateService.setAuthenticated({
24191
+ accessToken: response.accessToken,
24192
+ refreshToken: response.refreshToken,
24193
+ userId: tokenData?.uid,
24194
+ email: tokenData?.email,
24195
+ roles: response.roles || [],
24196
+ permissions: response.permissions || [],
24197
+ isSuperAdmin: response.permissions?.includes('*:*') || false,
24198
+ expiresAt,
24199
+ });
24200
+ this.storageService.saveState({
24201
+ accessToken: response.accessToken,
24202
+ refreshToken: response.refreshToken,
24203
+ roles: response.roles || [],
24204
+ permissions: response.permissions || [],
24205
+ isSuperAdmin: response.permissions?.includes('*:*') || false,
24206
+ expiresAt,
24207
+ });
24208
+ this.startRefreshTimer();
24209
+ this.syncService.broadcast({ type: 'LOGIN' });
24210
+ // Integración con Firebase
24211
+ if (this.config.enableFirebaseIntegration &&
24212
+ 'firebaseToken' in response &&
24213
+ response.firebaseToken) {
24214
+ this.signInWithFirebase(response.firebaseToken);
24215
+ }
24216
+ }
24217
+ clearState() {
24218
+ this.stopRefreshTimer();
24219
+ this.stateService.reset();
24220
+ this.storageService.clear();
24221
+ }
24222
+ startRefreshTimer() {
24223
+ this.stopRefreshTimer();
24224
+ const state = this.stateService.state();
24225
+ if (!state.expiresAt)
24226
+ return;
24227
+ const refreshBeforeMs = (this.config.refreshBeforeExpiry || 60) * 1000;
24228
+ const refreshAt = state.expiresAt - refreshBeforeMs;
24229
+ const delay = refreshAt - Date.now();
24230
+ if (delay > 0) {
24231
+ this.refreshTimerId = setTimeout(() => {
24232
+ this.refreshAccessToken().subscribe({
24233
+ error: () => this.logout(),
24234
+ });
24235
+ }, delay);
24236
+ }
24237
+ else if (state.refreshToken) {
24238
+ // Token ya debería refrescarse, intentar ahora
24239
+ this.refreshAccessToken().subscribe({
24240
+ error: () => this.logout(),
24241
+ });
24242
+ }
24243
+ }
24244
+ stopRefreshTimer() {
24245
+ if (this.refreshTimerId) {
24246
+ clearTimeout(this.refreshTimerId);
24247
+ this.refreshTimerId = null;
24248
+ }
24249
+ }
24250
+ handleSyncEvent(event) {
24251
+ switch (event.type) {
24252
+ case 'LOGIN':
24253
+ case 'TOKEN_REFRESH': {
24254
+ // Recargar estado desde storage
24255
+ const state = this.storageService.loadState();
24256
+ if (state.accessToken) {
24257
+ this.stateService.restoreFromStorage(state);
24258
+ const claims = this.tokenService.parseToken(state.accessToken);
24259
+ if (claims) {
24260
+ this.stateService.updateUserInfo(claims.uid, claims.email);
24261
+ }
24262
+ this.startRefreshTimer();
24263
+ }
24264
+ break;
24265
+ }
24266
+ case 'LOGOUT':
24267
+ this.stateService.reset();
24268
+ this.stopRefreshTimer();
24269
+ this.router.navigate([this.config.loginRoute]);
24270
+ break;
24271
+ case 'PERMISSIONS_UPDATE': {
24272
+ const perms = this.storageService.loadPermissions();
24273
+ this.stateService.updatePermissions(perms.roles, perms.permissions, perms.isSuperAdmin);
24274
+ break;
24275
+ }
24276
+ }
24277
+ }
24278
+ handleAuthError(error) {
24279
+ const authError = {
24280
+ code: error.error?.code || 'UNKNOWN_ERROR',
24281
+ message: error.error?.message || 'Error de autenticación desconocido',
24282
+ };
24283
+ this.stateService.setError(authError);
24284
+ return throwError(() => authError);
24285
+ }
24286
+ // =============================================
24287
+ // FIREBASE INTEGRATION
24288
+ // =============================================
24289
+ async signInWithFirebase(firebaseToken) {
24290
+ try {
24291
+ // Importar FirebaseService dinámicamente
24292
+ const firebase = await Promise.resolve().then(function () { return index; });
24293
+ const injector = (await import('@angular/core')).inject;
24294
+ // Esto es un workaround - en producción se usaría un patrón más robusto
24295
+ console.log('[ValtechAuth] Firebase integration: token received, attempting signin...');
24296
+ // Por ahora, solo loguear que se recibió el token
24297
+ // La integración real requiere inyectar FirebaseService
24298
+ }
24299
+ catch {
24300
+ console.warn('[ValtechAuth] FirebaseService no disponible');
24301
+ }
24302
+ }
24303
+ async signOutFirebase() {
24304
+ if (!this.config.enableFirebaseIntegration)
24305
+ return;
24306
+ try {
24307
+ // Similar al signin, la integración real requiere inyección
24308
+ console.log('[ValtechAuth] Firebase signout triggered');
24309
+ }
24310
+ catch {
24311
+ // Ignorar errores de Firebase
24312
+ }
24313
+ }
24314
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
24315
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthService, providedIn: 'root' }); }
24316
+ }
24317
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthService, decorators: [{
24318
+ type: Injectable,
24319
+ args: [{ providedIn: 'root' }]
24320
+ }] });
24321
+
24322
+ // Control de estado de refresco (singleton a nivel de módulo)
24323
+ let isRefreshing = false;
24324
+ const refreshTokenSubject = new BehaviorSubject(null);
24325
+ /**
24326
+ * Interceptor HTTP que:
24327
+ * 1. Agrega header Authorization con Bearer token a requests API
24328
+ * 2. Maneja errores 401 refrescando el token automáticamente
24329
+ * 3. Encola requests durante el refresco para evitar múltiples refresh
24330
+ *
24331
+ * @example
24332
+ * ```typescript
24333
+ * // Incluido automáticamente por provideValtechAuth()
24334
+ * // Para uso manual:
24335
+ * import { provideHttpClient, withInterceptors } from '@angular/common/http';
24336
+ * import { authInterceptor } from 'valtech-components';
24337
+ *
24338
+ * bootstrapApplication(AppComponent, {
24339
+ * providers: [
24340
+ * provideHttpClient(withInterceptors([authInterceptor])),
24341
+ * ],
24342
+ * });
24343
+ * ```
24344
+ */
24345
+ const authInterceptor = (request, next) => {
24346
+ const authService = inject(AuthService);
24347
+ const config = inject(VALTECH_AUTH_CONFIG);
24348
+ // Omitir requests que no son a nuestra API
24349
+ if (!isApiRequest(request, config.apiUrl)) {
24350
+ return next(request);
24351
+ }
24352
+ // Omitir endpoints de auth que no necesitan token
24353
+ if (isAuthEndpoint(request, config.authPrefix)) {
24354
+ return next(request);
24355
+ }
24356
+ const accessToken = authService.accessToken();
24357
+ // Agregar header de autorización si hay token
24358
+ if (accessToken) {
24359
+ request = addAuthHeader(request, accessToken);
24360
+ }
24361
+ return next(request).pipe(catchError((error) => {
24362
+ if (error.status === 401 && !isAuthEndpoint(request, config.authPrefix)) {
24363
+ return handle401Error(request, next, authService);
24364
+ }
24365
+ if (error.status === 403) {
24366
+ console.error('[ValtechAuth] Permiso denegado:', error.error?.message || 'Acceso prohibido');
24367
+ }
24368
+ return throwError(() => error);
24369
+ }));
24370
+ };
24371
+ /**
24372
+ * Agrega header de autorización a la request.
24373
+ */
24374
+ function addAuthHeader(request, token) {
24375
+ return request.clone({
24376
+ setHeaders: {
24377
+ Authorization: `Bearer ${token}`,
24378
+ },
24379
+ });
24380
+ }
24381
+ /**
24382
+ * Verifica si la request es a nuestra API.
24383
+ */
24384
+ function isApiRequest(request, apiUrl) {
24385
+ return request.url.startsWith(apiUrl) || request.url.includes('/v2/auth');
24386
+ }
24387
+ /**
24388
+ * Verifica si la request es a un endpoint de auth que no debe reintentar.
24389
+ */
24390
+ function isAuthEndpoint(request, authPrefix) {
24391
+ const authEndpoints = ['/signin', '/signup', '/refresh', '/logout', '/mfa/verify'];
24392
+ return authEndpoints.some((endpoint) => request.url.includes(`${authPrefix}${endpoint}`));
24393
+ }
24394
+ /**
24395
+ * Maneja errores 401 refrescando el token.
24396
+ */
24397
+ function handle401Error(request, next, authService) {
24398
+ if (!isRefreshing) {
24399
+ isRefreshing = true;
24400
+ refreshTokenSubject.next(null);
24401
+ return authService.refreshAccessToken().pipe(switchMap((response) => {
24402
+ refreshTokenSubject.next(response.accessToken);
24403
+ return next(addAuthHeader(request, response.accessToken));
24404
+ }), catchError((error) => {
24405
+ authService.logout();
24406
+ return throwError(() => error);
24407
+ }), finalize(() => {
24408
+ isRefreshing = false;
24409
+ }));
24410
+ }
24411
+ // Esperar a que termine el refresco en curso
24412
+ return refreshTokenSubject.pipe(filter$1((token) => token !== null), take(1), switchMap((token) => next(addAuthHeader(request, token))));
24413
+ }
24414
+
24415
+ /**
24416
+ * Token de inyección para la configuración de Auth.
24417
+ */
24418
+ const VALTECH_AUTH_CONFIG = new InjectionToken('ValtechAuthConfig');
24419
+ /**
24420
+ * Configuración por defecto.
24421
+ */
24422
+ const DEFAULT_AUTH_CONFIG = {
24423
+ authPrefix: '/v2/auth',
24424
+ storagePrefix: 'valtech_auth_',
24425
+ refreshBeforeExpiry: 60,
24426
+ enableTabSync: true,
24427
+ loginRoute: '/login',
24428
+ homeRoute: '/',
24429
+ unauthorizedRoute: '/unauthorized',
24430
+ enableFirebaseIntegration: false,
24431
+ };
24432
+ /**
24433
+ * Factory para inicializar el AuthService.
24434
+ */
24435
+ function initializeAuth(authService) {
24436
+ return () => authService.initialize();
24437
+ }
24438
+ /**
24439
+ * Provee el servicio de autenticación a la aplicación Angular.
24440
+ *
24441
+ * @param config - Configuración de autenticación
24442
+ * @returns EnvironmentProviders para usar en bootstrapApplication
24443
+ *
24444
+ * @example
24445
+ * ```typescript
24446
+ * // main.ts
24447
+ * import { bootstrapApplication } from '@angular/platform-browser';
24448
+ * import { provideValtechAuth } from 'valtech-components';
24449
+ * import { environment } from './environments/environment';
24450
+ *
24451
+ * bootstrapApplication(AppComponent, {
24452
+ * providers: [
24453
+ * provideValtechAuth({
24454
+ * apiUrl: environment.apiUrl,
24455
+ * enableFirebaseIntegration: true,
24456
+ * }),
24457
+ * ],
24458
+ * });
24459
+ * ```
24460
+ */
24461
+ function provideValtechAuth(config) {
24462
+ const mergedConfig = {
24463
+ ...DEFAULT_AUTH_CONFIG,
24464
+ ...config,
24465
+ };
24466
+ return makeEnvironmentProviders([
24467
+ { provide: VALTECH_AUTH_CONFIG, useValue: mergedConfig },
24468
+ provideHttpClient(withInterceptors([authInterceptor])),
24469
+ // Inicializar AuthService al arrancar la app
24470
+ {
24471
+ provide: APP_INITIALIZER,
24472
+ useFactory: initializeAuth,
24473
+ deps: [AuthService],
24474
+ multi: true,
24475
+ },
24476
+ ]);
24477
+ }
24478
+ /**
24479
+ * Provee solo el interceptor (para apps que ya tienen AuthService configurado manualmente).
24480
+ */
24481
+ function provideValtechAuthInterceptor() {
24482
+ return makeEnvironmentProviders([
24483
+ provideHttpClient(withInterceptors([authInterceptor])),
24484
+ ]);
24485
+ }
24486
+
24487
+ /**
24488
+ * Guard que verifica si el usuario está autenticado.
24489
+ * Redirige a loginRoute si no está autenticado.
24490
+ *
24491
+ * @example
24492
+ * ```typescript
24493
+ * import { authGuard } from 'valtech-components';
24494
+ *
24495
+ * const routes: Routes = [
24496
+ * {
24497
+ * path: 'dashboard',
24498
+ * canActivate: [authGuard],
24499
+ * loadComponent: () => import('./dashboard.page'),
24500
+ * },
24501
+ * ];
24502
+ * ```
24503
+ */
24504
+ const authGuard = () => {
24505
+ const authService = inject(AuthService);
24506
+ const router = inject(Router);
24507
+ const config = inject(VALTECH_AUTH_CONFIG);
24508
+ if (authService.isAuthenticated()) {
24509
+ return true;
24510
+ }
24511
+ return router.createUrlTree([config.loginRoute]);
24512
+ };
24513
+ /**
24514
+ * Guard que verifica si el usuario NO está autenticado.
24515
+ * Redirige a homeRoute si ya está autenticado.
24516
+ * Útil para páginas de login/registro.
24517
+ *
24518
+ * @example
24519
+ * ```typescript
24520
+ * import { guestGuard } from 'valtech-components';
24521
+ *
24522
+ * const routes: Routes = [
24523
+ * {
24524
+ * path: 'login',
24525
+ * canActivate: [guestGuard],
24526
+ * loadComponent: () => import('./login.page'),
24527
+ * },
24528
+ * ];
24529
+ * ```
24530
+ */
24531
+ const guestGuard = () => {
24532
+ const authService = inject(AuthService);
24533
+ const router = inject(Router);
24534
+ const config = inject(VALTECH_AUTH_CONFIG);
24535
+ if (!authService.isAuthenticated()) {
24536
+ return true;
24537
+ }
24538
+ return router.createUrlTree([config.homeRoute]);
24539
+ };
24540
+ /**
24541
+ * Factory para crear guard de permisos.
24542
+ * Verifica si el usuario tiene el permiso especificado.
24543
+ *
24544
+ * @param permissions - Permiso o lista de permisos requeridos (OR)
24545
+ * @returns Guard function
24546
+ *
24547
+ * @example
24548
+ * ```typescript
24549
+ * import { authGuard, permissionGuard } from 'valtech-components';
24550
+ *
24551
+ * const routes: Routes = [
24552
+ * {
24553
+ * path: 'templates',
24554
+ * canActivate: [authGuard, permissionGuard('templates:read')],
24555
+ * loadComponent: () => import('./templates.page'),
24556
+ * },
24557
+ * {
24558
+ * path: 'admin',
24559
+ * canActivate: [authGuard, permissionGuard(['admin:*', 'super_admin'])],
24560
+ * loadComponent: () => import('./admin.page'),
24561
+ * },
24562
+ * ];
24563
+ * ```
24564
+ */
24565
+ function permissionGuard(permissions) {
24566
+ return () => {
24567
+ const authService = inject(AuthService);
24568
+ const router = inject(Router);
24569
+ const config = inject(VALTECH_AUTH_CONFIG);
24570
+ const permArray = Array.isArray(permissions) ? permissions : [permissions];
24571
+ if (authService.hasAnyPermission(permArray)) {
24572
+ return true;
24573
+ }
24574
+ console.warn(`[ValtechAuth] Permiso denegado. Requerido: ${permArray.join(' o ')}`);
24575
+ return router.createUrlTree([config.unauthorizedRoute]);
24576
+ };
24577
+ }
24578
+ /**
24579
+ * Guard que lee permisos desde route.data.
24580
+ * Permite configurar permisos directamente en la definición de rutas.
24581
+ *
24582
+ * @example
24583
+ * ```typescript
24584
+ * import { authGuard, permissionGuardFromRoute } from 'valtech-components';
24585
+ *
24586
+ * const routes: Routes = [
24587
+ * {
24588
+ * path: 'admin/users',
24589
+ * canActivate: [authGuard, permissionGuardFromRoute],
24590
+ * data: {
24591
+ * permissions: ['users:read', 'users:manage'],
24592
+ * requireAll: false // true = AND, false = OR (default)
24593
+ * },
24594
+ * loadComponent: () => import('./users.page'),
24595
+ * },
24596
+ * ];
24597
+ * ```
24598
+ */
24599
+ const permissionGuardFromRoute = (route) => {
24600
+ const authService = inject(AuthService);
24601
+ const router = inject(Router);
24602
+ const config = inject(VALTECH_AUTH_CONFIG);
24603
+ const permissions = route.data['permissions'];
24604
+ const requireAll = route.data['requireAll'];
24605
+ if (!permissions || permissions.length === 0) {
24606
+ return true;
24607
+ }
24608
+ const hasAccess = requireAll
24609
+ ? authService.hasAllPermissions(permissions)
24610
+ : authService.hasAnyPermission(permissions);
24611
+ if (hasAccess) {
24612
+ return true;
24613
+ }
24614
+ console.warn(`[ValtechAuth] Permiso denegado. Requerido: ${permissions.join(requireAll ? ' y ' : ' o ')}`);
24615
+ return router.createUrlTree([config.unauthorizedRoute]);
24616
+ };
24617
+ /**
24618
+ * Guard que verifica si el usuario es super admin.
24619
+ *
24620
+ * @example
24621
+ * ```typescript
24622
+ * import { authGuard, superAdminGuard } from 'valtech-components';
24623
+ *
24624
+ * const routes: Routes = [
24625
+ * {
24626
+ * path: 'super-admin',
24627
+ * canActivate: [authGuard, superAdminGuard],
24628
+ * loadComponent: () => import('./super-admin.page'),
24629
+ * },
24630
+ * ];
24631
+ * ```
24632
+ */
24633
+ const superAdminGuard = () => {
24634
+ const authService = inject(AuthService);
24635
+ const router = inject(Router);
24636
+ const config = inject(VALTECH_AUTH_CONFIG);
24637
+ if (authService.isSuperAdmin()) {
24638
+ return true;
24639
+ }
24640
+ console.warn('[ValtechAuth] Acceso de super admin requerido');
24641
+ return router.createUrlTree([config.unauthorizedRoute]);
24642
+ };
24643
+ /**
24644
+ * Guard que verifica si el usuario tiene un rol específico.
24645
+ *
24646
+ * @param roles - Rol o lista de roles requeridos (OR)
24647
+ * @returns Guard function
24648
+ *
24649
+ * @example
24650
+ * ```typescript
24651
+ * import { authGuard, roleGuard } from 'valtech-components';
24652
+ *
24653
+ * const routes: Routes = [
24654
+ * {
24655
+ * path: 'editor',
24656
+ * canActivate: [authGuard, roleGuard(['editor', 'admin'])],
24657
+ * loadComponent: () => import('./editor.page'),
24658
+ * },
24659
+ * ];
24660
+ * ```
24661
+ */
24662
+ function roleGuard(roles) {
24663
+ return () => {
24664
+ const authService = inject(AuthService);
24665
+ const router = inject(Router);
24666
+ const config = inject(VALTECH_AUTH_CONFIG);
24667
+ const roleArray = Array.isArray(roles) ? roles : [roles];
24668
+ const hasRole = roleArray.some((role) => authService.hasRole(role));
24669
+ if (hasRole) {
24670
+ return true;
24671
+ }
24672
+ console.warn(`[ValtechAuth] Rol requerido: ${roleArray.join(' o ')}`);
24673
+ return router.createUrlTree([config.unauthorizedRoute]);
24674
+ };
24675
+ }
24676
+
24677
+ /**
24678
+ * Valtech Auth Service
24679
+ *
24680
+ * Servicio de autenticación reutilizable para aplicaciones Angular.
24681
+ * Proporciona autenticación con AuthV2, MFA, sincronización entre pestañas,
24682
+ * y refresh proactivo de tokens.
24683
+ *
24684
+ * @example
24685
+ * ```typescript
24686
+ * // En main.ts
24687
+ * import { bootstrapApplication } from '@angular/platform-browser';
24688
+ * import { provideValtechAuth } from 'valtech-components';
24689
+ * import { environment } from './environments/environment';
24690
+ *
24691
+ * bootstrapApplication(AppComponent, {
24692
+ * providers: [
24693
+ * provideValtechAuth({
24694
+ * apiUrl: environment.apiUrl,
24695
+ * enableFirebaseIntegration: true,
24696
+ * }),
24697
+ * ],
24698
+ * });
24699
+ *
24700
+ * // En app.routes.ts
24701
+ * import { authGuard, guestGuard, permissionGuard } from 'valtech-components';
24702
+ *
24703
+ * const routes: Routes = [
24704
+ * { path: 'login', canActivate: [guestGuard], loadComponent: () => import('./login.page') },
24705
+ * { path: 'dashboard', canActivate: [authGuard], loadComponent: () => import('./dashboard.page') },
24706
+ * { path: 'admin', canActivate: [authGuard, permissionGuard('admin:*')], loadComponent: () => import('./admin.page') },
24707
+ * ];
24708
+ *
24709
+ * // En componentes
24710
+ * import { AuthService } from 'valtech-components';
24711
+ *
24712
+ * @Component({...})
24713
+ * export class LoginComponent {
24714
+ * private auth = inject(AuthService);
24715
+ *
24716
+ * async login() {
24717
+ * await firstValueFrom(this.auth.signin({ email, password }));
24718
+ * if (this.auth.mfaPending().required) {
24719
+ * // Mostrar UI de MFA
24720
+ * } else {
24721
+ * this.router.navigate(['/dashboard']);
24722
+ * }
24723
+ * }
24724
+ *
24725
+ * // En template: usar signals directamente
24726
+ * // {{ auth.user()?.email }}
24727
+ * // @if (auth.hasPermission('templates:edit')) { ... }
24728
+ * }
24729
+ * ```
24730
+ */
24731
+ // Tipos
24732
+
23276
24733
  /*
23277
24734
  * Public API Surface of valtech-components
23278
24735
  */
@@ -23281,5 +24738,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
23281
24738
  * Generated bundle index. Do not edit.
23282
24739
  */
23283
24740
 
23284
- export { ARTICLE_SPACING, AccordionComponent, ActionHeaderComponent, ActionType, AlertBoxComponent, ArticleBuilder, ArticleComponent, 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_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, DisplayComponent, DividerComponent, DownloadService, EmailInputComponent, ExpandableTextComponent, FabComponent, FileInputComponent, FirebaseService, FirestoreCollection, FirestoreService, FooterComponent, FooterLinksComponent, FormComponent, FormFooterComponent, FunHeaderComponent, GlowCardComponent, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, Icon, IconComponent, IconService, ImageComponent, InAppBrowserService, InfoComponent, InputType, ItemListComponent, LanguageSelectorComponent, LayeredCardComponent, LayoutComponent, LinkComponent, LinkProcessorService, LinksAccordionComponent, LinksCakeComponent, LocalStorageService, LocaleService, MODAL_SIZES, MOTION, MenuComponent, MessagingService, ModalService, MultiSelectSearchComponent, NavigationService, NoContentComponent, NotesBoxComponent, NumberFromToComponent, NumberInputComponent, NumberStepperComponent, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PLATFORM_CONFIGS, PageContentComponent, PageTemplateComponent, PageWrapperComponent, PaginationComponent, ParticipantCardComponent, PasswordInputComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, 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, ShareButtonsComponent, SimpleComponent, SkeletonComponent, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, TabsComponent, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TicketGridComponent, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, ToolbarActionType, ToolbarComponent, VALTECH_FIREBASE_CONFIG, WinnerDisplayComponent, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, buildPath, createGlowCardProps, createNumberFromToField, createTitleProps, extractPathParams, getCollectionPath, getDocumentId, goToTop, hasEmulators, isAtEnd, isCollectionPath, isDocumentPath, isValidPath, joinPath, maxLength, provideValtechFirebase, query, replaceSpecialChars, resolveColor, resolveInputDefaultValue };
24741
+ 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, DisplayComponent, DividerComponent, DownloadService, EmailInputComponent, ExpandableTextComponent, FabComponent, FileInputComponent, FirebaseService$1 as FirebaseService, FirestoreCollection, FirestoreService, FooterComponent, FooterLinksComponent, FormComponent, FormFooterComponent, FunHeaderComponent, GlowCardComponent, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, Icon, IconComponent, IconService, ImageComponent, InAppBrowserService, InfoComponent, InputType, ItemListComponent, LanguageSelectorComponent, LayeredCardComponent, LayoutComponent, LinkComponent, LinkProcessorService, LinksAccordionComponent, LinksCakeComponent, LocalStorageService, LocaleService, MODAL_SIZES, MOTION, MenuComponent, MessagingService, ModalService, MultiSelectSearchComponent, NavigationService, NoContentComponent, NotesBoxComponent, NumberFromToComponent, NumberInputComponent, NumberStepperComponent, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PLATFORM_CONFIGS, PageContentComponent, PageTemplateComponent, PageWrapperComponent, PaginationComponent, ParticipantCardComponent, PasswordInputComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, 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, ShareButtonsComponent, SimpleComponent, SkeletonComponent, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, TabsComponent, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TicketGridComponent, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, VALTECH_AUTH_CONFIG, VALTECH_FIREBASE_CONFIG, WinnerDisplayComponent, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, buildPath, createGlowCardProps, createNumberFromToField, createTitleProps, extractPathParams, getCollectionPath, getDocumentId, goToTop, guestGuard, hasEmulators, isAtEnd, isCollectionPath, isDocumentPath, isValidPath, joinPath, maxLength, permissionGuard, permissionGuardFromRoute, provideValtechAuth, provideValtechAuthInterceptor, provideValtechFirebase, query, replaceSpecialChars, resolveColor, resolveInputDefaultValue, roleGuard, superAdminGuard };
23285
24742
  //# sourceMappingURL=valtech-components.mjs.map