valtech-components 2.0.929 → 2.0.931
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/components/atoms/pattern/pattern.component.mjs +15 -11
- package/esm2022/lib/components/organisms/change-email-modal/change-email-modal.component.mjs +5 -3
- package/esm2022/lib/services/auth/auth.service.mjs +26 -2
- package/esm2022/lib/version.mjs +2 -2
- package/fesm2022/valtech-components.mjs +42 -12
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/atoms/pattern/pattern.component.d.ts +1 -0
- package/lib/components/atoms/rights-footer/rights-footer.component.d.ts +2 -2
- package/lib/components/atoms/text/text.component.d.ts +1 -1
- package/lib/components/atoms/user-avatar/user-avatar.component.d.ts +1 -1
- package/lib/components/molecules/content-reaction/content-reaction.component.d.ts +2 -2
- package/lib/components/molecules/features-list/features-list.component.d.ts +1 -1
- package/lib/components/organisms/article/article.component.d.ts +4 -4
- package/lib/components/organisms/landing-steps/landing-steps.component.d.ts +1 -1
- package/lib/services/auth/auth.service.d.ts +1 -0
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
package/esm2022/lib/version.mjs
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* Current version of valtech-components.
|
|
3
3
|
* This is automatically updated during the publish process.
|
|
4
4
|
*/
|
|
5
|
-
export const VERSION = '2.0.
|
|
6
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
5
|
+
export const VERSION = '2.0.931';
|
|
6
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVyc2lvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvdmVyc2lvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQUcsU0FBUyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDdXJyZW50IHZlcnNpb24gb2YgdmFsdGVjaC1jb21wb25lbnRzLlxuICogVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHVwZGF0ZWQgZHVyaW5nIHRoZSBwdWJsaXNoIHByb2Nlc3MuXG4gKi9cbmV4cG9ydCBjb25zdCBWRVJTSU9OID0gJzIuMC45MzEnO1xuIl19
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, InjectionToken, makeEnvironmentProviders, APP_INITIALIZER, ErrorHandler, Injectable, DestroyRef, Inject, signal, computed, PLATFORM_ID, isDevMode, Optional, runInInjectionContext, effect, Pipe, TemplateRef, ViewContainerRef, input, Directive, EventEmitter, Component, Input, Output, ChangeDetectionStrategy, HostBinding, HostListener, ViewChild, ChangeDetectorRef, ContentChild, output, Injector, isSignal, ElementRef, ViewEncapsulation } from '@angular/core';
|
|
2
|
+
import { inject, InjectionToken, makeEnvironmentProviders, APP_INITIALIZER, ErrorHandler, Injectable, DestroyRef, Inject, signal, computed, PLATFORM_ID, isDevMode, Optional, runInInjectionContext, effect, Pipe, TemplateRef, ViewContainerRef, input, Directive, EventEmitter, Component, Input, Output, ChangeDetectionStrategy, HostBinding, HostListener, NgZone, ViewChild, ChangeDetectorRef, ContentChild, output, Injector, isSignal, ElementRef, ViewEncapsulation } from '@angular/core';
|
|
3
3
|
import { BehaviorSubject, throwError, Subject, map, distinctUntilChanged, filter as filter$1, take as take$1, firstValueFrom, of, from, EMPTY, Observable, interval, debounceTime, switchMap as switchMap$1, catchError as catchError$1, takeUntil, isObservable, shareReplay, race, timer } from 'rxjs';
|
|
4
4
|
import { catchError, switchMap, finalize, filter, take, map as map$1, tap, retry, timeout, debounceTime as debounceTime$1, takeUntil as takeUntil$1 } from 'rxjs/operators';
|
|
5
5
|
import * as i1$3 from '@angular/common/http';
|
|
@@ -54,7 +54,7 @@ import 'prismjs/components/prism-json';
|
|
|
54
54
|
* Current version of valtech-components.
|
|
55
55
|
* This is automatically updated during the publish process.
|
|
56
56
|
*/
|
|
57
|
-
const VERSION = '2.0.
|
|
57
|
+
const VERSION = '2.0.931';
|
|
58
58
|
|
|
59
59
|
// Control de estado de refresco (singleton a nivel de módulo)
|
|
60
60
|
let isRefreshing = false;
|
|
@@ -8081,6 +8081,13 @@ class AuthService {
|
|
|
8081
8081
|
// cualquier listener Firestore (ej. el inbox de notificaciones) cuelga.
|
|
8082
8082
|
// Fire-and-forget: NO debe demorar el resolve de initialize().
|
|
8083
8083
|
void this.ensureFirebaseSessionOnBootstrap();
|
|
8084
|
+
// 5. Listener RBAC Firestore — re-establecer tras reload de página.
|
|
8085
|
+
// handleSuccessfulAuth lo configura en el login inicial, pero no sobrevive
|
|
8086
|
+
// recargas: initialize() restaura el state desde storage pero no el listener.
|
|
8087
|
+
// setupFirestoreRBACSync espera internamente a que Firebase Auth esté lista.
|
|
8088
|
+
if (claims?.uid) {
|
|
8089
|
+
this.setupFirestoreRBACSync(claims.uid);
|
|
8090
|
+
}
|
|
8084
8091
|
}
|
|
8085
8092
|
else if (storedState.refreshToken) {
|
|
8086
8093
|
// 4. Token expirado pero hay refresh token.
|
|
@@ -8107,6 +8114,9 @@ class AuthService {
|
|
|
8107
8114
|
if (expiredClaims.org) {
|
|
8108
8115
|
this.stateService.updateActiveOrg(expiredClaims.org);
|
|
8109
8116
|
}
|
|
8117
|
+
if (expiredClaims.uid) {
|
|
8118
|
+
this.setupFirestoreRBACSync(expiredClaims.uid);
|
|
8119
|
+
}
|
|
8110
8120
|
}
|
|
8111
8121
|
// Refresh en segundo plano — NO se hace await: initialize() resuelve ya.
|
|
8112
8122
|
firstValueFrom(this.refreshAccessToken()).catch(() => {
|
|
@@ -8854,6 +8864,20 @@ class AuthService {
|
|
|
8854
8864
|
if (!this.config?.enableFirestoreRBAC || !this.firestoreInstance)
|
|
8855
8865
|
return;
|
|
8856
8866
|
this.teardownFirestoreRBACSync();
|
|
8867
|
+
if (!this.firebaseService || this.firebaseService.firebaseAuthReady()) {
|
|
8868
|
+
// Firebase not used or already authenticated — attach listener now.
|
|
8869
|
+
this._attachFirestoreRBACListener(userId);
|
|
8870
|
+
}
|
|
8871
|
+
else {
|
|
8872
|
+
// Firebase Auth not ready yet. Firestore permission-denied errors terminate
|
|
8873
|
+
// onSnapshot permanently (no automatic retry when auth state changes).
|
|
8874
|
+
// Wait until the user is authenticated, then attach.
|
|
8875
|
+
this.firebaseService.firebaseAuthReady$
|
|
8876
|
+
.pipe(filter(ready => ready), take(1))
|
|
8877
|
+
.subscribe(() => this._attachFirestoreRBACListener(userId));
|
|
8878
|
+
}
|
|
8879
|
+
}
|
|
8880
|
+
_attachFirestoreRBACListener(userId) {
|
|
8857
8881
|
const docRef = doc(this.firestoreInstance, 'users', userId);
|
|
8858
8882
|
this.firestoreRBACUnsubscribe = onSnapshot(docRef, snap => {
|
|
8859
8883
|
const rbac = snap.data()?.['rbac'];
|
|
@@ -14341,6 +14365,7 @@ class PatternComponent {
|
|
|
14341
14365
|
}
|
|
14342
14366
|
constructor() {
|
|
14343
14367
|
this.sanitizer = inject(DomSanitizer);
|
|
14368
|
+
this.ngZone = inject(NgZone);
|
|
14344
14369
|
this.cols = signal(12);
|
|
14345
14370
|
this.rows = signal(4);
|
|
14346
14371
|
this.seed = signal(this.randomSeed());
|
|
@@ -14391,6 +14416,8 @@ class PatternComponent {
|
|
|
14391
14416
|
// con un seed nuevo. Visualmente: el patrón cambia de vez en cuando.
|
|
14392
14417
|
// Si `tilesPerTick > 0` y < total tiles, hace staggered (reemplaza solo
|
|
14393
14418
|
// N tiles en vez de toda la grid). Default tilesPerTick=0 → reseed total.
|
|
14419
|
+
// El setInterval corre FUERA de Zone.js para no disparar un CD completo
|
|
14420
|
+
// de toda la app en cada tick — solo val-pattern se actualiza vía señales.
|
|
14394
14421
|
effect(onCleanup => {
|
|
14395
14422
|
const isAnimated = this.animated();
|
|
14396
14423
|
const interval = this.reshuffleInterval();
|
|
@@ -14400,14 +14427,16 @@ class PatternComponent {
|
|
|
14400
14427
|
this.timer = undefined;
|
|
14401
14428
|
if (!isAnimated)
|
|
14402
14429
|
return;
|
|
14403
|
-
this.
|
|
14404
|
-
|
|
14405
|
-
|
|
14406
|
-
|
|
14407
|
-
|
|
14408
|
-
|
|
14409
|
-
|
|
14410
|
-
|
|
14430
|
+
this.ngZone.runOutsideAngular(() => {
|
|
14431
|
+
this.timer = setInterval(() => {
|
|
14432
|
+
if (perTick > 0) {
|
|
14433
|
+
this.mutateRandomTiles(perTick);
|
|
14434
|
+
}
|
|
14435
|
+
else {
|
|
14436
|
+
this.seed.set(this.randomSeed());
|
|
14437
|
+
}
|
|
14438
|
+
}, interval);
|
|
14439
|
+
});
|
|
14411
14440
|
onCleanup(() => {
|
|
14412
14441
|
if (this.timer) {
|
|
14413
14442
|
clearInterval(this.timer);
|
|
@@ -31641,7 +31670,7 @@ class ChangeEmailModalComponent {
|
|
|
31641
31670
|
this.toast.show({ message, duration: 3500 });
|
|
31642
31671
|
}
|
|
31643
31672
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChangeEmailModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
31644
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ChangeEmailModalComponent, isStandalone: true, selector: "val-change-email-modal", inputs: { isOpen: "isOpen" }, outputs: { changed: "changed", dismissed: "dismissed" }, ngImport: i0, template: "<ion-modal [isOpen]=\"isOpen\" (didDismiss)=\"close()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"close()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (_step() === 'loading') {\n <div class=\"modal-loading\">\n <ion-spinner name=\"crescent\"></ion-spinner>\n </div>\n } @else if (_step() === 'no-password') {\n <val-display [props]=\"{ content: noPasswordTitle(), size: 'small', color: 'dark' }\" />\n <val-
|
|
31673
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ChangeEmailModalComponent, isStandalone: true, selector: "val-change-email-modal", inputs: { isOpen: "isOpen" }, outputs: { changed: "changed", dismissed: "dismissed" }, ngImport: i0, template: "<ion-modal [isOpen]=\"isOpen\" (didDismiss)=\"close()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"close()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (_step() === 'loading') {\n <div class=\"modal-loading\">\n <ion-spinner name=\"crescent\"></ion-spinner>\n </div>\n } @else if (_step() === 'no-password') {\n <val-display [props]=\"{ content: noPasswordTitle(), size: 'small', color: 'dark' }\" />\n <val-title [props]=\"{ content: noPasswordHint(), size: 'large', color: 'dark', bold: false }\" />\n <ion-button expand=\"block\" fill=\"solid\" color=\"dark\" (click)=\"close()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n } @else if (_step() === 'step1') {\n <val-form [props]=\"step1Props()\" (onSubmit)=\"handleStep1($event)\" />\n } @else if (_step() === 'step2') {\n <val-form [props]=\"step2Props()\" (onSubmit)=\"handleStep2($event)\" />\n } @else if (_step() === 'step3') {\n <val-form [props]=\"step3Props()\" (onSubmit)=\"handleStep3($event)\" />\n }\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".modal-form-section{display:flex;flex-direction:column;gap:16px;max-width:420px;margin:0 auto;padding-top:8px}.modal-loading{display:flex;justify-content:center;padding:40px 0}\n"], dependencies: [{ 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: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonModal, selector: "ion-modal" }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: FormComponent, selector: "val-form", inputs: ["props"], outputs: ["onSubmit", "onInvalid", "onSelectChange"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }] }); }
|
|
31645
31674
|
}
|
|
31646
31675
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChangeEmailModalComponent, decorators: [{
|
|
31647
31676
|
type: Component,
|
|
@@ -31656,7 +31685,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
31656
31685
|
FormComponent,
|
|
31657
31686
|
DisplayComponent,
|
|
31658
31687
|
TextComponent,
|
|
31659
|
-
|
|
31688
|
+
TitleComponent,
|
|
31689
|
+
], template: "<ion-modal [isOpen]=\"isOpen\" (didDismiss)=\"close()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"close()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (_step() === 'loading') {\n <div class=\"modal-loading\">\n <ion-spinner name=\"crescent\"></ion-spinner>\n </div>\n } @else if (_step() === 'no-password') {\n <val-display [props]=\"{ content: noPasswordTitle(), size: 'small', color: 'dark' }\" />\n <val-title [props]=\"{ content: noPasswordHint(), size: 'large', color: 'dark', bold: false }\" />\n <ion-button expand=\"block\" fill=\"solid\" color=\"dark\" (click)=\"close()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n } @else if (_step() === 'step1') {\n <val-form [props]=\"step1Props()\" (onSubmit)=\"handleStep1($event)\" />\n } @else if (_step() === 'step2') {\n <val-form [props]=\"step2Props()\" (onSubmit)=\"handleStep2($event)\" />\n } @else if (_step() === 'step3') {\n <val-form [props]=\"step3Props()\" (onSubmit)=\"handleStep3($event)\" />\n }\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".modal-form-section{display:flex;flex-direction:column;gap:16px;max-width:420px;margin:0 auto;padding-top:8px}.modal-loading{display:flex;justify-content:center;padding:40px 0}\n"] }]
|
|
31660
31690
|
}], propDecorators: { isOpen: [{
|
|
31661
31691
|
type: Input
|
|
31662
31692
|
}], changed: [{
|