valtech-components 4.0.939 → 4.0.941
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/organisms/form/form.component.mjs +35 -3
- package/esm2022/lib/components/organisms/login/login.component.mjs +24 -4
- package/esm2022/lib/directives/feature-guard.directive.mjs +48 -0
- package/esm2022/lib/services/feature-control.service.mjs +117 -0
- package/esm2022/lib/services/qr-generator/qrbrand.mjs +89 -0
- package/esm2022/lib/version.mjs +2 -2
- package/esm2022/public-api.mjs +7 -2
- package/fesm2022/valtech-components.mjs +305 -7
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/organisms/form/form.component.d.ts +24 -0
- package/lib/components/organisms/login/login.component.d.ts +16 -0
- package/lib/directives/feature-guard.directive.d.ts +21 -0
- package/lib/services/feature-control.service.d.ts +50 -0
- package/lib/services/qr-generator/qrbrand.d.ts +50 -0
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
- package/public-api.d.ts +4 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, makeEnvironmentProviders, inject, APP_INITIALIZER, ErrorHandler, Injectable, DestroyRef, Inject, signal, computed, PLATFORM_ID, isDevMode, Optional, runInInjectionContext, effect, Pipe, Component, Input, ChangeDetectionStrategy, input, output, Injector, TemplateRef, ViewContainerRef, Directive, ElementRef, Renderer2, HostListener, EventEmitter, Output, HostBinding, SecurityContext, NgZone, ViewChild, ChangeDetectorRef, ContentChild, model, ViewEncapsulation, untracked, viewChild, isSignal } from '@angular/core';
|
|
2
|
+
import { InjectionToken, makeEnvironmentProviders, inject, APP_INITIALIZER, ErrorHandler, Injectable, DestroyRef, Inject, signal, computed, PLATFORM_ID, isDevMode, Optional, runInInjectionContext, effect, Pipe, Component, Input, ChangeDetectionStrategy, input, output, Injector, TemplateRef, ViewContainerRef, Directive, ElementRef, Renderer2, HostListener, EventEmitter, Output, HostBinding, SecurityContext, NgZone, ViewChild, ChangeDetectorRef, ContentChild, model, ViewEncapsulation, untracked, ViewChildren, viewChild, isSignal } from '@angular/core';
|
|
3
3
|
import { BehaviorSubject, throwError, Subject, map, distinctUntilChanged, filter as filter$1, take as take$1, firstValueFrom, timeout as timeout$1, catchError as catchError$1, of, from, EMPTY, Observable, interval, defer, timer, merge, concat, debounceTime, switchMap as switchMap$1, takeUntil, isObservable, forkJoin, race, shareReplay as shareReplay$1, tap as tap$1 } from 'rxjs';
|
|
4
4
|
import { catchError, switchMap, finalize, filter, take, timeout, map as map$1, tap, shareReplay, distinctUntilChanged as distinctUntilChanged$1, retry, debounceTime as debounceTime$1, takeUntil as takeUntil$1 } from 'rxjs/operators';
|
|
5
5
|
import * as i1$3 from '@angular/common/http';
|
|
@@ -66,7 +66,7 @@ import fixWebmDuration from 'fix-webm-duration';
|
|
|
66
66
|
* Current version of valtech-components.
|
|
67
67
|
* This is automatically updated during the publish process.
|
|
68
68
|
*/
|
|
69
|
-
const VERSION = '4.0.
|
|
69
|
+
const VERSION = '4.0.941';
|
|
70
70
|
|
|
71
71
|
function evaluateValtechAccess(rule, context, features = {}, visitedFeatures = new Set()) {
|
|
72
72
|
if (rule == null)
|
|
@@ -11586,6 +11586,163 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
11586
11586
|
args: ['pointerdown', ['$event']]
|
|
11587
11587
|
}] } });
|
|
11588
11588
|
|
|
11589
|
+
class FeatureControlService {
|
|
11590
|
+
constructor(http, analytics) {
|
|
11591
|
+
this.http = http;
|
|
11592
|
+
this.analytics = analytics;
|
|
11593
|
+
this.features = signal(new Map());
|
|
11594
|
+
this.isLoaded = signal(false);
|
|
11595
|
+
this.previousState = new Map();
|
|
11596
|
+
}
|
|
11597
|
+
logFeatureEvent(key, enabled, previousEnabled) {
|
|
11598
|
+
if (!this.analytics)
|
|
11599
|
+
return;
|
|
11600
|
+
try {
|
|
11601
|
+
if (previousEnabled === null) {
|
|
11602
|
+
// Carga inicial
|
|
11603
|
+
this.analytics.logEvent('feature_loaded', {
|
|
11604
|
+
feature_key: key,
|
|
11605
|
+
feature_enabled: enabled,
|
|
11606
|
+
});
|
|
11607
|
+
}
|
|
11608
|
+
else if (previousEnabled !== enabled) {
|
|
11609
|
+
// Transición de estado
|
|
11610
|
+
this.analytics.logEvent('feature_changed', {
|
|
11611
|
+
feature_key: key,
|
|
11612
|
+
previous_state: previousEnabled ? 'enabled' : 'disabled',
|
|
11613
|
+
current_state: enabled ? 'enabled' : 'disabled',
|
|
11614
|
+
});
|
|
11615
|
+
}
|
|
11616
|
+
}
|
|
11617
|
+
catch (err) {
|
|
11618
|
+
console.warn(`Failed to log feature event for ${key}:`, err);
|
|
11619
|
+
}
|
|
11620
|
+
}
|
|
11621
|
+
/**
|
|
11622
|
+
* Load user features from backend.
|
|
11623
|
+
* Call this during app initialization (AppComponent ctor or effect).
|
|
11624
|
+
* Logs feature state changes to Firebase Analytics.
|
|
11625
|
+
*/
|
|
11626
|
+
async loadUserFeatures() {
|
|
11627
|
+
try {
|
|
11628
|
+
const response = await firstValueFrom(this.http.get('/v2/user/features'));
|
|
11629
|
+
const map = new Map();
|
|
11630
|
+
response.forEach(f => {
|
|
11631
|
+
const previousEnabled = this.previousState.get(f.key) ?? null;
|
|
11632
|
+
this.logFeatureEvent(f.key, f.enabled, previousEnabled);
|
|
11633
|
+
this.previousState.set(f.key, f.enabled);
|
|
11634
|
+
map.set(f.key, f.enabled);
|
|
11635
|
+
});
|
|
11636
|
+
this.features.set(map);
|
|
11637
|
+
this.isLoaded.set(true);
|
|
11638
|
+
}
|
|
11639
|
+
catch (error) {
|
|
11640
|
+
console.error('Failed to load feature control:', error);
|
|
11641
|
+
// Fallback: assume all features enabled on error (optimistic)
|
|
11642
|
+
this.isLoaded.set(true);
|
|
11643
|
+
}
|
|
11644
|
+
}
|
|
11645
|
+
/**
|
|
11646
|
+
* Check if a feature is enabled for the current user.
|
|
11647
|
+
* Returns true if feature is not found (optimistic default).
|
|
11648
|
+
* If rollout percentage is set, uses consistent hashing for canary rollouts.
|
|
11649
|
+
*/
|
|
11650
|
+
isEnabled(featureKey) {
|
|
11651
|
+
const featuresMap = this.features();
|
|
11652
|
+
const feature = featuresMap.get(featureKey);
|
|
11653
|
+
// Not in map: default to enabled (optimistic)
|
|
11654
|
+
if (feature === undefined)
|
|
11655
|
+
return true;
|
|
11656
|
+
// Not enabled: return false
|
|
11657
|
+
if (!feature)
|
|
11658
|
+
return false;
|
|
11659
|
+
// TODO: Implement rollout percentage check with hash
|
|
11660
|
+
// For now, if enabled and no rollout, it's enabled for everyone
|
|
11661
|
+
return true;
|
|
11662
|
+
}
|
|
11663
|
+
/**
|
|
11664
|
+
* Get a computed signal for a feature.
|
|
11665
|
+
* Use in templates: *ngIf="featureEnabled('oauth_facebook')()"
|
|
11666
|
+
* Or in component: featureEnabled('payment_settings').
|
|
11667
|
+
*/
|
|
11668
|
+
featureEnabled(featureKey) {
|
|
11669
|
+
return () => this.isEnabled(featureKey);
|
|
11670
|
+
}
|
|
11671
|
+
/**
|
|
11672
|
+
* Get all features for debugging (admin only).
|
|
11673
|
+
*/
|
|
11674
|
+
getAllFeatures() {
|
|
11675
|
+
return this.features();
|
|
11676
|
+
}
|
|
11677
|
+
/**
|
|
11678
|
+
* Check if features have been loaded.
|
|
11679
|
+
*/
|
|
11680
|
+
isReady() {
|
|
11681
|
+
return this.isLoaded();
|
|
11682
|
+
}
|
|
11683
|
+
/**
|
|
11684
|
+
* Watch for feature changes (for testing/demo purposes).
|
|
11685
|
+
*/
|
|
11686
|
+
watchFeatures() {
|
|
11687
|
+
return this.features;
|
|
11688
|
+
}
|
|
11689
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FeatureControlService, deps: [{ token: i1$3.HttpClient }, { token: AnalyticsService, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
11690
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FeatureControlService, providedIn: 'root' }); }
|
|
11691
|
+
}
|
|
11692
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FeatureControlService, decorators: [{
|
|
11693
|
+
type: Injectable,
|
|
11694
|
+
args: [{
|
|
11695
|
+
providedIn: 'root',
|
|
11696
|
+
}]
|
|
11697
|
+
}], ctorParameters: () => [{ type: i1$3.HttpClient }, { type: AnalyticsService, decorators: [{
|
|
11698
|
+
type: Optional
|
|
11699
|
+
}] }] });
|
|
11700
|
+
|
|
11701
|
+
/**
|
|
11702
|
+
* Structural directive to hide elements when a feature is disabled.
|
|
11703
|
+
*
|
|
11704
|
+
* Usage: <button *valFeatureGuard="'oauth_facebook'">Sign in with Facebook</button>
|
|
11705
|
+
* If oauth_facebook is disabled, the button is not rendered.
|
|
11706
|
+
*/
|
|
11707
|
+
class FeatureGuardDirective {
|
|
11708
|
+
set valFeatureGuard(featureKey) {
|
|
11709
|
+
this.featureKey = featureKey;
|
|
11710
|
+
this.updateVisibility();
|
|
11711
|
+
}
|
|
11712
|
+
constructor(templateRef, viewContainer, featureControl) {
|
|
11713
|
+
this.templateRef = templateRef;
|
|
11714
|
+
this.viewContainer = viewContainer;
|
|
11715
|
+
this.featureControl = featureControl;
|
|
11716
|
+
this.featureKey = '';
|
|
11717
|
+
}
|
|
11718
|
+
ngOnInit() {
|
|
11719
|
+
this.updateVisibility();
|
|
11720
|
+
}
|
|
11721
|
+
updateVisibility() {
|
|
11722
|
+
if (!this.featureKey) {
|
|
11723
|
+
return;
|
|
11724
|
+
}
|
|
11725
|
+
const isEnabled = this.featureControl.isEnabled(this.featureKey);
|
|
11726
|
+
if (isEnabled) {
|
|
11727
|
+
this.viewContainer.createEmbeddedView(this.templateRef);
|
|
11728
|
+
}
|
|
11729
|
+
else {
|
|
11730
|
+
this.viewContainer.clear();
|
|
11731
|
+
}
|
|
11732
|
+
}
|
|
11733
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FeatureGuardDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: FeatureControlService }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
11734
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: FeatureGuardDirective, isStandalone: true, selector: "[valFeatureGuard]", inputs: { valFeatureGuard: "valFeatureGuard" }, ngImport: i0 }); }
|
|
11735
|
+
}
|
|
11736
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FeatureGuardDirective, decorators: [{
|
|
11737
|
+
type: Directive,
|
|
11738
|
+
args: [{
|
|
11739
|
+
selector: '[valFeatureGuard]',
|
|
11740
|
+
standalone: true,
|
|
11741
|
+
}]
|
|
11742
|
+
}], ctorParameters: () => [{ type: i0.TemplateRef }, { type: i0.ViewContainerRef }, { type: FeatureControlService }], propDecorators: { valFeatureGuard: [{
|
|
11743
|
+
type: Input
|
|
11744
|
+
}] } });
|
|
11745
|
+
|
|
11589
11746
|
/**
|
|
11590
11747
|
* Presets de botón por defecto provistos por la librería.
|
|
11591
11748
|
*
|
|
@@ -36723,7 +36880,8 @@ class FormComponent {
|
|
|
36723
36880
|
/** Sugerencias descartadas por el usuario, para no volver a insistir. */
|
|
36724
36881
|
this.suggestionDismissed = new Set();
|
|
36725
36882
|
}
|
|
36726
|
-
|
|
36883
|
+
/** Arma la definición de controles (valor inicial + validadores) desde `props`. */
|
|
36884
|
+
buildFormControlsDef() {
|
|
36727
36885
|
const formControls = {};
|
|
36728
36886
|
this.props.sections.forEach(section => {
|
|
36729
36887
|
section.fields.forEach(field => {
|
|
@@ -36746,7 +36904,38 @@ class FormComponent {
|
|
|
36746
36904
|
}
|
|
36747
36905
|
});
|
|
36748
36906
|
});
|
|
36749
|
-
|
|
36907
|
+
return formControls;
|
|
36908
|
+
}
|
|
36909
|
+
/**
|
|
36910
|
+
* Reconstruye el `FormGroup` desde cero, con los valores iniciales de `props`
|
|
36911
|
+
* actuales (no los que el usuario haya tecleado desde entonces).
|
|
36912
|
+
*
|
|
36913
|
+
* Existe para el caso en que Angular NO destruye el componente entre dos usos
|
|
36914
|
+
* — típicamente `IonicRouteStrategy`, que cachea la página ruteada al navegar
|
|
36915
|
+
* afuera y la reutiliza al volver sin correr `ngOnInit` de nuevo. Sin esto,
|
|
36916
|
+
* un form de login mantiene lo que el usuario anterior tecleó después de
|
|
36917
|
+
* cerrar sesión y volver a `/login`: el `FormGroup` se construyó UNA vez y
|
|
36918
|
+
* nadie lo tocó desde entonces.
|
|
36919
|
+
*
|
|
36920
|
+
* Reconstruye el `FormGroup` entero (no `.reset(values)`) porque la
|
|
36921
|
+
* definición trae `[valor, validators]` por control, no valores planos —
|
|
36922
|
+
* reusar `buildFormControlsDef()` tal cual evita mantener dos formas de
|
|
36923
|
+
* calcular "cuál es el valor inicial" que puedan desincronizarse.
|
|
36924
|
+
*
|
|
36925
|
+
* El caller (típicamente `val-login`, vía `ionViewWillEnter`) decide CUÁNDO
|
|
36926
|
+
* llamarlo — acá no hay heurística de "cuándo resetear", porque un form de
|
|
36927
|
+
* varios pasos sí podría querer conservar lo tecleado al volver a una
|
|
36928
|
+
* pestaña.
|
|
36929
|
+
*/
|
|
36930
|
+
resetForm() {
|
|
36931
|
+
if (!this.form)
|
|
36932
|
+
return;
|
|
36933
|
+
this.form = this.fb.group(this.buildFormControlsDef());
|
|
36934
|
+
this.value.set(this.form.getRawValue());
|
|
36935
|
+
this.valid.set(this.form.valid);
|
|
36936
|
+
}
|
|
36937
|
+
ngOnInit() {
|
|
36938
|
+
this.form = this.fb.group(this.buildFormControlsDef());
|
|
36750
36939
|
this.props.sections.forEach(section => {
|
|
36751
36940
|
section.fields
|
|
36752
36941
|
.filter(x => x.type === this.types.SELECT ||
|
|
@@ -50673,6 +50862,23 @@ class LoginComponent {
|
|
|
50673
50862
|
queueMicrotask(() => this.openMFAVerifyModal());
|
|
50674
50863
|
}
|
|
50675
50864
|
}
|
|
50865
|
+
/**
|
|
50866
|
+
* Ionic (`IonicRouteStrategy`) no destruye la página de login al navegar
|
|
50867
|
+
* afuera — la "detach"-ea y la reutiliza si el usuario vuelve a la misma
|
|
50868
|
+
* ruta, así que `ngOnInit` no vuelve a correr. `val-form` arma su
|
|
50869
|
+
* `FormGroup` UNA sola vez en su propio `ngOnInit`; sin este hook, cerrar
|
|
50870
|
+
* sesión y volver a `/login` mostraba el email y la contraseña que la
|
|
50871
|
+
* sesión anterior había tecleado.
|
|
50872
|
+
*
|
|
50873
|
+
* `ionViewWillEnter` es el gancho de Ionic pensado exactamente para esto:
|
|
50874
|
+
* corre en CADA entrada a la vista, sea la primera vez o una reutilización
|
|
50875
|
+
* desde caché. Ionic lo invoca por duck-typing sobre cualquier componente
|
|
50876
|
+
* de la jerarquía que lo declare, sin necesidad de implementar la interfaz
|
|
50877
|
+
* `ViewWillEnter` (mismo patrón que `SelectSearchComponent` en esta lib).
|
|
50878
|
+
*/
|
|
50879
|
+
ionViewWillEnter() {
|
|
50880
|
+
this.forms?.forEach((f) => f.resetForm());
|
|
50881
|
+
}
|
|
50676
50882
|
ngOnDestroy() {
|
|
50677
50883
|
this.stopResendCooldown();
|
|
50678
50884
|
this.stopResetResendCooldown();
|
|
@@ -50680,7 +50886,7 @@ class LoginComponent {
|
|
|
50680
50886
|
this.stopListeningForOAuthReturn();
|
|
50681
50887
|
}
|
|
50682
50888
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LoginComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
50683
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LoginComponent, isStandalone: true, selector: "val-login", inputs: { props: "props" }, outputs: { onSuccess: "onSuccess", onError: "onError", onMFARequired: "onMFARequired" }, ngImport: i0, template: "<div class=\"val-login\" [class.val-login--card]=\"config.showCard\">\n <!-- Logo \u2014 default de marca (--main-logo) si el consumer no pasa logo -->\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n\n <!-- Login Form -->\n <val-form [props]=\"loginFormProps()\" (onSubmit)=\"loginHandler($event)\" />\n\n <!-- OAuth Section -->\n @if (config.showOAuth && config.oauthProviders.length > 0) {\n <div class=\"oauth-separator\">\n <span>{{ t('orContinueWith') }}</span>\n </div>\n\n <div class=\"oauth-buttons\">\n @for (provider of config.oauthProviders; track provider) {\n <val-button\n [props]=\"oauthButtonProps(provider)\"\n (onClick)=\"loginWithOAuth(provider)\"\n />\n }\n </div>\n }\n\n <!-- Register Link -->\n @if (config.showRegister) {\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('noAccount') }}\n <a (click)=\"openRegisterModal()\">{{ t('register') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Forgot Password Link -->\n @if (config.showForgotPassword) {\n <div class=\"auth-link forgot-password\">\n <ion-text color=\"dark\">\n {{ t('forgotLink') }}\n <a (click)=\"openForgotPasswordModal()\">{{ t('recoverPassword') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Legal Notice -->\n @if (props.legal) {\n <div class=\"legal-notice\">\n <ion-text color=\"dark\">\n <p>\n {{ t('legalPrefix') }} @if (resolvedCompanyLink) {\n <a [href]=\"resolvedCompanyLink\" target=\"_blank\" rel=\"noopener noreferrer\"\n ><strong>{{ props.legal.companyName }}</strong></a\n >\n } @else {\n <strong>{{ props.legal.companyName }}</strong>\n } {{ t('legalSuffix') }} @if (props.legal.termsLink) {\n <a [href]=\"props.legal.termsLink\">{{ t('termsAndConditions') }}</a>\n } @else {\n <span>{{ t('termsAndConditions') }}</span>\n } {{ t('and') }} @if (props.legal.privacyLink) {\n <a [href]=\"props.legal.privacyLink\">{{ t('privacyPolicy') }}</a>\n } @else {\n <span>{{ t('privacyPolicy') }}</span>\n }.\n </p>\n </ion-text>\n </div>\n }\n</div>\n\n<!-- Register Modal -->\n<ion-modal [isOpen]=\"isRegisterModalOpen\" (didDismiss)=\"closeRegisterModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeRegisterModal()\">\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 <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"registerFormProps()\" (onSubmit)=\"registerHandler($event)\" />\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('hasAccount') }}\n <a (click)=\"onRegisterSwitchToLogin()\">{{ t('signIn') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Verify Email Modal -->\n<ion-modal [isOpen]=\"isVerifyModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeVerifyModal()\">\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 <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"verifyFormProps()\" (onSubmit)=\"verifyHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Forgot Password Modal -->\n<ion-modal [isOpen]=\"isForgotPasswordModalOpen\" (didDismiss)=\"closeForgotPasswordModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeForgotPasswordModal()\">\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 <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"forgotPasswordFormProps()\" (onSubmit)=\"forgotPasswordHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Reset Password Modal -->\n<ion-modal [isOpen]=\"isResetPasswordModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeResetPasswordModal()\">\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 <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"resetPasswordFormProps()\" (onSubmit)=\"resetPasswordHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resetResendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resetResendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendResetCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Verify Modal -->\n<ion-modal [isOpen]=\"isMFAVerifyModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"onMFAVerifyDismissed()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeMFAVerifyModal()\">\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 <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"mfaVerifyFormProps()\" (onSubmit)=\"verifyMFAHandler($event)\" />\n @if (mfaMethod() === 'TOTP') {\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n @if (mfaUseBackupCode()) {\n <a (click)=\"toggleMFABackupCode()\">{{ t('mfaUseTotpAction') }}</a>\n } @else { {{ t('mfaUseBackupLink') }}\n <a (click)=\"toggleMFABackupCode()\">{{ t('mfaUseBackupAction') }}</a>\n }\n </ion-text>\n </div>\n }\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('mfaLostBackupLink') }}\n <a (click)=\"openMFAResetModal()\">{{ t('mfaResetAction') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Reset Modal (B) \u2014 recovery por email cuando no hay backup codes -->\n<ion-modal [isOpen]=\"isMFAResetModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"closeMFAResetModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeMFAResetModal()\">\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 <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n @if (mfaResetStep() === 'request') {\n <val-form [props]=\"mfaResetRequestFormProps()\" (onSubmit)=\"mfaResetRequestHandler($event)\" />\n } @else {\n <val-form [props]=\"mfaResetConfirmFormProps()\" (onSubmit)=\"mfaResetConfirmHandler($event)\" />\n }\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".val-login{width:100%}.val-login--card{padding:1rem .75rem;background:var(--ion-color-light);border-radius:16px;box-shadow:0 2px 8px #00000014}.logo-container{max-width:130px;margin-bottom:1.5rem}.auth-link{text-align:center;margin-top:1rem;font-size:.9rem}.auth-link a{color:var(--ion-color-primary);text-decoration:none;font-weight:500;cursor:pointer}.auth-link a:hover{text-decoration:underline}.oauth-separator{display:flex;align-items:center;margin:1.5rem 0}.oauth-separator:before,.oauth-separator:after{content:\"\";flex:1;height:1px;background:var(--ion-color-medium-tint)}.oauth-separator span{padding:0 1rem;color:var(--ion-color-dark);font-size:.85rem}.oauth-buttons{margin-bottom:1rem;display:flex;flex-direction:column;gap:.5rem}.oauth-buttons val-button{--border-width: 1px}.oauth-buttons ion-icon{font-size:1.2rem;margin-right:.5rem}.legal-notice{margin-top:1.5rem;padding-top:1rem;border-top:1px solid var(--ion-color-medium-tint)}.legal-notice p{font-size:.75rem;line-height:1.5;text-align:center;margin:0}.legal-notice a{color:var(--ion-color-primary);text-decoration:none}.legal-notice a:hover{text-decoration:underline}.resend-link{text-align:center;margin-top:1rem;font-size:.9rem}.resend-link a{color:var(--ion-color-primary);cursor:pointer;font-weight:500}.resend-link a:hover{text-decoration:underline}.resend-link .cooldown{color:var(--ion-color-medium)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: FormComponent, selector: "val-form", inputs: ["props"], outputs: ["onSubmit", "onValueChange", "onInvalid", "onSelectChange"] }, { kind: "component", type: ImageComponent, selector: "val-image", inputs: ["props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }] }); }
|
|
50889
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LoginComponent, isStandalone: true, selector: "val-login", inputs: { props: "props" }, outputs: { onSuccess: "onSuccess", onError: "onError", onMFARequired: "onMFARequired" }, viewQueries: [{ propertyName: "forms", predicate: FormComponent, descendants: true }], ngImport: i0, template: "<div class=\"val-login\" [class.val-login--card]=\"config.showCard\">\n <!-- Logo \u2014 default de marca (--main-logo) si el consumer no pasa logo -->\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n\n <!-- Login Form -->\n <val-form [props]=\"loginFormProps()\" (onSubmit)=\"loginHandler($event)\" />\n\n <!-- OAuth Section -->\n @if (config.showOAuth && config.oauthProviders.length > 0) {\n <div class=\"oauth-separator\">\n <span>{{ t('orContinueWith') }}</span>\n </div>\n\n <div class=\"oauth-buttons\">\n @for (provider of config.oauthProviders; track provider) {\n <val-button\n [props]=\"oauthButtonProps(provider)\"\n (onClick)=\"loginWithOAuth(provider)\"\n />\n }\n </div>\n }\n\n <!-- Register Link -->\n @if (config.showRegister) {\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('noAccount') }}\n <a (click)=\"openRegisterModal()\">{{ t('register') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Forgot Password Link -->\n @if (config.showForgotPassword) {\n <div class=\"auth-link forgot-password\">\n <ion-text color=\"dark\">\n {{ t('forgotLink') }}\n <a (click)=\"openForgotPasswordModal()\">{{ t('recoverPassword') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Legal Notice -->\n @if (props.legal) {\n <div class=\"legal-notice\">\n <ion-text color=\"dark\">\n <p>\n {{ t('legalPrefix') }} @if (resolvedCompanyLink) {\n <a [href]=\"resolvedCompanyLink\" target=\"_blank\" rel=\"noopener noreferrer\"\n ><strong>{{ props.legal.companyName }}</strong></a\n >\n } @else {\n <strong>{{ props.legal.companyName }}</strong>\n } {{ t('legalSuffix') }} @if (props.legal.termsLink) {\n <a [href]=\"props.legal.termsLink\">{{ t('termsAndConditions') }}</a>\n } @else {\n <span>{{ t('termsAndConditions') }}</span>\n } {{ t('and') }} @if (props.legal.privacyLink) {\n <a [href]=\"props.legal.privacyLink\">{{ t('privacyPolicy') }}</a>\n } @else {\n <span>{{ t('privacyPolicy') }}</span>\n }.\n </p>\n </ion-text>\n </div>\n }\n</div>\n\n<!-- Register Modal -->\n<ion-modal [isOpen]=\"isRegisterModalOpen\" (didDismiss)=\"closeRegisterModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeRegisterModal()\">\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 <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"registerFormProps()\" (onSubmit)=\"registerHandler($event)\" />\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('hasAccount') }}\n <a (click)=\"onRegisterSwitchToLogin()\">{{ t('signIn') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Verify Email Modal -->\n<ion-modal [isOpen]=\"isVerifyModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeVerifyModal()\">\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 <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"verifyFormProps()\" (onSubmit)=\"verifyHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Forgot Password Modal -->\n<ion-modal [isOpen]=\"isForgotPasswordModalOpen\" (didDismiss)=\"closeForgotPasswordModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeForgotPasswordModal()\">\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 <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"forgotPasswordFormProps()\" (onSubmit)=\"forgotPasswordHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Reset Password Modal -->\n<ion-modal [isOpen]=\"isResetPasswordModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeResetPasswordModal()\">\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 <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"resetPasswordFormProps()\" (onSubmit)=\"resetPasswordHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resetResendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resetResendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendResetCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Verify Modal -->\n<ion-modal [isOpen]=\"isMFAVerifyModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"onMFAVerifyDismissed()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeMFAVerifyModal()\">\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 <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"mfaVerifyFormProps()\" (onSubmit)=\"verifyMFAHandler($event)\" />\n @if (mfaMethod() === 'TOTP') {\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n @if (mfaUseBackupCode()) {\n <a (click)=\"toggleMFABackupCode()\">{{ t('mfaUseTotpAction') }}</a>\n } @else { {{ t('mfaUseBackupLink') }}\n <a (click)=\"toggleMFABackupCode()\">{{ t('mfaUseBackupAction') }}</a>\n }\n </ion-text>\n </div>\n }\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('mfaLostBackupLink') }}\n <a (click)=\"openMFAResetModal()\">{{ t('mfaResetAction') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Reset Modal (B) \u2014 recovery por email cuando no hay backup codes -->\n<ion-modal [isOpen]=\"isMFAResetModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"closeMFAResetModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeMFAResetModal()\">\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 <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n @if (mfaResetStep() === 'request') {\n <val-form [props]=\"mfaResetRequestFormProps()\" (onSubmit)=\"mfaResetRequestHandler($event)\" />\n } @else {\n <val-form [props]=\"mfaResetConfirmFormProps()\" (onSubmit)=\"mfaResetConfirmHandler($event)\" />\n }\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".val-login{width:100%}.val-login--card{padding:1rem .75rem;background:var(--ion-color-light);border-radius:16px;box-shadow:0 2px 8px #00000014}.logo-container{max-width:130px;margin-bottom:1.5rem}.auth-link{text-align:center;margin-top:1rem;font-size:.9rem}.auth-link a{color:var(--ion-color-primary);text-decoration:none;font-weight:500;cursor:pointer}.auth-link a:hover{text-decoration:underline}.oauth-separator{display:flex;align-items:center;margin:1.5rem 0}.oauth-separator:before,.oauth-separator:after{content:\"\";flex:1;height:1px;background:var(--ion-color-medium-tint)}.oauth-separator span{padding:0 1rem;color:var(--ion-color-dark);font-size:.85rem}.oauth-buttons{margin-bottom:1rem;display:flex;flex-direction:column;gap:.5rem}.oauth-buttons val-button{--border-width: 1px}.oauth-buttons ion-icon{font-size:1.2rem;margin-right:.5rem}.legal-notice{margin-top:1.5rem;padding-top:1rem;border-top:1px solid var(--ion-color-medium-tint)}.legal-notice p{font-size:.75rem;line-height:1.5;text-align:center;margin:0}.legal-notice a{color:var(--ion-color-primary);text-decoration:none}.legal-notice a:hover{text-decoration:underline}.resend-link{text-align:center;margin-top:1rem;font-size:.9rem}.resend-link a{color:var(--ion-color-primary);cursor:pointer;font-weight:500}.resend-link a:hover{text-decoration:underline}.resend-link .cooldown{color:var(--ion-color-medium)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: FormComponent, selector: "val-form", inputs: ["props"], outputs: ["onSubmit", "onValueChange", "onInvalid", "onSelectChange"] }, { kind: "component", type: ImageComponent, selector: "val-image", inputs: ["props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }] }); }
|
|
50684
50890
|
}
|
|
50685
50891
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LoginComponent, decorators: [{
|
|
50686
50892
|
type: Component,
|
|
@@ -50698,7 +50904,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
50698
50904
|
ImageComponent,
|
|
50699
50905
|
ButtonComponent,
|
|
50700
50906
|
], template: "<div class=\"val-login\" [class.val-login--card]=\"config.showCard\">\n <!-- Logo \u2014 default de marca (--main-logo) si el consumer no pasa logo -->\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n\n <!-- Login Form -->\n <val-form [props]=\"loginFormProps()\" (onSubmit)=\"loginHandler($event)\" />\n\n <!-- OAuth Section -->\n @if (config.showOAuth && config.oauthProviders.length > 0) {\n <div class=\"oauth-separator\">\n <span>{{ t('orContinueWith') }}</span>\n </div>\n\n <div class=\"oauth-buttons\">\n @for (provider of config.oauthProviders; track provider) {\n <val-button\n [props]=\"oauthButtonProps(provider)\"\n (onClick)=\"loginWithOAuth(provider)\"\n />\n }\n </div>\n }\n\n <!-- Register Link -->\n @if (config.showRegister) {\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('noAccount') }}\n <a (click)=\"openRegisterModal()\">{{ t('register') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Forgot Password Link -->\n @if (config.showForgotPassword) {\n <div class=\"auth-link forgot-password\">\n <ion-text color=\"dark\">\n {{ t('forgotLink') }}\n <a (click)=\"openForgotPasswordModal()\">{{ t('recoverPassword') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Legal Notice -->\n @if (props.legal) {\n <div class=\"legal-notice\">\n <ion-text color=\"dark\">\n <p>\n {{ t('legalPrefix') }} @if (resolvedCompanyLink) {\n <a [href]=\"resolvedCompanyLink\" target=\"_blank\" rel=\"noopener noreferrer\"\n ><strong>{{ props.legal.companyName }}</strong></a\n >\n } @else {\n <strong>{{ props.legal.companyName }}</strong>\n } {{ t('legalSuffix') }} @if (props.legal.termsLink) {\n <a [href]=\"props.legal.termsLink\">{{ t('termsAndConditions') }}</a>\n } @else {\n <span>{{ t('termsAndConditions') }}</span>\n } {{ t('and') }} @if (props.legal.privacyLink) {\n <a [href]=\"props.legal.privacyLink\">{{ t('privacyPolicy') }}</a>\n } @else {\n <span>{{ t('privacyPolicy') }}</span>\n }.\n </p>\n </ion-text>\n </div>\n }\n</div>\n\n<!-- Register Modal -->\n<ion-modal [isOpen]=\"isRegisterModalOpen\" (didDismiss)=\"closeRegisterModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeRegisterModal()\">\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 <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"registerFormProps()\" (onSubmit)=\"registerHandler($event)\" />\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('hasAccount') }}\n <a (click)=\"onRegisterSwitchToLogin()\">{{ t('signIn') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Verify Email Modal -->\n<ion-modal [isOpen]=\"isVerifyModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeVerifyModal()\">\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 <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"verifyFormProps()\" (onSubmit)=\"verifyHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Forgot Password Modal -->\n<ion-modal [isOpen]=\"isForgotPasswordModalOpen\" (didDismiss)=\"closeForgotPasswordModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeForgotPasswordModal()\">\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 <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"forgotPasswordFormProps()\" (onSubmit)=\"forgotPasswordHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Reset Password Modal -->\n<ion-modal [isOpen]=\"isResetPasswordModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeResetPasswordModal()\">\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 <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"resetPasswordFormProps()\" (onSubmit)=\"resetPasswordHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resetResendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resetResendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendResetCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Verify Modal -->\n<ion-modal [isOpen]=\"isMFAVerifyModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"onMFAVerifyDismissed()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeMFAVerifyModal()\">\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 <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"mfaVerifyFormProps()\" (onSubmit)=\"verifyMFAHandler($event)\" />\n @if (mfaMethod() === 'TOTP') {\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n @if (mfaUseBackupCode()) {\n <a (click)=\"toggleMFABackupCode()\">{{ t('mfaUseTotpAction') }}</a>\n } @else { {{ t('mfaUseBackupLink') }}\n <a (click)=\"toggleMFABackupCode()\">{{ t('mfaUseBackupAction') }}</a>\n }\n </ion-text>\n </div>\n }\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('mfaLostBackupLink') }}\n <a (click)=\"openMFAResetModal()\">{{ t('mfaResetAction') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Reset Modal (B) \u2014 recovery por email cuando no hay backup codes -->\n<ion-modal [isOpen]=\"isMFAResetModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"closeMFAResetModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeMFAResetModal()\">\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 <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n @if (mfaResetStep() === 'request') {\n <val-form [props]=\"mfaResetRequestFormProps()\" (onSubmit)=\"mfaResetRequestHandler($event)\" />\n } @else {\n <val-form [props]=\"mfaResetConfirmFormProps()\" (onSubmit)=\"mfaResetConfirmHandler($event)\" />\n }\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".val-login{width:100%}.val-login--card{padding:1rem .75rem;background:var(--ion-color-light);border-radius:16px;box-shadow:0 2px 8px #00000014}.logo-container{max-width:130px;margin-bottom:1.5rem}.auth-link{text-align:center;margin-top:1rem;font-size:.9rem}.auth-link a{color:var(--ion-color-primary);text-decoration:none;font-weight:500;cursor:pointer}.auth-link a:hover{text-decoration:underline}.oauth-separator{display:flex;align-items:center;margin:1.5rem 0}.oauth-separator:before,.oauth-separator:after{content:\"\";flex:1;height:1px;background:var(--ion-color-medium-tint)}.oauth-separator span{padding:0 1rem;color:var(--ion-color-dark);font-size:.85rem}.oauth-buttons{margin-bottom:1rem;display:flex;flex-direction:column;gap:.5rem}.oauth-buttons val-button{--border-width: 1px}.oauth-buttons ion-icon{font-size:1.2rem;margin-right:.5rem}.legal-notice{margin-top:1.5rem;padding-top:1rem;border-top:1px solid var(--ion-color-medium-tint)}.legal-notice p{font-size:.75rem;line-height:1.5;text-align:center;margin:0}.legal-notice a{color:var(--ion-color-primary);text-decoration:none}.legal-notice a:hover{text-decoration:underline}.resend-link{text-align:center;margin-top:1rem;font-size:.9rem}.resend-link a{color:var(--ion-color-primary);cursor:pointer;font-weight:500}.resend-link a:hover{text-decoration:underline}.resend-link .cooldown{color:var(--ion-color-medium)}\n"] }]
|
|
50701
|
-
}], propDecorators: {
|
|
50907
|
+
}], propDecorators: { forms: [{
|
|
50908
|
+
type: ViewChildren,
|
|
50909
|
+
args: [FormComponent]
|
|
50910
|
+
}], props: [{
|
|
50702
50911
|
type: Input
|
|
50703
50912
|
}], onSuccess: [{
|
|
50704
50913
|
type: Output
|
|
@@ -74293,6 +74502,95 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
74293
74502
|
// ValtechConfig and LangProvider have been removed in v3.0.0
|
|
74294
74503
|
// Use LocaleService for language management instead
|
|
74295
74504
|
|
|
74505
|
+
/**
|
|
74506
|
+
* Contrato de marca de un QR, compartido entre backend y frontend (ADR-078).
|
|
74507
|
+
*
|
|
74508
|
+
* Espejo TypeScript de `backend/go/services/pkg/qrbrand/qrbrand.go`. Los tests
|
|
74509
|
+
* de contraste de este archivo usan LOS MISMOS casos que el lado Go
|
|
74510
|
+
* (`qrbrand_test.go`) — si un lado cambia el número esperado sin el otro,
|
|
74511
|
+
* dejan de coincidir.
|
|
74512
|
+
*
|
|
74513
|
+
* No dibuja nada: valida que una combinación de colores sea escaneable y
|
|
74514
|
+
* decide cuánta corrección de errores necesita un QR que lleva logo encima.
|
|
74515
|
+
* El renderizado real sigue siendo QrGeneratorService (cliente) y qrpng.go
|
|
74516
|
+
* (backend, correo) — cada uno dibuja a su manera; lo que comparten es esta
|
|
74517
|
+
* validación.
|
|
74518
|
+
*/
|
|
74519
|
+
/** Sin marca configurada: tinta sobre blanco. Nunca se persiste. */
|
|
74520
|
+
function defaultQrBrand(orgId, appId) {
|
|
74521
|
+
return { orgId, appId, ink: '#111111', bg: '#FFFFFF', dotStyle: 'square' };
|
|
74522
|
+
}
|
|
74523
|
+
const HEX_RE = /^#([0-9a-fA-F]{6})$/;
|
|
74524
|
+
/** El mínimo WCAG para texto normal (AA) — ver qrbrand.go para el porqué de reusarlo acá. */
|
|
74525
|
+
const MIN_CONTRAST_RATIO = 4.5;
|
|
74526
|
+
class QrBrandValidationError extends Error {
|
|
74527
|
+
constructor(field, message) {
|
|
74528
|
+
super(`${field}: ${message}`);
|
|
74529
|
+
this.field = field;
|
|
74530
|
+
this.name = 'QrBrandValidationError';
|
|
74531
|
+
}
|
|
74532
|
+
}
|
|
74533
|
+
function hexToRgb(hex) {
|
|
74534
|
+
const m = HEX_RE.exec(hex);
|
|
74535
|
+
if (!m)
|
|
74536
|
+
return [0, 0, 0];
|
|
74537
|
+
const v = parseInt(m[1], 16);
|
|
74538
|
+
return [((v >> 16) & 0xff) / 255, ((v >> 8) & 0xff) / 255, (v & 0xff) / 255];
|
|
74539
|
+
}
|
|
74540
|
+
function srgbToLinear(c) {
|
|
74541
|
+
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
74542
|
+
}
|
|
74543
|
+
function relativeLuminance(hex) {
|
|
74544
|
+
const [r, g, b] = hexToRgb(hex);
|
|
74545
|
+
const [rl, gl, bl] = [srgbToLinear(r), srgbToLinear(g), srgbToLinear(b)];
|
|
74546
|
+
return 0.2126 * rl + 0.7152 * gl + 0.0722 * bl;
|
|
74547
|
+
}
|
|
74548
|
+
/** Contraste WCAG entre dos colores hex (#RRGGBB). Fórmula estándar (L1+0.05)/(L2+0.05). */
|
|
74549
|
+
function qrContrastRatio(hexA, hexB) {
|
|
74550
|
+
let la = relativeLuminance(hexA);
|
|
74551
|
+
let lb = relativeLuminance(hexB);
|
|
74552
|
+
if (la < lb)
|
|
74553
|
+
[la, lb] = [lb, la];
|
|
74554
|
+
return (la + 0.05) / (lb + 0.05);
|
|
74555
|
+
}
|
|
74556
|
+
/**
|
|
74557
|
+
* Rechaza una combinación de colores que un lector real no va a poder leer.
|
|
74558
|
+
* Escaneabilidad sobre estética: esta función no negocia (ADR-078 regla 1).
|
|
74559
|
+
* Lanza QrBrandValidationError; no retorna un booleano — el caller casi
|
|
74560
|
+
* siempre necesita el mensaje para mostrarlo en el formulario.
|
|
74561
|
+
*/
|
|
74562
|
+
function validateQrBrand(b) {
|
|
74563
|
+
if (!HEX_RE.test(b.ink)) {
|
|
74564
|
+
throw new QrBrandValidationError('ink', 'debe ser un color hex de 6 dígitos, ej. #111111');
|
|
74565
|
+
}
|
|
74566
|
+
if (!HEX_RE.test(b.bg)) {
|
|
74567
|
+
throw new QrBrandValidationError('bg', 'debe ser un color hex de 6 dígitos, ej. #FFFFFF');
|
|
74568
|
+
}
|
|
74569
|
+
if (b.dotStyle && !['square', 'rounded', 'dots'].includes(b.dotStyle)) {
|
|
74570
|
+
throw new QrBrandValidationError('dotStyle', 'debe ser square, rounded o dots');
|
|
74571
|
+
}
|
|
74572
|
+
const ratio = qrContrastRatio(b.ink, b.bg);
|
|
74573
|
+
if (ratio < MIN_CONTRAST_RATIO) {
|
|
74574
|
+
throw new QrBrandValidationError('ink/bg', `contraste ${ratio.toFixed(2)}:1 por debajo del mínimo ${MIN_CONTRAST_RATIO.toFixed(1)}:1 — un lector real no va a poder escanearlo`);
|
|
74575
|
+
}
|
|
74576
|
+
if (b.logo && (b.logo.clearArea ?? 0) > 0.3) {
|
|
74577
|
+
throw new QrBrandValidationError('logo.clearArea', 'un logo que tapa más del 30% del QR deja de ser legible aunque suba la corrección de errores');
|
|
74578
|
+
}
|
|
74579
|
+
}
|
|
74580
|
+
/**
|
|
74581
|
+
* El logo obliga a subir la corrección de errores, no se le pregunta al
|
|
74582
|
+
* usuario (ADR-078 regla 2). Sin logo, M alcanza. Con logo, sube a Q; con
|
|
74583
|
+
* logo grande (>15% del área), sube al máximo H.
|
|
74584
|
+
*/
|
|
74585
|
+
function qrErrorCorrectionFor(b) {
|
|
74586
|
+
const clearArea = b.logo?.clearArea ?? 0;
|
|
74587
|
+
if (!b.logo || clearArea <= 0)
|
|
74588
|
+
return 'M';
|
|
74589
|
+
if (clearArea > 0.15)
|
|
74590
|
+
return 'H';
|
|
74591
|
+
return 'Q';
|
|
74592
|
+
}
|
|
74593
|
+
|
|
74296
74594
|
const CANVAS_WIDTH = 720;
|
|
74297
74595
|
const CANVAS_HEIGHT = 1280;
|
|
74298
74596
|
const SAFE_X = 64;
|
|
@@ -88922,5 +89220,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
88922
89220
|
* Generated bundle index. Do not edit.
|
|
88923
89221
|
*/
|
|
88924
89222
|
|
|
88925
|
-
export { ACCESS_REQUEST_TYPE, ACCESS_REQUEST_VIEW_I18N, ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, APP_VERSION_PLATFORM_PLUGIN, APP_VERSION_REMOTE_PLUGIN, ARTICLE_CARD_DEFAULTS, ARTICLE_SPACING, ARTICLE_STRIP_DEFAULTS, AUTH_CTA_DEFAULTS, AVATAR_UPLOAD_DEFAULTS, AboutViewComponent, AccessControlService, AccessRequestViewComponent, AccordionComponent, AccountViewComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AnimalCardComponent, AnimatedTerminalComponent, ApiKeyCreateModalComponent, ApiKeyService, ApiKeysModalComponent, ApiKeysViewComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, ArticleStripComponent, AttachmentUploaderComponent, AuthBackgroundComponent, AuthCtaComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BackButtonComponent, BannerComponent, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, BubbleBlitzGameComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHEV_KEYS, CIRCLE_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CORNER_KEYS, CTA_CARD_DEFAULTS, CURRENCY_INFO, CanAccessDirective, CardComponent, CardSection, CardType, CardsCarouselComponent, ChangeEmailModalComponent, ChangePasswordModalComponent, ChatComposerComponent, ChatInputComponent, ChatWindowComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, ChipSelectComponent, ClientTelemetryService, CodeDisplayComponent, CodeValidatorComponent, CollectionsService, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ConfirmationDialogV2Component, ContainerComponent, ContentLoaderComponent, ContentReactionComponent, ContentReactionModalComponent, ContentService, ContentTransformer, ConversationListItemComponent, ConversationService, CookieBannerComponent, CookieSettingsComponent, CountdownComponent, CreateOrgModalComponent, CtaCardComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_APP_VERSION_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_BUTTON_PRESETS, DEFAULT_CANCEL_BUTTON, DEFAULT_CANONICAL_FIELD_ALIASES, DEFAULT_CHECK_INTERVAL_MS, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_DEBUG_CONSOLE_CONFIG, DEFAULT_DONATION_CONFIG, DEFAULT_EMPTY_STATE, DEFAULT_EMULATOR_CONFIG, DEFAULT_FEEDBACK_CONFIG, DEFAULT_FEEDBACK_TYPE_OPTIONS, DEFAULT_HOME_HEADER, DEFAULT_INFINITE_LIST_METADATA, DEFAULT_LOGIN_LOGO, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_POST_UPDATE_GRACE_MS, DEFAULT_PRESETS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_SPLASH_SCREEN_CONFIG, DangerSectionComponent, DataTableComponent, DatasetPaginationService, DateInputComponent, DatePickerComponent, DateRangeInputComponent, DebugConsoleComponent, DeleteAccountModalComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EXPECTED_NOT_FOUND, EditOrgModalComponent, EmptyStateComponent, EntityCardComponent, EntityFeedService, EntradaSerializada, ExpandableTextComponent, ExternalBrowserService, FEATURES_LIST_DEFAULTS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FieldListComponent, FieldOptionsEditorComponent, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FolderTabsComponent, FontSizeOption, FontSizeSelectorComponent, FontSizeService, FooterComponent, FooterLinksComponent, FormComponent, FormFieldComponent, FormSchemaBuilderService, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GAME_AVATAR_CATALOG_SIZE_PER_STYLE, GameAvatarComponent, GameProfileService, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, GroupMembersComponent, GroupPickerComponent, GroupsService, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandleService, HandoffService, HapticsService, HasPermissionDirective, HeaderActionsService, HeaderComponent, HintComponent, HorizontalScrollComponent, HrefComponent, HtmlViewerModalComponent, I18nService, IMAGE_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, IONIC_COLORS$5 as IONIC_COLORS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, InviteMemberModalComponent, ItemListComponent, KNOWN_ROUTES, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGGED_IN_HINT_COOKIE, LOGIN_DEFAULTS, LandingSplitComponent, LandingStepsComponent, LanguageSelectorComponent, LanguageSelectorV2Component, LayeredCardComponent, LegalContentService, LegalLinkService, LightRippleDirective, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LiveReadFallbackService, LoadMoreComponent, LoadingDirective, LocalStorageService, LocaleService, LoginAttemptModalComponent, LoginComponent, MEDIA_OBJECT_DEFAULTS, MEMBER_CARD_DEFAULTS, METADATA_LIST_DEFAULTS, META_SCHEMA_VERSION, METRIC_CARD_DEFAULTS, MINI_GAMES_I18N, MINI_GAME_PLAYER_AVATARS, MINI_GAME_PLAYER_COLORS, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MediaObjectComponent, MediaViewerModalComponent, MemberCardComponent, MemberDetailModalComponent, MemberImportModalComponent, MemoryGameComponent, MenuComponent, MessageBubbleComponent, MessagingService, MetaService, MetadataListComponent, MeteringService, MetricCardComponent, MfaModalComponent, MiniGameCalloutComponent, MiniGamePlayerProfileService, MiniGameScorePopComponent, MiniGamesMenuComponent, ModalLayoutComponent, ModalService, ModalShellComponent, MultiSelectSearchComponent, NUM_KEYS, NavigationService, NetworkBannerComponent, NetworkStatusService, NewsBuilder, NoContentComponent, NotesBoxComponent, NoticeComponent, NotificationActionService, NotificationPreferencesViewComponent, NotificationsService, NotificationsViewComponent, NumberFromToComponent, NumberPickerComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OperationReferenceComponent, OptionCardsComponent, OptionSheetComponent, OptionSheetService, OrgInfoSheetComponent, OrgService, OrgSwitchService, OrganizationViewComponent, PATTERN_MOTIFS, PATTERN_PALETTES, PATTERN_STYLE_CONFIGS, PERSONA_CONFIG, PLATFORM_CONFIGS, POST_UPDATE_TS_KEY, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, PageWavesComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PatternComponent, PdfService, PermissionCatalogService, PermissionSelectorComponent, PermissionsModalComponent, PermissionsViewComponent, PersonaService, PhoneDisplayComponent, PhoneFormatService, PhoneInputComponent, PickerV2Component, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PreferencesViewComponent, PresetService, PriceTagComponent, PricingTableComponent, ProcessLinksPipe, ProfileCardComponent, ProfileContentComponent, ProfileModalComponent, ProfileSkeletonComponent, ProfileViewComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QrScannerComponent, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, RbacService, ReactionBarComponent, ReactionsService, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, RequestFormComponent, RequestModalComponent, RequestReviewPanelComponent, RequestService, RetroAudioService, RightsFooterComponent, RoleManagerComponent, RotatingTextComponent, SEARCH_HEADER_DEFAULTS, SETTINGS_SECTIONS_CATALOG, SHAPE_KEYS, SHARE_PROFILE_MODAL_DEFAULTS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, STATS_BAR_DEFAULTS, STROKE_KEYS, SearchHeaderComponent, SearchSelectorComponent, SearchbarComponent, SectionHeaderComponent, SecurityViewComponent, SegmentControlComponent, SelectSearchComponent, SessionListModalComponent, SessionService, SessionTransitionOverlayComponent, SettingsHubComponent, ShareButtonsComponent, ShareProfileModalComponent, SimonGameComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SplashComponent, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SupportTicketCtaComponent, SwipeCarouselComponent, SwitchOrgModalComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeSelectorComponent, ThemeService, ThreadPanelComponent, TicketCardComponent, TicketCardImageService, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TransferOwnershipModalComponent, TranslatePipe, TypedCollection, TypingIndicatorComponent, UPDATE_BANNER_DEFAULT_CONTENT, UPDATE_BANNER_I18N_NAMESPACE, UpdateBannerComponent, UsageMetersComponent, UsageService, UserAvatarComponent, UsernameInputComponent, VALTECH_ACCESS_FEATURES, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_APP_VERSION, VALTECH_AUTH_CONFIG, VALTECH_CHAT_CONFIG, VALTECH_COLLECTIONS_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_CONTENT_CONFIG, VALTECH_COPYRIGHT_TEMPLATE, VALTECH_DEBUG_CONSOLE, VALTECH_DEFAULT_CONTENT, VALTECH_DIAGRAMS, VALTECH_DONATION_CONFIG, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_LEGAL_CONFIG, VALTECH_LEGAL_ENTITY, VALTECH_MENU_I18N, VALTECH_NETWORK_ERROR_KEY, VALTECH_REACTIONS_CONFIG, VALTECH_SETTINGS_MENU_LINKS, VALTECH_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VALTECH_WHATSAPP_CONFIG, VAL_REGISTERED_ICONS, VERSION, ValQuotaWarningComponent, ValtechErrorService, VerifyViewComponent, WhatsappFabComponent, WhatsappService, WizardComponent, WizardFooterComponent, WorkflowService, accessGuard, accessGuardFromRoute, applyDefaultValueToControl, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildCompanyFooterProps, buildFooterLinks, buildLegalLinkResolver, buildPath, buildPlatformMenu, buildSettingsCards, buildSideNavItemsFromBottomNav, button, canSubmitRequestType, classifyChip, collections, connectPageRefresh, createErrorStateProps, createFirebaseConfig, createGameAvatarCatalog, createGameAvatarProps, createGlowCardProps, createInitialDatasetState, createInitialPaginationState, createNumberFromToField, createPageState, createPermissionLabeler, createRefreshableStream, createTitleProps, datasetPageFromLegacyCursor, docs, errorLoggingInterceptor, evaluateValtechAccess, extractPathParams, firmaDeSesionDeCustomToken, formatClockTime, formatDateSeparator, formatRelativeTime, gameAvatarCatalogEntryToMetadata, gameAvatarDataUri, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, groupPermissionsByScope, guestGuard, hasEmulators, iconButton, interpretError, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isIonicColor, isKnownRoute, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, provideLegalContent, providePersona, provideSplashScreen, provideValtechAboutRoutes, provideValtechAccessFeatures, provideValtechAccountRoutes, provideValtechAds, provideValtechApiKeysRoutes, provideValtechAppConfig, provideValtechAppVersion, provideValtechAppVersionHttp, provideValtechAuth, provideValtechAuthInterceptor, provideValtechChat, provideValtechCollections, provideValtechContent, provideValtechDebugConsole, provideValtechDiagrams, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationClickActions, provideValtechNotificationPreferencesRoutes, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPermissionsRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechReactions, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, provideValtechWhatsapp, query, rbacGuard, renderGameAvatarSvg, renderPatternSvgInner, replaceSpecialChars, requestSubmitMode, resolveColor, resolveCopyrightTemplate, resolveInputDefaultValue, resolveIonicColor, resolveWebBaseUrl, roleGuard, roleOf, selectableRequestTypes, storagePaths, suggestEmailFix, superAdminGuard, supportedGameAvatarStyles, toArticle, validateRoutes };
|
|
89223
|
+
export { ACCESS_REQUEST_TYPE, ACCESS_REQUEST_VIEW_I18N, ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, APP_VERSION_PLATFORM_PLUGIN, APP_VERSION_REMOTE_PLUGIN, ARTICLE_CARD_DEFAULTS, ARTICLE_SPACING, ARTICLE_STRIP_DEFAULTS, AUTH_CTA_DEFAULTS, AVATAR_UPLOAD_DEFAULTS, AboutViewComponent, AccessControlService, AccessRequestViewComponent, AccordionComponent, AccountViewComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AnimalCardComponent, AnimatedTerminalComponent, ApiKeyCreateModalComponent, ApiKeyService, ApiKeysModalComponent, ApiKeysViewComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, ArticleStripComponent, AttachmentUploaderComponent, AuthBackgroundComponent, AuthCtaComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BackButtonComponent, BannerComponent, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, BubbleBlitzGameComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHEV_KEYS, CIRCLE_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CORNER_KEYS, CTA_CARD_DEFAULTS, CURRENCY_INFO, CanAccessDirective, CardComponent, CardSection, CardType, CardsCarouselComponent, ChangeEmailModalComponent, ChangePasswordModalComponent, ChatComposerComponent, ChatInputComponent, ChatWindowComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, ChipSelectComponent, ClientTelemetryService, CodeDisplayComponent, CodeValidatorComponent, CollectionsService, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ConfirmationDialogV2Component, ContainerComponent, ContentLoaderComponent, ContentReactionComponent, ContentReactionModalComponent, ContentService, ContentTransformer, ConversationListItemComponent, ConversationService, CookieBannerComponent, CookieSettingsComponent, CountdownComponent, CreateOrgModalComponent, CtaCardComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_APP_VERSION_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_BUTTON_PRESETS, DEFAULT_CANCEL_BUTTON, DEFAULT_CANONICAL_FIELD_ALIASES, DEFAULT_CHECK_INTERVAL_MS, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_DEBUG_CONSOLE_CONFIG, DEFAULT_DONATION_CONFIG, DEFAULT_EMPTY_STATE, DEFAULT_EMULATOR_CONFIG, DEFAULT_FEEDBACK_CONFIG, DEFAULT_FEEDBACK_TYPE_OPTIONS, DEFAULT_HOME_HEADER, DEFAULT_INFINITE_LIST_METADATA, DEFAULT_LOGIN_LOGO, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_POST_UPDATE_GRACE_MS, DEFAULT_PRESETS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_SPLASH_SCREEN_CONFIG, DangerSectionComponent, DataTableComponent, DatasetPaginationService, DateInputComponent, DatePickerComponent, DateRangeInputComponent, DebugConsoleComponent, DeleteAccountModalComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EXPECTED_NOT_FOUND, EditOrgModalComponent, EmptyStateComponent, EntityCardComponent, EntityFeedService, EntradaSerializada, ExpandableTextComponent, ExternalBrowserService, FEATURES_LIST_DEFAULTS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeatureControlService, FeatureGuardDirective, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FieldListComponent, FieldOptionsEditorComponent, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FolderTabsComponent, FontSizeOption, FontSizeSelectorComponent, FontSizeService, FooterComponent, FooterLinksComponent, FormComponent, FormFieldComponent, FormSchemaBuilderService, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GAME_AVATAR_CATALOG_SIZE_PER_STYLE, GameAvatarComponent, GameProfileService, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, GroupMembersComponent, GroupPickerComponent, GroupsService, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandleService, HandoffService, HapticsService, HasPermissionDirective, HeaderActionsService, HeaderComponent, HintComponent, HorizontalScrollComponent, HrefComponent, HtmlViewerModalComponent, I18nService, IMAGE_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, IONIC_COLORS$5 as IONIC_COLORS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, InviteMemberModalComponent, ItemListComponent, KNOWN_ROUTES, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGGED_IN_HINT_COOKIE, LOGIN_DEFAULTS, LandingSplitComponent, LandingStepsComponent, LanguageSelectorComponent, LanguageSelectorV2Component, LayeredCardComponent, LegalContentService, LegalLinkService, LightRippleDirective, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LiveReadFallbackService, LoadMoreComponent, LoadingDirective, LocalStorageService, LocaleService, LoginAttemptModalComponent, LoginComponent, MEDIA_OBJECT_DEFAULTS, MEMBER_CARD_DEFAULTS, METADATA_LIST_DEFAULTS, META_SCHEMA_VERSION, METRIC_CARD_DEFAULTS, MINI_GAMES_I18N, MINI_GAME_PLAYER_AVATARS, MINI_GAME_PLAYER_COLORS, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MediaObjectComponent, MediaViewerModalComponent, MemberCardComponent, MemberDetailModalComponent, MemberImportModalComponent, MemoryGameComponent, MenuComponent, MessageBubbleComponent, MessagingService, MetaService, MetadataListComponent, MeteringService, MetricCardComponent, MfaModalComponent, MiniGameCalloutComponent, MiniGamePlayerProfileService, MiniGameScorePopComponent, MiniGamesMenuComponent, ModalLayoutComponent, ModalService, ModalShellComponent, MultiSelectSearchComponent, NUM_KEYS, NavigationService, NetworkBannerComponent, NetworkStatusService, NewsBuilder, NoContentComponent, NotesBoxComponent, NoticeComponent, NotificationActionService, NotificationPreferencesViewComponent, NotificationsService, NotificationsViewComponent, NumberFromToComponent, NumberPickerComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OperationReferenceComponent, OptionCardsComponent, OptionSheetComponent, OptionSheetService, OrgInfoSheetComponent, OrgService, OrgSwitchService, OrganizationViewComponent, PATTERN_MOTIFS, PATTERN_PALETTES, PATTERN_STYLE_CONFIGS, PERSONA_CONFIG, PLATFORM_CONFIGS, POST_UPDATE_TS_KEY, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, PageWavesComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PatternComponent, PdfService, PermissionCatalogService, PermissionSelectorComponent, PermissionsModalComponent, PermissionsViewComponent, PersonaService, PhoneDisplayComponent, PhoneFormatService, PhoneInputComponent, PickerV2Component, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PreferencesViewComponent, PresetService, PriceTagComponent, PricingTableComponent, ProcessLinksPipe, ProfileCardComponent, ProfileContentComponent, ProfileModalComponent, ProfileSkeletonComponent, ProfileViewComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrBrandValidationError, QrCodeComponent, QrGeneratorService, QrScannerComponent, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, RbacService, ReactionBarComponent, ReactionsService, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, RequestFormComponent, RequestModalComponent, RequestReviewPanelComponent, RequestService, RetroAudioService, RightsFooterComponent, RoleManagerComponent, RotatingTextComponent, SEARCH_HEADER_DEFAULTS, SETTINGS_SECTIONS_CATALOG, SHAPE_KEYS, SHARE_PROFILE_MODAL_DEFAULTS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, STATS_BAR_DEFAULTS, STROKE_KEYS, SearchHeaderComponent, SearchSelectorComponent, SearchbarComponent, SectionHeaderComponent, SecurityViewComponent, SegmentControlComponent, SelectSearchComponent, SessionListModalComponent, SessionService, SessionTransitionOverlayComponent, SettingsHubComponent, ShareButtonsComponent, ShareProfileModalComponent, SimonGameComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SplashComponent, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SupportTicketCtaComponent, SwipeCarouselComponent, SwitchOrgModalComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeSelectorComponent, ThemeService, ThreadPanelComponent, TicketCardComponent, TicketCardImageService, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TransferOwnershipModalComponent, TranslatePipe, TypedCollection, TypingIndicatorComponent, UPDATE_BANNER_DEFAULT_CONTENT, UPDATE_BANNER_I18N_NAMESPACE, UpdateBannerComponent, UsageMetersComponent, UsageService, UserAvatarComponent, UsernameInputComponent, VALTECH_ACCESS_FEATURES, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_APP_VERSION, VALTECH_AUTH_CONFIG, VALTECH_CHAT_CONFIG, VALTECH_COLLECTIONS_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_CONTENT_CONFIG, VALTECH_COPYRIGHT_TEMPLATE, VALTECH_DEBUG_CONSOLE, VALTECH_DEFAULT_CONTENT, VALTECH_DIAGRAMS, VALTECH_DONATION_CONFIG, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_LEGAL_CONFIG, VALTECH_LEGAL_ENTITY, VALTECH_MENU_I18N, VALTECH_NETWORK_ERROR_KEY, VALTECH_REACTIONS_CONFIG, VALTECH_SETTINGS_MENU_LINKS, VALTECH_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VALTECH_WHATSAPP_CONFIG, VAL_REGISTERED_ICONS, VERSION, ValQuotaWarningComponent, ValtechErrorService, VerifyViewComponent, WhatsappFabComponent, WhatsappService, WizardComponent, WizardFooterComponent, WorkflowService, accessGuard, accessGuardFromRoute, applyDefaultValueToControl, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildCompanyFooterProps, buildFooterLinks, buildLegalLinkResolver, buildPath, buildPlatformMenu, buildSettingsCards, buildSideNavItemsFromBottomNav, button, canSubmitRequestType, classifyChip, collections, connectPageRefresh, createErrorStateProps, createFirebaseConfig, createGameAvatarCatalog, createGameAvatarProps, createGlowCardProps, createInitialDatasetState, createInitialPaginationState, createNumberFromToField, createPageState, createPermissionLabeler, createRefreshableStream, createTitleProps, datasetPageFromLegacyCursor, defaultQrBrand, docs, errorLoggingInterceptor, evaluateValtechAccess, extractPathParams, firmaDeSesionDeCustomToken, formatClockTime, formatDateSeparator, formatRelativeTime, gameAvatarCatalogEntryToMetadata, gameAvatarDataUri, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, groupPermissionsByScope, guestGuard, hasEmulators, iconButton, interpretError, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isIonicColor, isKnownRoute, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, provideLegalContent, providePersona, provideSplashScreen, provideValtechAboutRoutes, provideValtechAccessFeatures, provideValtechAccountRoutes, provideValtechAds, provideValtechApiKeysRoutes, provideValtechAppConfig, provideValtechAppVersion, provideValtechAppVersionHttp, provideValtechAuth, provideValtechAuthInterceptor, provideValtechChat, provideValtechCollections, provideValtechContent, provideValtechDebugConsole, provideValtechDiagrams, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationClickActions, provideValtechNotificationPreferencesRoutes, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPermissionsRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechReactions, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, provideValtechWhatsapp, qrContrastRatio, qrErrorCorrectionFor, query, rbacGuard, renderGameAvatarSvg, renderPatternSvgInner, replaceSpecialChars, requestSubmitMode, resolveColor, resolveCopyrightTemplate, resolveInputDefaultValue, resolveIonicColor, resolveWebBaseUrl, roleGuard, roleOf, selectableRequestTypes, storagePaths, suggestEmailFix, superAdminGuard, supportedGameAvatarStyles, toArticle, validateQrBrand, validateRoutes };
|
|
88926
89224
|
//# sourceMappingURL=valtech-components.mjs.map
|