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
|
@@ -51,6 +51,30 @@ export declare class FormComponent implements OnInit, OnChanges, DoCheck {
|
|
|
51
51
|
private previousUploadingCount;
|
|
52
52
|
private uploadingFields;
|
|
53
53
|
constructor(fb: FormBuilder, elementRef: ElementRef);
|
|
54
|
+
/** Arma la definición de controles (valor inicial + validadores) desde `props`. */
|
|
55
|
+
private buildFormControlsDef;
|
|
56
|
+
/**
|
|
57
|
+
* Reconstruye el `FormGroup` desde cero, con los valores iniciales de `props`
|
|
58
|
+
* actuales (no los que el usuario haya tecleado desde entonces).
|
|
59
|
+
*
|
|
60
|
+
* Existe para el caso en que Angular NO destruye el componente entre dos usos
|
|
61
|
+
* — típicamente `IonicRouteStrategy`, que cachea la página ruteada al navegar
|
|
62
|
+
* afuera y la reutiliza al volver sin correr `ngOnInit` de nuevo. Sin esto,
|
|
63
|
+
* un form de login mantiene lo que el usuario anterior tecleó después de
|
|
64
|
+
* cerrar sesión y volver a `/login`: el `FormGroup` se construyó UNA vez y
|
|
65
|
+
* nadie lo tocó desde entonces.
|
|
66
|
+
*
|
|
67
|
+
* Reconstruye el `FormGroup` entero (no `.reset(values)`) porque la
|
|
68
|
+
* definición trae `[valor, validators]` por control, no valores planos —
|
|
69
|
+
* reusar `buildFormControlsDef()` tal cual evita mantener dos formas de
|
|
70
|
+
* calcular "cuál es el valor inicial" que puedan desincronizarse.
|
|
71
|
+
*
|
|
72
|
+
* El caller (típicamente `val-login`, vía `ionViewWillEnter`) decide CUÁNDO
|
|
73
|
+
* llamarlo — acá no hay heurística de "cuándo resetear", porque un form de
|
|
74
|
+
* varios pasos sí podría querer conservar lo tecleado al volver a una
|
|
75
|
+
* pestaña.
|
|
76
|
+
*/
|
|
77
|
+
resetForm(): void;
|
|
54
78
|
ngOnInit(): void;
|
|
55
79
|
ngOnChanges(changes: SimpleChanges): void;
|
|
56
80
|
private patchInitialValuesFromProps;
|
|
@@ -5,6 +5,7 @@ import { ImageMetadata } from '../../atoms/image/types';
|
|
|
5
5
|
import { LoginMetadata, LoginSuccessEvent, LoginErrorEvent, MFARequiredEvent } from './types';
|
|
6
6
|
import * as i0 from "@angular/core";
|
|
7
7
|
export declare class LoginComponent implements OnInit, OnDestroy {
|
|
8
|
+
private forms;
|
|
8
9
|
props: LoginMetadata;
|
|
9
10
|
onSuccess: EventEmitter<LoginSuccessEvent>;
|
|
10
11
|
onError: EventEmitter<LoginErrorEvent>;
|
|
@@ -125,6 +126,21 @@ export declare class LoginComponent implements OnInit, OnDestroy {
|
|
|
125
126
|
private listenForOAuthReturn;
|
|
126
127
|
private stopListeningForOAuthReturn;
|
|
127
128
|
ngOnInit(): void;
|
|
129
|
+
/**
|
|
130
|
+
* Ionic (`IonicRouteStrategy`) no destruye la página de login al navegar
|
|
131
|
+
* afuera — la "detach"-ea y la reutiliza si el usuario vuelve a la misma
|
|
132
|
+
* ruta, así que `ngOnInit` no vuelve a correr. `val-form` arma su
|
|
133
|
+
* `FormGroup` UNA sola vez en su propio `ngOnInit`; sin este hook, cerrar
|
|
134
|
+
* sesión y volver a `/login` mostraba el email y la contraseña que la
|
|
135
|
+
* sesión anterior había tecleado.
|
|
136
|
+
*
|
|
137
|
+
* `ionViewWillEnter` es el gancho de Ionic pensado exactamente para esto:
|
|
138
|
+
* corre en CADA entrada a la vista, sea la primera vez o una reutilización
|
|
139
|
+
* desde caché. Ionic lo invoca por duck-typing sobre cualquier componente
|
|
140
|
+
* de la jerarquía que lo declare, sin necesidad de implementar la interfaz
|
|
141
|
+
* `ViewWillEnter` (mismo patrón que `SelectSearchComponent` en esta lib).
|
|
142
|
+
*/
|
|
143
|
+
ionViewWillEnter(): void;
|
|
128
144
|
ngOnDestroy(): void;
|
|
129
145
|
static ɵfac: i0.ɵɵFactoryDeclaration<LoginComponent, never>;
|
|
130
146
|
static ɵcmp: i0.ɵɵComponentDeclaration<LoginComponent, "val-login", never, { "props": { "alias": "props"; "required": false; }; }, { "onSuccess": "onSuccess"; "onError": "onError"; "onMFARequired": "onMFARequired"; }, never, never, true, never>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { TemplateRef, ViewContainerRef, OnInit } from '@angular/core';
|
|
2
|
+
import { FeatureControlService } from '../services/feature-control.service';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
/**
|
|
5
|
+
* Structural directive to hide elements when a feature is disabled.
|
|
6
|
+
*
|
|
7
|
+
* Usage: <button *valFeatureGuard="'oauth_facebook'">Sign in with Facebook</button>
|
|
8
|
+
* If oauth_facebook is disabled, the button is not rendered.
|
|
9
|
+
*/
|
|
10
|
+
export declare class FeatureGuardDirective implements OnInit {
|
|
11
|
+
private templateRef;
|
|
12
|
+
private viewContainer;
|
|
13
|
+
private featureControl;
|
|
14
|
+
set valFeatureGuard(featureKey: string);
|
|
15
|
+
private featureKey;
|
|
16
|
+
constructor(templateRef: TemplateRef<any>, viewContainer: ViewContainerRef, featureControl: FeatureControlService);
|
|
17
|
+
ngOnInit(): void;
|
|
18
|
+
private updateVisibility;
|
|
19
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<FeatureGuardDirective, never>;
|
|
20
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<FeatureGuardDirective, "[valFeatureGuard]", never, { "valFeatureGuard": { "alias": "valFeatureGuard"; "required": false; }; }, {}, never, never, true, never>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { HttpClient } from '@angular/common/http';
|
|
2
|
+
import { AnalyticsService } from './firebase/analytics.service';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export interface UserFeature {
|
|
5
|
+
key: string;
|
|
6
|
+
enabled: boolean;
|
|
7
|
+
rolloutPercentage?: number;
|
|
8
|
+
rolloutHash?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class FeatureControlService {
|
|
11
|
+
private http;
|
|
12
|
+
private analytics?;
|
|
13
|
+
private features;
|
|
14
|
+
private isLoaded;
|
|
15
|
+
private previousState;
|
|
16
|
+
constructor(http: HttpClient, analytics?: AnalyticsService);
|
|
17
|
+
private logFeatureEvent;
|
|
18
|
+
/**
|
|
19
|
+
* Load user features from backend.
|
|
20
|
+
* Call this during app initialization (AppComponent ctor or effect).
|
|
21
|
+
* Logs feature state changes to Firebase Analytics.
|
|
22
|
+
*/
|
|
23
|
+
loadUserFeatures(): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Check if a feature is enabled for the current user.
|
|
26
|
+
* Returns true if feature is not found (optimistic default).
|
|
27
|
+
* If rollout percentage is set, uses consistent hashing for canary rollouts.
|
|
28
|
+
*/
|
|
29
|
+
isEnabled(featureKey: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Get a computed signal for a feature.
|
|
32
|
+
* Use in templates: *ngIf="featureEnabled('oauth_facebook')()"
|
|
33
|
+
* Or in component: featureEnabled('payment_settings').
|
|
34
|
+
*/
|
|
35
|
+
featureEnabled(featureKey: string): () => boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Get all features for debugging (admin only).
|
|
38
|
+
*/
|
|
39
|
+
getAllFeatures(): Map<string, boolean>;
|
|
40
|
+
/**
|
|
41
|
+
* Check if features have been loaded.
|
|
42
|
+
*/
|
|
43
|
+
isReady(): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Watch for feature changes (for testing/demo purposes).
|
|
46
|
+
*/
|
|
47
|
+
watchFeatures(): import("@angular/core").WritableSignal<Map<string, boolean>>;
|
|
48
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<FeatureControlService, [null, { optional: true; }]>;
|
|
49
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<FeatureControlService>;
|
|
50
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contrato de marca de un QR, compartido entre backend y frontend (ADR-078).
|
|
3
|
+
*
|
|
4
|
+
* Espejo TypeScript de `backend/go/services/pkg/qrbrand/qrbrand.go`. Los tests
|
|
5
|
+
* de contraste de este archivo usan LOS MISMOS casos que el lado Go
|
|
6
|
+
* (`qrbrand_test.go`) — si un lado cambia el número esperado sin el otro,
|
|
7
|
+
* dejan de coincidir.
|
|
8
|
+
*
|
|
9
|
+
* No dibuja nada: valida que una combinación de colores sea escaneable y
|
|
10
|
+
* decide cuánta corrección de errores necesita un QR que lleva logo encima.
|
|
11
|
+
* El renderizado real sigue siendo QrGeneratorService (cliente) y qrpng.go
|
|
12
|
+
* (backend, correo) — cada uno dibuja a su manera; lo que comparten es esta
|
|
13
|
+
* validación.
|
|
14
|
+
*/
|
|
15
|
+
export type QrBrandDotStyle = 'square' | 'rounded' | 'dots';
|
|
16
|
+
export type QrBrandErrorCorrection = 'L' | 'M' | 'Q' | 'H';
|
|
17
|
+
export interface QrBrandLogo {
|
|
18
|
+
assetId: string;
|
|
19
|
+
/** Fracción del QR (0–1) que el logo tapa en el centro. */
|
|
20
|
+
clearArea?: number;
|
|
21
|
+
}
|
|
22
|
+
export interface QrBrand {
|
|
23
|
+
orgId: string;
|
|
24
|
+
appId: string;
|
|
25
|
+
ink: string;
|
|
26
|
+
bg: string;
|
|
27
|
+
dotStyle?: QrBrandDotStyle;
|
|
28
|
+
logo?: QrBrandLogo;
|
|
29
|
+
}
|
|
30
|
+
/** Sin marca configurada: tinta sobre blanco. Nunca se persiste. */
|
|
31
|
+
export declare function defaultQrBrand(orgId: string, appId: string): QrBrand;
|
|
32
|
+
export declare class QrBrandValidationError extends Error {
|
|
33
|
+
readonly field: string;
|
|
34
|
+
constructor(field: string, message: string);
|
|
35
|
+
}
|
|
36
|
+
/** Contraste WCAG entre dos colores hex (#RRGGBB). Fórmula estándar (L1+0.05)/(L2+0.05). */
|
|
37
|
+
export declare function qrContrastRatio(hexA: string, hexB: string): number;
|
|
38
|
+
/**
|
|
39
|
+
* Rechaza una combinación de colores que un lector real no va a poder leer.
|
|
40
|
+
* Escaneabilidad sobre estética: esta función no negocia (ADR-078 regla 1).
|
|
41
|
+
* Lanza QrBrandValidationError; no retorna un booleano — el caller casi
|
|
42
|
+
* siempre necesita el mensaje para mostrarlo en el formulario.
|
|
43
|
+
*/
|
|
44
|
+
export declare function validateQrBrand(b: QrBrand): void;
|
|
45
|
+
/**
|
|
46
|
+
* El logo obliga a subir la corrección de errores, no se le pregunta al
|
|
47
|
+
* usuario (ADR-078 regla 2). Sin logo, M alcanza. Con logo, sube a Q; con
|
|
48
|
+
* logo grande (>15% del área), sube al máximo H.
|
|
49
|
+
*/
|
|
50
|
+
export declare function qrErrorCorrectionFor(b: QrBrand): QrBrandErrorCorrection;
|
package/lib/version.d.ts
CHANGED
package/package.json
CHANGED
package/public-api.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from './lib/version';
|
|
|
2
2
|
export * from './lib/services/access-control';
|
|
3
3
|
export * from './lib/directives/has-permission.directive';
|
|
4
4
|
export * from './lib/directives/light-ripple.directive';
|
|
5
|
+
export * from './lib/directives/feature-guard.directive';
|
|
5
6
|
export * from './lib/components/atoms/avatar/avatar.component';
|
|
6
7
|
export * from './lib/components/atoms/avatar/types';
|
|
7
8
|
export * from './lib/components/atoms/box/box.component';
|
|
@@ -434,6 +435,7 @@ export * from './lib/services/confirmation-dialog/confirmation-dialog.service';
|
|
|
434
435
|
export * from './lib/services/confirmation-dialog/types';
|
|
435
436
|
export * from './lib/services/qr-generator/qr-generator.service';
|
|
436
437
|
export * from './lib/services/qr-generator/types';
|
|
438
|
+
export * from './lib/services/qr-generator/qrbrand';
|
|
437
439
|
export * from './lib/services/ticket-card-image/ticket-card-image.service';
|
|
438
440
|
export * from './lib/services/ticket-card-image/types';
|
|
439
441
|
export * from './lib/services/modal/modal.service';
|
|
@@ -447,8 +449,9 @@ export * from './lib/services/markdown-article/beautify-legal-article';
|
|
|
447
449
|
export * from './lib/services/legal-link/legal-link.service';
|
|
448
450
|
export * from './lib/services/firebase';
|
|
449
451
|
export * from './lib/services/auth';
|
|
452
|
+
export * from './lib/services/feature-control.service';
|
|
450
453
|
export { OrgService } from './lib/services/org/org.service';
|
|
451
|
-
export { GroupPickerComponent
|
|
454
|
+
export { GroupPickerComponent } from './lib/components/molecules/group-picker/group-picker.component';
|
|
452
455
|
export { GroupMembersComponent, GroupMemberCandidate, } from './lib/components/organisms/group-members/group-members.component';
|
|
453
456
|
export { GroupsService } from './lib/services/groups/groups.service';
|
|
454
457
|
export { ValGroup, ValGroupMember, CreateGroupRequest as CreateValGroupRequest, UpdateGroupRequest as UpdateValGroupRequest, AddGroupMemberRequest, GroupResponse as ValGroupResponse, ListGroupsResponse as ListValGroupsResponse, ListGroupMembersResponse as ListValGroupMembersResponse, MyGroupsResponse, } from './lib/services/groups/types';
|