valtech-components 4.0.175 → 4.0.176
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/molecules/update-banner/update-banner.component.mjs +6 -18
- package/esm2022/lib/components/organisms/account-view/account-view.component.mjs +1 -40
- package/esm2022/lib/components/organisms/html-viewer-modal/html-viewer-modal.component.mjs +3 -3
- package/esm2022/lib/components/organisms/organization-view/organization-view.component.mjs +28 -3
- package/esm2022/lib/components/organisms/organization-view/organization-view.i18n.mjs +3 -1
- package/esm2022/lib/services/auth/auth-state.service.mjs +5 -2
- package/esm2022/lib/services/auth/auth.service.mjs +4 -28
- package/esm2022/lib/version.mjs +2 -2
- package/fesm2022/valtech-components.mjs +440 -485
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/molecules/update-banner/update-banner.component.d.ts +0 -7
- package/lib/components/organisms/account-view/account-view.component.d.ts +0 -2
- package/lib/components/organisms/organization-view/organization-view.component.d.ts +1 -0
- package/lib/services/auth/auth.service.d.ts +0 -1
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/lib/services/firebase/firebase-messaging-sw.js +145 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { inject, InjectionToken, makeEnvironmentProviders, APP_INITIALIZER, ErrorHandler, Injectable, DestroyRef, Inject, signal, computed, PLATFORM_ID, isDevMode, Optional, runInInjectionContext, effect, Pipe, TemplateRef, ViewContainerRef, input, Directive, EventEmitter, Component, Input, Output, ChangeDetectionStrategy, HostBinding, HostListener, SecurityContext, NgZone, ViewChild, ElementRef, ChangeDetectorRef, output, ContentChild, model, ViewEncapsulation, untracked, viewChild, Injector, isSignal } from '@angular/core';
|
|
3
|
-
import { BehaviorSubject, throwError, Subject, map, distinctUntilChanged, filter as filter$1, take as take$1, firstValueFrom, of, from, EMPTY, Observable, interval, debounceTime, switchMap as switchMap$1, catchError as catchError$1, takeUntil, isObservable, forkJoin, race, timer, shareReplay
|
|
4
|
-
import { catchError, switchMap, finalize, filter, take, timeout, map as map$1, tap,
|
|
3
|
+
import { BehaviorSubject, throwError, Subject, map, distinctUntilChanged, filter as filter$1, take as take$1, firstValueFrom, of, from, EMPTY, Observable, interval, debounceTime, switchMap as switchMap$1, catchError as catchError$1, takeUntil, isObservable, forkJoin, race, timer, shareReplay } from 'rxjs';
|
|
4
|
+
import { catchError, switchMap, finalize, filter, take, timeout, map as map$1, tap, 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';
|
|
6
6
|
import { provideHttpClient, withInterceptors, HttpClient, HttpErrorResponse } from '@angular/common/http';
|
|
7
7
|
import * as i1$1 from '@angular/fire/firestore';
|
|
@@ -56,7 +56,7 @@ import { BrowserMultiFormatReader } from '@zxing/browser';
|
|
|
56
56
|
* Current version of valtech-components.
|
|
57
57
|
* This is automatically updated during the publish process.
|
|
58
58
|
*/
|
|
59
|
-
const VERSION = '4.0.
|
|
59
|
+
const VERSION = '4.0.176';
|
|
60
60
|
|
|
61
61
|
// Control de estado de refresco (singleton a nivel de módulo)
|
|
62
62
|
let isRefreshing = false;
|
|
@@ -2204,7 +2204,10 @@ class AuthStateService {
|
|
|
2204
2204
|
* Resetea todo el estado a valores iniciales.
|
|
2205
2205
|
*/
|
|
2206
2206
|
reset() {
|
|
2207
|
-
|
|
2207
|
+
// isLoading: false — al resetear (logout) ya no hay bootstrap en curso;
|
|
2208
|
+
// INITIAL_AUTH_STATE tiene isLoading:true porque es el estado del arranque frío.
|
|
2209
|
+
// El guestGuard espera isLoading=false para dejar pasar a /login.
|
|
2210
|
+
this._state.set({ ...INITIAL_AUTH_STATE, isLoading: false });
|
|
2208
2211
|
this._mfaPending.set(INITIAL_MFA_STATE);
|
|
2209
2212
|
}
|
|
2210
2213
|
/**
|
|
@@ -8349,13 +8352,6 @@ class AuthService {
|
|
|
8349
8352
|
this.refreshTimerId = null;
|
|
8350
8353
|
this.syncSubscription = null;
|
|
8351
8354
|
this.firestoreRBACUnsubscribe = null;
|
|
8352
|
-
// Single-flight refresh: un solo POST /refresh en vuelo a la vez. Todos los
|
|
8353
|
-
// callers (bootstrap, reestablecer Firebase, interceptor 401, timer proactivo)
|
|
8354
|
-
// comparten el MISMO observable. Sin esto, refreshes concurrentes chocan contra
|
|
8355
|
-
// la rotación de refresh token del backend: el primero rota el token y el
|
|
8356
|
-
// segundo llega con el token ya invalidado → 401 → logout espurio (el usuario
|
|
8357
|
-
// cae a la landing al actualizar). Ver project_pwa-login-freeze.
|
|
8358
|
-
this.inFlightRefresh$ = null;
|
|
8359
8355
|
// =============================================
|
|
8360
8356
|
// ESTADO PÚBLICO (Signals readonly)
|
|
8361
8357
|
// =============================================
|
|
@@ -8766,20 +8762,13 @@ class AuthService {
|
|
|
8766
8762
|
* que el cliente debe guardar para el próximo refresh.
|
|
8767
8763
|
*/
|
|
8768
8764
|
refreshAccessToken() {
|
|
8769
|
-
// Single-flight: si ya hay un /refresh en vuelo, devolvemos el MISMO
|
|
8770
|
-
// observable (multicast vía shareReplay). Evita la carrera contra la rotación
|
|
8771
|
-
// de refresh token del backend, que producía 401 espurios → logout al
|
|
8772
|
-
// actualizar. Ver inFlightRefresh$ y project_pwa-login-freeze.
|
|
8773
|
-
if (this.inFlightRefresh$) {
|
|
8774
|
-
return this.inFlightRefresh$;
|
|
8775
|
-
}
|
|
8776
8765
|
// H-05 same-site-aware: en same-site (prod) el refresh va SOLO por la cookie
|
|
8777
8766
|
// HttpOnly (body vacío), no se persiste en localStorage → un XSS no lo roba.
|
|
8778
8767
|
// En cross-site (dev) la cookie de terceros se bloquea (Safari ITP / Chrome
|
|
8779
8768
|
// 3rd-party phase-out) → se manda en el body + se persiste (fallback).
|
|
8780
8769
|
// withCredentials adjunta la cookie cuando el browser la permite.
|
|
8781
8770
|
const body = this.storageService.cookieOnly ? {} : { refreshToken: this.state().refreshToken };
|
|
8782
|
-
|
|
8771
|
+
return this.http
|
|
8783
8772
|
.post(`${this.baseUrl}/refresh`, body, { withCredentials: true })
|
|
8784
8773
|
.pipe(
|
|
8785
8774
|
// Nunca dejar el refresh colgado: si la red/Lambda no responde a tiempo,
|
|
@@ -8809,17 +8798,7 @@ class AuthService {
|
|
|
8809
8798
|
// initialize() only clears state (no redirect). Auto-navigating to
|
|
8810
8799
|
// /login from this method redirects even users on public routes.
|
|
8811
8800
|
return throwError(() => error);
|
|
8812
|
-
})
|
|
8813
|
-
// Liberar el slot al terminar (éxito, error o timeout) para que el
|
|
8814
|
-
// próximo refresh real arranque uno nuevo.
|
|
8815
|
-
finalize(() => {
|
|
8816
|
-
this.inFlightRefresh$ = null;
|
|
8817
|
-
}),
|
|
8818
|
-
// Multicast: los side-effects del tap corren UNA vez y todos los callers
|
|
8819
|
-
// concurrentes reciben la misma respuesta/error. refCount:false → que un
|
|
8820
|
-
// caller se desuscribe temprano NO cancela la rotación de token en vuelo.
|
|
8821
|
-
shareReplay({ bufferSize: 1, refCount: false }));
|
|
8822
|
-
return this.inFlightRefresh$;
|
|
8801
|
+
}));
|
|
8823
8802
|
}
|
|
8824
8803
|
/**
|
|
8825
8804
|
* Maneja autenticación exitosa desde fuentes externas (OAuth, etc).
|
|
@@ -28372,13 +28351,6 @@ class UpdateBannerComponent {
|
|
|
28372
28351
|
dismissAction: this.tr('dismissAction'),
|
|
28373
28352
|
};
|
|
28374
28353
|
});
|
|
28375
|
-
/**
|
|
28376
|
-
* Feedback visual mientras se aplica el update. El botón pasa a estado
|
|
28377
|
-
* WORKING (spinner) y se bloquean nuevos taps. `applyUpdate()` siempre
|
|
28378
|
-
* recarga la página al terminar (try/finally), así que NO reseteamos este
|
|
28379
|
-
* flag: queda en true hasta que el reload reemplaza la app.
|
|
28380
|
-
*/
|
|
28381
|
-
this.applying = signal(false);
|
|
28382
28354
|
if (!this.i18n.hasNamespace(UPDATE_BANNER_I18N_NAMESPACE)) {
|
|
28383
28355
|
this.i18n.registerContent(UPDATE_BANNER_I18N_NAMESPACE, {
|
|
28384
28356
|
es: UPDATE_BANNER_DEFAULT_CONTENT.es,
|
|
@@ -28388,11 +28360,6 @@ class UpdateBannerComponent {
|
|
|
28388
28360
|
}
|
|
28389
28361
|
/** Aplica la actualización (activa el SW si existe + recarga). */
|
|
28390
28362
|
onUpdate() {
|
|
28391
|
-
// Anti multi-tap: el botón WORKING no queda `disabled` a nivel DOM, así que
|
|
28392
|
-
// sin este guard un usuario impaciente dispararía applyUpdate() N veces.
|
|
28393
|
-
if (this.applying())
|
|
28394
|
-
return;
|
|
28395
|
-
this.applying.set(true);
|
|
28396
28363
|
void this.version.applyUpdate();
|
|
28397
28364
|
}
|
|
28398
28365
|
/** Descarta el banner opcional. No-op en modo obligatorio. */
|
|
@@ -28462,7 +28429,7 @@ class UpdateBannerComponent {
|
|
|
28462
28429
|
color: 'primary',
|
|
28463
28430
|
fill: 'solid',
|
|
28464
28431
|
size: 'small',
|
|
28465
|
-
state:
|
|
28432
|
+
state: 'ENABLED',
|
|
28466
28433
|
type: 'button',
|
|
28467
28434
|
}"
|
|
28468
28435
|
(onClick)="onUpdate()"
|
|
@@ -28474,7 +28441,7 @@ class UpdateBannerComponent {
|
|
|
28474
28441
|
color: 'dark',
|
|
28475
28442
|
fill: 'clear',
|
|
28476
28443
|
size: 'small',
|
|
28477
|
-
state:
|
|
28444
|
+
state: 'ENABLED',
|
|
28478
28445
|
type: 'button',
|
|
28479
28446
|
}"
|
|
28480
28447
|
(onClick)="onDismiss()"
|
|
@@ -28537,7 +28504,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
28537
28504
|
color: 'primary',
|
|
28538
28505
|
fill: 'solid',
|
|
28539
28506
|
size: 'small',
|
|
28540
|
-
state:
|
|
28507
|
+
state: 'ENABLED',
|
|
28541
28508
|
type: 'button',
|
|
28542
28509
|
}"
|
|
28543
28510
|
(onClick)="onUpdate()"
|
|
@@ -28549,7 +28516,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
28549
28516
|
color: 'dark',
|
|
28550
28517
|
fill: 'clear',
|
|
28551
28518
|
size: 'small',
|
|
28552
|
-
state:
|
|
28519
|
+
state: 'ENABLED',
|
|
28553
28520
|
type: 'button',
|
|
28554
28521
|
}"
|
|
28555
28522
|
(onClick)="onDismiss()"
|
|
@@ -35380,7 +35347,7 @@ class HtmlViewerModalComponent {
|
|
|
35380
35347
|
<ion-content>
|
|
35381
35348
|
<iframe [srcdoc]="safeHtml" style="width: 100%; height: 100%; border: none;" title="Visor de documento"></iframe>
|
|
35382
35349
|
</ion-content>
|
|
35383
|
-
`, isInline: true, styles: [":host{display:flex;flex-direction:column}ion-content{--padding-
|
|
35350
|
+
`, isInline: true, styles: [":host{display:flex;flex-direction:column}ion-content{--padding-bottom: 0;--padding-top: 0}iframe{display:block}\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: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { 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: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
|
|
35384
35351
|
}
|
|
35385
35352
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HtmlViewerModalComponent, decorators: [{
|
|
35386
35353
|
type: Component,
|
|
@@ -35403,7 +35370,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
35403
35370
|
<ion-content>
|
|
35404
35371
|
<iframe [srcdoc]="safeHtml" style="width: 100%; height: 100%; border: none;" title="Visor de documento"></iframe>
|
|
35405
35372
|
</ion-content>
|
|
35406
|
-
`, styles: [":host{display:flex;flex-direction:column}ion-content{--padding-
|
|
35373
|
+
`, styles: [":host{display:flex;flex-direction:column}ion-content{--padding-bottom: 0;--padding-top: 0}iframe{display:block}\n"] }]
|
|
35407
35374
|
}], propDecorators: { html: [{
|
|
35408
35375
|
type: Input
|
|
35409
35376
|
}], title: [{
|
|
@@ -49841,384 +49808,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
49841
49808
|
type: Input
|
|
49842
49809
|
}] } });
|
|
49843
49810
|
|
|
49844
|
-
/**
|
|
49845
|
-
* Defaults i18n (es/en) embebidos en `val-switch-org-modal`. Auto-registrados en
|
|
49846
|
-
* el constructor del componente si el consumer no proveyó el namespace
|
|
49847
|
-
* (`Settings.SwitchOrg` por default). SOLO incluye las keys que el modal usa.
|
|
49848
|
-
*/
|
|
49849
|
-
const SWITCH_ORG_MODAL_I18N = {
|
|
49850
|
-
es: {
|
|
49851
|
-
title: 'Cambiar de cuenta',
|
|
49852
|
-
subtitle: 'Selecciona la organización a la que quieres cambiar.',
|
|
49853
|
-
searchPlaceholder: 'Buscar organización...',
|
|
49854
|
-
noResults: 'No se encontraron organizaciones.',
|
|
49855
|
-
current: 'Actual',
|
|
49856
|
-
close: 'Cerrar',
|
|
49857
|
-
switchError: 'No se pudo cambiar de organización.',
|
|
49858
|
-
profile: 'Mi perfil',
|
|
49859
|
-
newOrg: 'Nueva organización',
|
|
49860
|
-
},
|
|
49861
|
-
en: {
|
|
49862
|
-
title: 'Switch account',
|
|
49863
|
-
subtitle: 'Select the organization you want to switch to.',
|
|
49864
|
-
searchPlaceholder: 'Search organization...',
|
|
49865
|
-
noResults: 'No organizations found.',
|
|
49866
|
-
current: 'Active',
|
|
49867
|
-
close: 'Close',
|
|
49868
|
-
switchError: 'Could not switch organization.',
|
|
49869
|
-
profile: 'My profile',
|
|
49870
|
-
newOrg: 'New organization',
|
|
49871
|
-
},
|
|
49872
|
-
};
|
|
49873
|
-
|
|
49874
|
-
const DEFAULT_NAMESPACE$e = 'Settings.SwitchOrg';
|
|
49875
|
-
addIcons({ addOutline, businessOutline, checkmarkCircleOutline });
|
|
49876
|
-
/**
|
|
49877
|
-
* `val-switch-org-modal` — modal de cambio de organización activa (organism
|
|
49878
|
-
* compartido). Promovido desde `showcase` bajo el proceso de ADR-021. Reusado por
|
|
49879
|
-
* la vista Cuenta (y futuras vistas org-aware).
|
|
49880
|
-
*
|
|
49881
|
-
* Lista las organizaciones del user (vía `OrgService.listMyOrgs`), permite buscar
|
|
49882
|
-
* por nombre, y cambia la org activa con `OrgSwitchService.switchTo`. La org
|
|
49883
|
-
* actual queda primera y deshabilitada.
|
|
49884
|
-
*
|
|
49885
|
-
* Abierto vía `ModalService` — recibe `_modalRef` por `componentProps` + callback
|
|
49886
|
-
* `onSuccess`. Header canónico (Regla #5): sin `ion-title`, botón Cerrar texto en
|
|
49887
|
-
* `slot=end`, título/subtítulo en el body con `val-display`/`val-title`.
|
|
49888
|
-
*
|
|
49889
|
-
* Auto-registra sus defaults i18n (es/en) si el consumer no proveyó el namespace
|
|
49890
|
-
* `Settings.SwitchOrg`.
|
|
49891
|
-
*/
|
|
49892
|
-
class SwitchOrgModalComponent {
|
|
49893
|
-
onLogoError(orgId) {
|
|
49894
|
-
const next = new Set(this.failedLogos());
|
|
49895
|
-
next.add(orgId);
|
|
49896
|
-
this.failedLogos.set(next);
|
|
49897
|
-
}
|
|
49898
|
-
constructor() {
|
|
49899
|
-
this.i18n = inject(I18nService);
|
|
49900
|
-
this.auth = inject(AuthService);
|
|
49901
|
-
this.orgService = inject(OrgService);
|
|
49902
|
-
this.orgSwitch = inject(OrgSwitchService);
|
|
49903
|
-
this.errors = inject(ValtechErrorService);
|
|
49904
|
-
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
49905
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$e;
|
|
49906
|
-
this.orgs = signal([]);
|
|
49907
|
-
this.loading = signal(false);
|
|
49908
|
-
this.query = signal('');
|
|
49909
|
-
this.switchingId = signal(null);
|
|
49910
|
-
this.user = computed(() => this.auth.user());
|
|
49911
|
-
/** Avatar de usuario que falló al cargar → cae a iniciales. */
|
|
49912
|
-
this.userAvatarFailed = signal(false);
|
|
49913
|
-
/** IDs de orgs cuyo logo falló al cargar → caen al ícono business-outline. */
|
|
49914
|
-
this.failedLogos = signal(new Set());
|
|
49915
|
-
this.userInitials = computed(() => {
|
|
49916
|
-
const name = this.user()?.name ?? this.user()?.email ?? '?';
|
|
49917
|
-
return name.slice(0, 2).toUpperCase();
|
|
49918
|
-
});
|
|
49919
|
-
this.activeOrgId = computed(() => {
|
|
49920
|
-
const u = this.auth.user();
|
|
49921
|
-
return u?.activeOrgId ?? u?.activeOrg ?? '';
|
|
49922
|
-
});
|
|
49923
|
-
this.filteredOrgs = computed(() => {
|
|
49924
|
-
const q = this.query().trim().toLowerCase();
|
|
49925
|
-
const list = this.orgs();
|
|
49926
|
-
if (!q)
|
|
49927
|
-
return list;
|
|
49928
|
-
return list.filter(o => o.name.toLowerCase().includes(q));
|
|
49929
|
-
});
|
|
49930
|
-
this.i18n.registerDefaults(DEFAULT_NAMESPACE$e, SWITCH_ORG_MODAL_I18N);
|
|
49931
|
-
this.loadOrgs();
|
|
49932
|
-
}
|
|
49933
|
-
onQueryChange(value) {
|
|
49934
|
-
this.query.set(value ?? '');
|
|
49935
|
-
}
|
|
49936
|
-
async onSelect(org) {
|
|
49937
|
-
if (this.switchingId() || org.id === this.activeOrgId())
|
|
49938
|
-
return;
|
|
49939
|
-
this.switchingId.set(org.id);
|
|
49940
|
-
try {
|
|
49941
|
-
await this.orgSwitch.switchTo(org.id);
|
|
49942
|
-
this.onSuccess?.();
|
|
49943
|
-
this.dismiss();
|
|
49944
|
-
}
|
|
49945
|
-
catch (err) {
|
|
49946
|
-
this.errors.handle(err, {
|
|
49947
|
-
context: 'account.switchOrg',
|
|
49948
|
-
fallbackKey: 'switchError',
|
|
49949
|
-
i18nNamespace: this.i18nNamespace,
|
|
49950
|
-
});
|
|
49951
|
-
this.switchingId.set(null);
|
|
49952
|
-
}
|
|
49953
|
-
}
|
|
49954
|
-
loadOrgs() {
|
|
49955
|
-
this.loading.set(true);
|
|
49956
|
-
this.orgService
|
|
49957
|
-
.listMyOrgs()
|
|
49958
|
-
.pipe(take(1))
|
|
49959
|
-
.subscribe({
|
|
49960
|
-
next: orgs => {
|
|
49961
|
-
const activeId = this.activeOrgId();
|
|
49962
|
-
this.orgs.set([...orgs].sort((a, b) => (a.id === activeId ? -1 : b.id === activeId ? 1 : 0)));
|
|
49963
|
-
this.loading.set(false);
|
|
49964
|
-
},
|
|
49965
|
-
error: () => this.loading.set(false),
|
|
49966
|
-
});
|
|
49967
|
-
}
|
|
49968
|
-
onProfile() {
|
|
49969
|
-
this.dismiss();
|
|
49970
|
-
this.onProfileClick?.();
|
|
49971
|
-
}
|
|
49972
|
-
onCreateNew() {
|
|
49973
|
-
this.dismiss();
|
|
49974
|
-
this.onCreateOrg?.();
|
|
49975
|
-
}
|
|
49976
|
-
dismiss() {
|
|
49977
|
-
this._modalRef?.dismiss(null, 'cancel');
|
|
49978
|
-
}
|
|
49979
|
-
t(key) {
|
|
49980
|
-
return this.i18n.t(key, this.i18nNamespace);
|
|
49981
|
-
}
|
|
49982
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SwitchOrgModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
49983
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: SwitchOrgModalComponent, isStandalone: true, selector: "val-switch-org-modal", inputs: { _modalRef: "_modalRef", onSuccess: "onSuccess", onProfileClick: "onProfileClick", onCreateOrg: "onCreateOrg", i18nNamespace: "i18nNamespace" }, ngImport: i0, template: `
|
|
49984
|
-
<ion-header>
|
|
49985
|
-
<ion-toolbar>
|
|
49986
|
-
<ion-buttons slot="end">
|
|
49987
|
-
<ion-button fill="clear" color="dark" shape="round" (click)="dismiss()">
|
|
49988
|
-
<strong>{{ t('close') }}</strong>
|
|
49989
|
-
</ion-button>
|
|
49990
|
-
</ion-buttons>
|
|
49991
|
-
</ion-toolbar>
|
|
49992
|
-
</ion-header>
|
|
49993
|
-
|
|
49994
|
-
<ion-content class="ion-padding">
|
|
49995
|
-
<val-display [props]="{ content: t('title'), size: 'small', color: 'dark' }" />
|
|
49996
|
-
<val-title
|
|
49997
|
-
[props]="{
|
|
49998
|
-
content: t('subtitle'),
|
|
49999
|
-
size: 'large',
|
|
50000
|
-
color: '',
|
|
50001
|
-
bold: false,
|
|
50002
|
-
}"
|
|
50003
|
-
/>
|
|
50004
|
-
|
|
50005
|
-
<div class="user-strip">
|
|
50006
|
-
<div class="user-strip__avatar">
|
|
50007
|
-
@if (user()?.avatarUrl && !userAvatarFailed()) {
|
|
50008
|
-
<img [src]="user()!.avatarUrl!" [alt]="user()?.name ?? ''" (error)="userAvatarFailed.set(true)" />
|
|
50009
|
-
} @else {
|
|
50010
|
-
<span>{{ userInitials() }}</span>
|
|
50011
|
-
}
|
|
50012
|
-
</div>
|
|
50013
|
-
<div class="user-strip__info">
|
|
50014
|
-
<span class="user-strip__name">{{ user()?.name || user()?.email || '' }}</span>
|
|
50015
|
-
<span class="user-strip__email">{{ user()?.email || '' }}</span>
|
|
50016
|
-
</div>
|
|
50017
|
-
<button class="user-strip__profile-btn" type="button" (click)="onProfile()">
|
|
50018
|
-
{{ t('profile') }}
|
|
50019
|
-
</button>
|
|
50020
|
-
</div>
|
|
50021
|
-
|
|
50022
|
-
<div class="switch-section">
|
|
50023
|
-
<val-searchbar
|
|
50024
|
-
[props]="{
|
|
50025
|
-
placeholder: t('searchPlaceholder'),
|
|
50026
|
-
debounce: 200,
|
|
50027
|
-
showCancelButton: 'never',
|
|
50028
|
-
}"
|
|
50029
|
-
(filterEvent)="onQueryChange($event)"
|
|
50030
|
-
/>
|
|
50031
|
-
|
|
50032
|
-
@if (loading()) {
|
|
50033
|
-
<div class="switch-state">
|
|
50034
|
-
<ion-spinner name="crescent" />
|
|
50035
|
-
</div>
|
|
50036
|
-
} @else if (filteredOrgs().length === 0) {
|
|
50037
|
-
<val-empty-state
|
|
50038
|
-
[props]="{
|
|
50039
|
-
variant: 'empty',
|
|
50040
|
-
title: t('noResults'),
|
|
50041
|
-
icon: 'business-outline',
|
|
50042
|
-
}"
|
|
50043
|
-
/>
|
|
50044
|
-
} @else {
|
|
50045
|
-
<div class="orgs-list">
|
|
50046
|
-
@for (org of filteredOrgs(); track org.id) {
|
|
50047
|
-
<button
|
|
50048
|
-
type="button"
|
|
50049
|
-
class="org-row"
|
|
50050
|
-
[class.org-row--active]="org.id === activeOrgId()"
|
|
50051
|
-
[disabled]="!!switchingId() || org.id === activeOrgId()"
|
|
50052
|
-
(click)="onSelect(org)"
|
|
50053
|
-
>
|
|
50054
|
-
<div class="org-row__icon">
|
|
50055
|
-
@if (org.logoUrl && !failedLogos().has(org.id)) {
|
|
50056
|
-
<img [src]="org.logoUrl" [alt]="org.name" (error)="onLogoError(org.id)" />
|
|
50057
|
-
} @else {
|
|
50058
|
-
<ion-icon name="business-outline" />
|
|
50059
|
-
}
|
|
50060
|
-
</div>
|
|
50061
|
-
<div class="org-row__body">
|
|
50062
|
-
<span class="org-row__name">{{ org.name }}</span>
|
|
50063
|
-
<span class="org-row__type">{{ org.type }}</span>
|
|
50064
|
-
</div>
|
|
50065
|
-
<div class="org-row__end">
|
|
50066
|
-
@if (switchingId() === org.id) {
|
|
50067
|
-
<ion-spinner name="crescent" class="org-row__spinner" />
|
|
50068
|
-
} @else if (org.id === activeOrgId()) {
|
|
50069
|
-
<span class="org-row__current">{{ t('current') }}</span>
|
|
50070
|
-
<ion-icon name="checkmark-circle-outline" class="org-row__check" />
|
|
50071
|
-
}
|
|
50072
|
-
</div>
|
|
50073
|
-
</button>
|
|
50074
|
-
}
|
|
50075
|
-
</div>
|
|
50076
|
-
}
|
|
50077
|
-
</div>
|
|
50078
|
-
|
|
50079
|
-
@if (onCreateOrg) {
|
|
50080
|
-
<div class="new-org-cta">
|
|
50081
|
-
<ion-button expand="block" fill="outline" color="dark" shape="round" (click)="onCreateNew()">
|
|
50082
|
-
<ion-icon slot="start" name="add-outline" />
|
|
50083
|
-
{{ t('newOrg') }}
|
|
50084
|
-
</ion-button>
|
|
50085
|
-
</div>
|
|
50086
|
-
}
|
|
50087
|
-
</ion-content>
|
|
50088
|
-
`, isInline: true, styles: [".switch-section{margin-top:16px;display:flex;flex-direction:column;gap:12px}.switch-state{display:flex;justify-content:center;padding:24px 0}.orgs-list{display:flex;flex-direction:column;gap:8px}.org-row{display:flex;align-items:center;gap:12px;width:100%;padding:12px 14px;border:1px solid rgba(var(--ion-color-dark-rgb),.14);border-radius:12px;background:var(--ion-card-background, var(--ion-background-color));cursor:pointer;text-align:left;transition:border-color .15s ease,opacity .15s ease}.org-row:not(:disabled):active{opacity:.7}.org-row:disabled{cursor:default}.org-row--active{border-color:var(--ion-color-dark)}.org-row__icon{width:36px;height:36px;border-radius:50%;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:18px;color:var(--ion-color-dark);background:rgba(var(--ion-color-dark-rgb),.08)}.org-row__body{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.org-row__name{font-weight:600;font-size:.95rem;color:var(--ion-color-dark);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.org-row__type{font-size:.8rem;color:rgba(var(--ion-color-dark-rgb),.7)}.org-row__end{display:flex;align-items:center;gap:6px;flex-shrink:0}.org-row__current{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:rgba(var(--ion-color-dark-rgb),.7)}.org-row__check{font-size:1.1rem;color:var(--ion-color-dark)}.org-row__spinner{width:18px;height:18px;color:var(--ion-color-dark)}.org-row__icon img{width:100%;height:100%;object-fit:cover;border-radius:50%}.user-strip{display:flex;align-items:center;gap:12px;padding:12px 0 4px;margin-bottom:8px;border-bottom:1px solid rgba(var(--ion-color-dark-rgb),.1)}.user-strip__avatar{width:44px;height:44px;border-radius:50%;flex-shrink:0;overflow:hidden;background:rgba(var(--ion-color-dark-rgb),.1);display:flex;align-items:center;justify-content:center;font-weight:700;font-size:1rem;color:var(--ion-color-dark)}.user-strip__avatar img{width:100%;height:100%;object-fit:cover}.user-strip__info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.user-strip__name{font-weight:600;font-size:.9rem;color:var(--ion-color-dark);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.user-strip__email{font-size:.78rem;color:rgba(var(--ion-color-dark-rgb),.6);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.user-strip__profile-btn{background:none;border:none;padding:6px 0;font-size:.82rem;font-weight:600;color:var(--ion-color-dark);cursor:pointer;white-space:nowrap;text-decoration:underline;text-underline-offset:3px}.new-org-cta{margin-top:16px;padding-top:16px;border-top:1px solid rgba(var(--ion-color-dark-rgb),.1)}\n"], dependencies: [{ kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { 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: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: EmptyStateComponent, selector: "val-empty-state", inputs: ["props"] }, { kind: "component", type: SearchbarComponent, selector: "val-searchbar", inputs: ["preset", "props"], outputs: ["filterEvent", "focusEvent", "blurEvent"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }] }); }
|
|
50089
|
-
}
|
|
50090
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SwitchOrgModalComponent, decorators: [{
|
|
50091
|
-
type: Component,
|
|
50092
|
-
args: [{ selector: 'val-switch-org-modal', standalone: true, imports: [
|
|
50093
|
-
IonHeader,
|
|
50094
|
-
IonToolbar,
|
|
50095
|
-
IonButtons,
|
|
50096
|
-
IonButton,
|
|
50097
|
-
IonContent,
|
|
50098
|
-
IonSpinner,
|
|
50099
|
-
IonIcon,
|
|
50100
|
-
DisplayComponent,
|
|
50101
|
-
EmptyStateComponent,
|
|
50102
|
-
SearchbarComponent,
|
|
50103
|
-
TitleComponent,
|
|
50104
|
-
], template: `
|
|
50105
|
-
<ion-header>
|
|
50106
|
-
<ion-toolbar>
|
|
50107
|
-
<ion-buttons slot="end">
|
|
50108
|
-
<ion-button fill="clear" color="dark" shape="round" (click)="dismiss()">
|
|
50109
|
-
<strong>{{ t('close') }}</strong>
|
|
50110
|
-
</ion-button>
|
|
50111
|
-
</ion-buttons>
|
|
50112
|
-
</ion-toolbar>
|
|
50113
|
-
</ion-header>
|
|
50114
|
-
|
|
50115
|
-
<ion-content class="ion-padding">
|
|
50116
|
-
<val-display [props]="{ content: t('title'), size: 'small', color: 'dark' }" />
|
|
50117
|
-
<val-title
|
|
50118
|
-
[props]="{
|
|
50119
|
-
content: t('subtitle'),
|
|
50120
|
-
size: 'large',
|
|
50121
|
-
color: '',
|
|
50122
|
-
bold: false,
|
|
50123
|
-
}"
|
|
50124
|
-
/>
|
|
50125
|
-
|
|
50126
|
-
<div class="user-strip">
|
|
50127
|
-
<div class="user-strip__avatar">
|
|
50128
|
-
@if (user()?.avatarUrl && !userAvatarFailed()) {
|
|
50129
|
-
<img [src]="user()!.avatarUrl!" [alt]="user()?.name ?? ''" (error)="userAvatarFailed.set(true)" />
|
|
50130
|
-
} @else {
|
|
50131
|
-
<span>{{ userInitials() }}</span>
|
|
50132
|
-
}
|
|
50133
|
-
</div>
|
|
50134
|
-
<div class="user-strip__info">
|
|
50135
|
-
<span class="user-strip__name">{{ user()?.name || user()?.email || '' }}</span>
|
|
50136
|
-
<span class="user-strip__email">{{ user()?.email || '' }}</span>
|
|
50137
|
-
</div>
|
|
50138
|
-
<button class="user-strip__profile-btn" type="button" (click)="onProfile()">
|
|
50139
|
-
{{ t('profile') }}
|
|
50140
|
-
</button>
|
|
50141
|
-
</div>
|
|
50142
|
-
|
|
50143
|
-
<div class="switch-section">
|
|
50144
|
-
<val-searchbar
|
|
50145
|
-
[props]="{
|
|
50146
|
-
placeholder: t('searchPlaceholder'),
|
|
50147
|
-
debounce: 200,
|
|
50148
|
-
showCancelButton: 'never',
|
|
50149
|
-
}"
|
|
50150
|
-
(filterEvent)="onQueryChange($event)"
|
|
50151
|
-
/>
|
|
50152
|
-
|
|
50153
|
-
@if (loading()) {
|
|
50154
|
-
<div class="switch-state">
|
|
50155
|
-
<ion-spinner name="crescent" />
|
|
50156
|
-
</div>
|
|
50157
|
-
} @else if (filteredOrgs().length === 0) {
|
|
50158
|
-
<val-empty-state
|
|
50159
|
-
[props]="{
|
|
50160
|
-
variant: 'empty',
|
|
50161
|
-
title: t('noResults'),
|
|
50162
|
-
icon: 'business-outline',
|
|
50163
|
-
}"
|
|
50164
|
-
/>
|
|
50165
|
-
} @else {
|
|
50166
|
-
<div class="orgs-list">
|
|
50167
|
-
@for (org of filteredOrgs(); track org.id) {
|
|
50168
|
-
<button
|
|
50169
|
-
type="button"
|
|
50170
|
-
class="org-row"
|
|
50171
|
-
[class.org-row--active]="org.id === activeOrgId()"
|
|
50172
|
-
[disabled]="!!switchingId() || org.id === activeOrgId()"
|
|
50173
|
-
(click)="onSelect(org)"
|
|
50174
|
-
>
|
|
50175
|
-
<div class="org-row__icon">
|
|
50176
|
-
@if (org.logoUrl && !failedLogos().has(org.id)) {
|
|
50177
|
-
<img [src]="org.logoUrl" [alt]="org.name" (error)="onLogoError(org.id)" />
|
|
50178
|
-
} @else {
|
|
50179
|
-
<ion-icon name="business-outline" />
|
|
50180
|
-
}
|
|
50181
|
-
</div>
|
|
50182
|
-
<div class="org-row__body">
|
|
50183
|
-
<span class="org-row__name">{{ org.name }}</span>
|
|
50184
|
-
<span class="org-row__type">{{ org.type }}</span>
|
|
50185
|
-
</div>
|
|
50186
|
-
<div class="org-row__end">
|
|
50187
|
-
@if (switchingId() === org.id) {
|
|
50188
|
-
<ion-spinner name="crescent" class="org-row__spinner" />
|
|
50189
|
-
} @else if (org.id === activeOrgId()) {
|
|
50190
|
-
<span class="org-row__current">{{ t('current') }}</span>
|
|
50191
|
-
<ion-icon name="checkmark-circle-outline" class="org-row__check" />
|
|
50192
|
-
}
|
|
50193
|
-
</div>
|
|
50194
|
-
</button>
|
|
50195
|
-
}
|
|
50196
|
-
</div>
|
|
50197
|
-
}
|
|
50198
|
-
</div>
|
|
50199
|
-
|
|
50200
|
-
@if (onCreateOrg) {
|
|
50201
|
-
<div class="new-org-cta">
|
|
50202
|
-
<ion-button expand="block" fill="outline" color="dark" shape="round" (click)="onCreateNew()">
|
|
50203
|
-
<ion-icon slot="start" name="add-outline" />
|
|
50204
|
-
{{ t('newOrg') }}
|
|
50205
|
-
</ion-button>
|
|
50206
|
-
</div>
|
|
50207
|
-
}
|
|
50208
|
-
</ion-content>
|
|
50209
|
-
`, styles: [".switch-section{margin-top:16px;display:flex;flex-direction:column;gap:12px}.switch-state{display:flex;justify-content:center;padding:24px 0}.orgs-list{display:flex;flex-direction:column;gap:8px}.org-row{display:flex;align-items:center;gap:12px;width:100%;padding:12px 14px;border:1px solid rgba(var(--ion-color-dark-rgb),.14);border-radius:12px;background:var(--ion-card-background, var(--ion-background-color));cursor:pointer;text-align:left;transition:border-color .15s ease,opacity .15s ease}.org-row:not(:disabled):active{opacity:.7}.org-row:disabled{cursor:default}.org-row--active{border-color:var(--ion-color-dark)}.org-row__icon{width:36px;height:36px;border-radius:50%;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:18px;color:var(--ion-color-dark);background:rgba(var(--ion-color-dark-rgb),.08)}.org-row__body{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.org-row__name{font-weight:600;font-size:.95rem;color:var(--ion-color-dark);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.org-row__type{font-size:.8rem;color:rgba(var(--ion-color-dark-rgb),.7)}.org-row__end{display:flex;align-items:center;gap:6px;flex-shrink:0}.org-row__current{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:rgba(var(--ion-color-dark-rgb),.7)}.org-row__check{font-size:1.1rem;color:var(--ion-color-dark)}.org-row__spinner{width:18px;height:18px;color:var(--ion-color-dark)}.org-row__icon img{width:100%;height:100%;object-fit:cover;border-radius:50%}.user-strip{display:flex;align-items:center;gap:12px;padding:12px 0 4px;margin-bottom:8px;border-bottom:1px solid rgba(var(--ion-color-dark-rgb),.1)}.user-strip__avatar{width:44px;height:44px;border-radius:50%;flex-shrink:0;overflow:hidden;background:rgba(var(--ion-color-dark-rgb),.1);display:flex;align-items:center;justify-content:center;font-weight:700;font-size:1rem;color:var(--ion-color-dark)}.user-strip__avatar img{width:100%;height:100%;object-fit:cover}.user-strip__info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.user-strip__name{font-weight:600;font-size:.9rem;color:var(--ion-color-dark);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.user-strip__email{font-size:.78rem;color:rgba(var(--ion-color-dark-rgb),.6);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.user-strip__profile-btn{background:none;border:none;padding:6px 0;font-size:.82rem;font-weight:600;color:var(--ion-color-dark);cursor:pointer;white-space:nowrap;text-decoration:underline;text-underline-offset:3px}.new-org-cta{margin-top:16px;padding-top:16px;border-top:1px solid rgba(var(--ion-color-dark-rgb),.1)}\n"] }]
|
|
50210
|
-
}], ctorParameters: () => [], propDecorators: { _modalRef: [{
|
|
50211
|
-
type: Input
|
|
50212
|
-
}], onSuccess: [{
|
|
50213
|
-
type: Input
|
|
50214
|
-
}], onProfileClick: [{
|
|
50215
|
-
type: Input
|
|
50216
|
-
}], onCreateOrg: [{
|
|
50217
|
-
type: Input
|
|
50218
|
-
}], i18nNamespace: [{
|
|
50219
|
-
type: Input
|
|
50220
|
-
}] } });
|
|
50221
|
-
|
|
50222
49811
|
/**
|
|
50223
49812
|
* Defaults i18n (es/en) embebidos en `val-account-view`. Auto-registrados en el
|
|
50224
49813
|
* constructor del componente si el consumer no proveyó el namespace
|
|
@@ -50320,7 +49909,7 @@ const ACCOUNT_VIEW_I18N = {
|
|
|
50320
49909
|
};
|
|
50321
49910
|
|
|
50322
49911
|
addIcons({ peopleOutline, businessOutline, chevronForwardOutline, swapHorizontalOutline, mailOutline, warningOutline });
|
|
50323
|
-
const DEFAULT_NAMESPACE$
|
|
49912
|
+
const DEFAULT_NAMESPACE$e = 'Settings.Account';
|
|
50324
49913
|
const DEFAULT_MANAGE_ORG_ROUTE = '/app/settings/organization';
|
|
50325
49914
|
/**
|
|
50326
49915
|
* `val-account-view` — vista Cuenta full-feature autocontenida (organism).
|
|
@@ -50361,7 +49950,7 @@ class AccountViewComponent {
|
|
|
50361
49950
|
showNewOrgCta: merged.showNewOrgCta ?? false,
|
|
50362
49951
|
showLogout: merged.showLogout ?? true,
|
|
50363
49952
|
showDeleteAccount: merged.showDeleteAccount ?? true,
|
|
50364
|
-
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$
|
|
49953
|
+
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$e,
|
|
50365
49954
|
manageOrgRoute: merged.manageOrgRoute ?? DEFAULT_MANAGE_ORG_ROUTE,
|
|
50366
49955
|
onOrgSwitched: merged.onOrgSwitched,
|
|
50367
49956
|
onOrgCreated: merged.onOrgCreated,
|
|
@@ -50459,15 +50048,6 @@ class AccountViewComponent {
|
|
|
50459
50048
|
type: 'button',
|
|
50460
50049
|
token: 'account-delete',
|
|
50461
50050
|
}));
|
|
50462
|
-
this.switchAccountButtonProps = computed(() => ({
|
|
50463
|
-
text: this.tt('switchAccountCta'),
|
|
50464
|
-
color: 'dark',
|
|
50465
|
-
fill: 'outline',
|
|
50466
|
-
size: 'default',
|
|
50467
|
-
shape: 'round',
|
|
50468
|
-
type: 'button',
|
|
50469
|
-
token: 'account-switch',
|
|
50470
|
-
}));
|
|
50471
50051
|
const ns = this.ns;
|
|
50472
50052
|
this.i18n.registerDefaults(ns, ACCOUNT_VIEW_I18N);
|
|
50473
50053
|
this.nav.setBackHeader('pageTitle', ns, { withMenu: true });
|
|
@@ -50486,25 +50066,6 @@ class AccountViewComponent {
|
|
|
50486
50066
|
};
|
|
50487
50067
|
return map[type] ?? type;
|
|
50488
50068
|
}
|
|
50489
|
-
onSwitchAccount() {
|
|
50490
|
-
void this.modalService.open({
|
|
50491
|
-
component: SwitchOrgModalComponent,
|
|
50492
|
-
componentProps: {
|
|
50493
|
-
i18nNamespace: 'Settings.SwitchOrg',
|
|
50494
|
-
onSuccess: () => {
|
|
50495
|
-
this.loadOrgs();
|
|
50496
|
-
this.loadPendingInvites();
|
|
50497
|
-
this.resolvedConfig().onOrgSwitched?.();
|
|
50498
|
-
},
|
|
50499
|
-
},
|
|
50500
|
-
breakpoints: {
|
|
50501
|
-
breakpoints: [0, 0.85],
|
|
50502
|
-
initialBreakpoint: 0.85,
|
|
50503
|
-
showHandle: true,
|
|
50504
|
-
},
|
|
50505
|
-
backdropDismiss: true,
|
|
50506
|
-
});
|
|
50507
|
-
}
|
|
50508
50069
|
onDeleteAccount() {
|
|
50509
50070
|
this.deleteAccountOpen.set(true);
|
|
50510
50071
|
this.resolvedConfig().onAccountDeleted?.();
|
|
@@ -50691,11 +50252,6 @@ class AccountViewComponent {
|
|
|
50691
50252
|
content: orgsActiveTitle(),
|
|
50692
50253
|
}"
|
|
50693
50254
|
/>
|
|
50694
|
-
@if (orgs().length > 1) {
|
|
50695
|
-
<ion-button fill="outline" color="dark" shape="round" size="small" (click)="onSwitchAccount()">
|
|
50696
|
-
{{ tt('orgsSwitch') }}
|
|
50697
|
-
</ion-button>
|
|
50698
|
-
}
|
|
50699
50255
|
</div>
|
|
50700
50256
|
<div class="section-body">
|
|
50701
50257
|
@if (orgsLoading()) {
|
|
@@ -50895,11 +50451,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
50895
50451
|
content: orgsActiveTitle(),
|
|
50896
50452
|
}"
|
|
50897
50453
|
/>
|
|
50898
|
-
@if (orgs().length > 1) {
|
|
50899
|
-
<ion-button fill="outline" color="dark" shape="round" size="small" (click)="onSwitchAccount()">
|
|
50900
|
-
{{ tt('orgsSwitch') }}
|
|
50901
|
-
</ion-button>
|
|
50902
|
-
}
|
|
50903
50454
|
</div>
|
|
50904
50455
|
<div class="section-body">
|
|
50905
50456
|
@if (orgsLoading()) {
|
|
@@ -51173,7 +50724,7 @@ const EDIT_ORG_MODAL_I18N = {
|
|
|
51173
50724
|
},
|
|
51174
50725
|
};
|
|
51175
50726
|
|
|
51176
|
-
const DEFAULT_NAMESPACE$
|
|
50727
|
+
const DEFAULT_NAMESPACE$d = 'EditOrgModal';
|
|
51177
50728
|
/**
|
|
51178
50729
|
* `val-edit-org-modal` — modal de edición de organización (nombre + descripción).
|
|
51179
50730
|
* Promovido desde `showcase` bajo el proceso de ADR-021. Reusado por la vista de
|
|
@@ -51200,7 +50751,7 @@ class EditOrgModalComponent {
|
|
|
51200
50751
|
/** Organización a editar (pasada por `componentProps`). */
|
|
51201
50752
|
this.org = null;
|
|
51202
50753
|
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
51203
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$
|
|
50754
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$d;
|
|
51204
50755
|
this.saving = signal(false);
|
|
51205
50756
|
this.logoUrl = signal(null);
|
|
51206
50757
|
this.removingLogo = signal(false);
|
|
@@ -51208,7 +50759,7 @@ class EditOrgModalComponent {
|
|
|
51208
50759
|
const name = this.org?.name ?? '';
|
|
51209
50760
|
return name.slice(0, 2).toUpperCase() || '?';
|
|
51210
50761
|
});
|
|
51211
|
-
this.i18n.registerDefaults(DEFAULT_NAMESPACE$
|
|
50762
|
+
this.i18n.registerDefaults(DEFAULT_NAMESPACE$d, EDIT_ORG_MODAL_I18N);
|
|
51212
50763
|
this.formMeta = signal(this.buildFormMeta());
|
|
51213
50764
|
effect(() => {
|
|
51214
50765
|
this.i18n.lang();
|
|
@@ -51532,7 +51083,7 @@ const INVITE_MEMBER_MODAL_I18N = {
|
|
|
51532
51083
|
},
|
|
51533
51084
|
};
|
|
51534
51085
|
|
|
51535
|
-
const DEFAULT_NAMESPACE$
|
|
51086
|
+
const DEFAULT_NAMESPACE$c = 'InviteModal';
|
|
51536
51087
|
addIcons({ personOutline, mailOutline, closeOutline, checkmarkCircleOutline });
|
|
51537
51088
|
/**
|
|
51538
51089
|
* `val-invite-member-modal` — invitación de miembros a una organización.
|
|
@@ -51563,7 +51114,7 @@ class InviteMemberModalComponent {
|
|
|
51563
51114
|
/** Ids de miembros ya existentes (excluidos de los resultados). */
|
|
51564
51115
|
this.existingMemberIds = [];
|
|
51565
51116
|
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
51566
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$
|
|
51117
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$c;
|
|
51567
51118
|
this.query = signal('');
|
|
51568
51119
|
this.searching = signal(false);
|
|
51569
51120
|
this.searchResults = signal([]);
|
|
@@ -51608,7 +51159,7 @@ class InviteMemberModalComponent {
|
|
|
51608
51159
|
state: this.sending() ? ComponentStates.WORKING : ComponentStates.ENABLED,
|
|
51609
51160
|
}));
|
|
51610
51161
|
this.searchSubject = new Subject();
|
|
51611
|
-
this.i18n.registerDefaults(DEFAULT_NAMESPACE$
|
|
51162
|
+
this.i18n.registerDefaults(DEFAULT_NAMESPACE$c, INVITE_MEMBER_MODAL_I18N);
|
|
51612
51163
|
this.roleSub = this.roleControl.valueChanges.subscribe(v => {
|
|
51613
51164
|
if (v)
|
|
51614
51165
|
this.selectedRole.set(v);
|
|
@@ -52301,7 +51852,7 @@ const MEMBER_DETAIL_MODAL_I18N = {
|
|
|
52301
51852
|
},
|
|
52302
51853
|
};
|
|
52303
51854
|
|
|
52304
|
-
const DEFAULT_NAMESPACE$
|
|
51855
|
+
const DEFAULT_NAMESPACE$b = 'Settings.MemberDetail';
|
|
52305
51856
|
/**
|
|
52306
51857
|
* `val-member-detail-modal` — detalle de miembro de organización: perfil, rol y
|
|
52307
51858
|
* permisos. Promovido desde `showcase` bajo el proceso de ADR-021.
|
|
@@ -52351,7 +51902,7 @@ class MemberDetailModalComponent {
|
|
|
52351
51902
|
{ id: 'admin', name: 'admin' },
|
|
52352
51903
|
];
|
|
52353
51904
|
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
52354
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$
|
|
51905
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$b;
|
|
52355
51906
|
this.working = signal(false);
|
|
52356
51907
|
this.currentRole = signal('');
|
|
52357
51908
|
this.roleControl = new FormControl('');
|
|
@@ -52417,7 +51968,7 @@ class MemberDetailModalComponent {
|
|
|
52417
51968
|
type: 'button',
|
|
52418
51969
|
state: this.working() ? ComponentStates.WORKING : ComponentStates.ENABLED,
|
|
52419
51970
|
}));
|
|
52420
|
-
this.i18n.registerDefaults(DEFAULT_NAMESPACE$
|
|
51971
|
+
this.i18n.registerDefaults(DEFAULT_NAMESPACE$b, MEMBER_DETAIL_MODAL_I18N);
|
|
52421
51972
|
}
|
|
52422
51973
|
ngOnInit() {
|
|
52423
51974
|
this.i18n.registerDefaults(this.i18nNamespace, MEMBER_DETAIL_MODAL_I18N);
|
|
@@ -52876,7 +52427,7 @@ const PERMISSIONS_VIEW_I18N = {
|
|
|
52876
52427
|
},
|
|
52877
52428
|
};
|
|
52878
52429
|
|
|
52879
|
-
const DEFAULT_NAMESPACE$
|
|
52430
|
+
const DEFAULT_NAMESPACE$a = 'Settings.Permissions';
|
|
52880
52431
|
/**
|
|
52881
52432
|
* `val-permissions-view` — vista Permisos full-feature autocontenida (organism).
|
|
52882
52433
|
* Visor RBAC de solo lectura: muestra los roles del sistema (Visor/Editor/Admin +
|
|
@@ -52921,7 +52472,7 @@ class PermissionsViewComponent {
|
|
|
52921
52472
|
return {
|
|
52922
52473
|
showSystemRoles: merged.showSystemRoles ?? true,
|
|
52923
52474
|
showCustomRoles: merged.showCustomRoles ?? true,
|
|
52924
|
-
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$
|
|
52475
|
+
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$a,
|
|
52925
52476
|
};
|
|
52926
52477
|
});
|
|
52927
52478
|
this.loading = signal(false);
|
|
@@ -53425,7 +52976,7 @@ const TRANSFER_OWNERSHIP_MODAL_I18N = {
|
|
|
53425
52976
|
},
|
|
53426
52977
|
};
|
|
53427
52978
|
|
|
53428
|
-
const DEFAULT_NAMESPACE$
|
|
52979
|
+
const DEFAULT_NAMESPACE$9 = 'Settings.TransferModal';
|
|
53429
52980
|
/**
|
|
53430
52981
|
* `val-transfer-ownership-modal` — selector de miembro para transferir la
|
|
53431
52982
|
* propiedad de la organización. Promovido desde `showcase` bajo el proceso de
|
|
@@ -53449,7 +53000,7 @@ class TransferOwnershipModalComponent {
|
|
|
53449
53000
|
/** Lista de miembros transferibles (todos excepto el owner actual). */
|
|
53450
53001
|
this.members = [];
|
|
53451
53002
|
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
53452
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$
|
|
53003
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$9;
|
|
53453
53004
|
this.query = signal('');
|
|
53454
53005
|
this.selectedId = signal('');
|
|
53455
53006
|
this.filtered = computed(() => {
|
|
@@ -53459,7 +53010,7 @@ class TransferOwnershipModalComponent {
|
|
|
53459
53010
|
return this.members.filter(m => m.name?.toLowerCase().includes(q) || m.email?.toLowerCase().includes(q) || m.userId.toLowerCase().includes(q));
|
|
53460
53011
|
});
|
|
53461
53012
|
this.noResultsLabel = computed(() => `${this.t('noResults')} "${this.query()}"`);
|
|
53462
|
-
this.i18n.registerDefaults(DEFAULT_NAMESPACE$
|
|
53013
|
+
this.i18n.registerDefaults(DEFAULT_NAMESPACE$9, TRANSFER_OWNERSHIP_MODAL_I18N);
|
|
53463
53014
|
}
|
|
53464
53015
|
ngOnInit() {
|
|
53465
53016
|
this.i18n.registerDefaults(this.i18nNamespace, TRANSFER_OWNERSHIP_MODAL_I18N);
|
|
@@ -53732,7 +53283,7 @@ const MEMBER_IMPORT_MODAL_I18N = {
|
|
|
53732
53283
|
},
|
|
53733
53284
|
};
|
|
53734
53285
|
|
|
53735
|
-
const DEFAULT_NAMESPACE$
|
|
53286
|
+
const DEFAULT_NAMESPACE$8 = 'Settings.ImportModal';
|
|
53736
53287
|
addIcons({ cloudUploadOutline, documentTextOutline });
|
|
53737
53288
|
/**
|
|
53738
53289
|
* `val-member-import-modal` — panel de carga masiva de miembros (ADR-023 fase 6).
|
|
@@ -53752,7 +53303,7 @@ class MemberImportModalComponent {
|
|
|
53752
53303
|
/** Nombres de roles disponibles (para el hint). Opcional. */
|
|
53753
53304
|
this.availableRoles = [];
|
|
53754
53305
|
/** Namespace i18n. */
|
|
53755
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$
|
|
53306
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$8;
|
|
53756
53307
|
this.csv = '';
|
|
53757
53308
|
this.importMode = signal('file');
|
|
53758
53309
|
this.onConflictControl = new FormControl('assignRole');
|
|
@@ -53794,7 +53345,7 @@ class MemberImportModalComponent {
|
|
|
53794
53345
|
return this.t('summary');
|
|
53795
53346
|
return `${this.t('summary')}: ${s.created} ${this.t('created')} · ${s.assigned} ${this.t('assigned')} · ${s.skipped} ${this.t('skipped')} · ${s.failed} ${this.t('failed')}`;
|
|
53796
53347
|
});
|
|
53797
|
-
this.i18n.registerDefaults(DEFAULT_NAMESPACE$
|
|
53348
|
+
this.i18n.registerDefaults(DEFAULT_NAMESPACE$8, MEMBER_IMPORT_MODAL_I18N);
|
|
53798
53349
|
}
|
|
53799
53350
|
ngOnInit() {
|
|
53800
53351
|
this.i18n.registerDefaults(this.i18nNamespace, MEMBER_IMPORT_MODAL_I18N);
|
|
@@ -54195,6 +53746,384 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
54195
53746
|
type: Input
|
|
54196
53747
|
}] } });
|
|
54197
53748
|
|
|
53749
|
+
/**
|
|
53750
|
+
* Defaults i18n (es/en) embebidos en `val-switch-org-modal`. Auto-registrados en
|
|
53751
|
+
* el constructor del componente si el consumer no proveyó el namespace
|
|
53752
|
+
* (`Settings.SwitchOrg` por default). SOLO incluye las keys que el modal usa.
|
|
53753
|
+
*/
|
|
53754
|
+
const SWITCH_ORG_MODAL_I18N = {
|
|
53755
|
+
es: {
|
|
53756
|
+
title: 'Cambiar de cuenta',
|
|
53757
|
+
subtitle: 'Selecciona la organización a la que quieres cambiar.',
|
|
53758
|
+
searchPlaceholder: 'Buscar organización...',
|
|
53759
|
+
noResults: 'No se encontraron organizaciones.',
|
|
53760
|
+
current: 'Actual',
|
|
53761
|
+
close: 'Cerrar',
|
|
53762
|
+
switchError: 'No se pudo cambiar de organización.',
|
|
53763
|
+
profile: 'Mi perfil',
|
|
53764
|
+
newOrg: 'Nueva organización',
|
|
53765
|
+
},
|
|
53766
|
+
en: {
|
|
53767
|
+
title: 'Switch account',
|
|
53768
|
+
subtitle: 'Select the organization you want to switch to.',
|
|
53769
|
+
searchPlaceholder: 'Search organization...',
|
|
53770
|
+
noResults: 'No organizations found.',
|
|
53771
|
+
current: 'Active',
|
|
53772
|
+
close: 'Close',
|
|
53773
|
+
switchError: 'Could not switch organization.',
|
|
53774
|
+
profile: 'My profile',
|
|
53775
|
+
newOrg: 'New organization',
|
|
53776
|
+
},
|
|
53777
|
+
};
|
|
53778
|
+
|
|
53779
|
+
const DEFAULT_NAMESPACE$7 = 'Settings.SwitchOrg';
|
|
53780
|
+
addIcons({ addOutline, businessOutline, checkmarkCircleOutline });
|
|
53781
|
+
/**
|
|
53782
|
+
* `val-switch-org-modal` — modal de cambio de organización activa (organism
|
|
53783
|
+
* compartido). Promovido desde `showcase` bajo el proceso de ADR-021. Reusado por
|
|
53784
|
+
* la vista Cuenta (y futuras vistas org-aware).
|
|
53785
|
+
*
|
|
53786
|
+
* Lista las organizaciones del user (vía `OrgService.listMyOrgs`), permite buscar
|
|
53787
|
+
* por nombre, y cambia la org activa con `OrgSwitchService.switchTo`. La org
|
|
53788
|
+
* actual queda primera y deshabilitada.
|
|
53789
|
+
*
|
|
53790
|
+
* Abierto vía `ModalService` — recibe `_modalRef` por `componentProps` + callback
|
|
53791
|
+
* `onSuccess`. Header canónico (Regla #5): sin `ion-title`, botón Cerrar texto en
|
|
53792
|
+
* `slot=end`, título/subtítulo en el body con `val-display`/`val-title`.
|
|
53793
|
+
*
|
|
53794
|
+
* Auto-registra sus defaults i18n (es/en) si el consumer no proveyó el namespace
|
|
53795
|
+
* `Settings.SwitchOrg`.
|
|
53796
|
+
*/
|
|
53797
|
+
class SwitchOrgModalComponent {
|
|
53798
|
+
onLogoError(orgId) {
|
|
53799
|
+
const next = new Set(this.failedLogos());
|
|
53800
|
+
next.add(orgId);
|
|
53801
|
+
this.failedLogos.set(next);
|
|
53802
|
+
}
|
|
53803
|
+
constructor() {
|
|
53804
|
+
this.i18n = inject(I18nService);
|
|
53805
|
+
this.auth = inject(AuthService);
|
|
53806
|
+
this.orgService = inject(OrgService);
|
|
53807
|
+
this.orgSwitch = inject(OrgSwitchService);
|
|
53808
|
+
this.errors = inject(ValtechErrorService);
|
|
53809
|
+
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
53810
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$7;
|
|
53811
|
+
this.orgs = signal([]);
|
|
53812
|
+
this.loading = signal(false);
|
|
53813
|
+
this.query = signal('');
|
|
53814
|
+
this.switchingId = signal(null);
|
|
53815
|
+
this.user = computed(() => this.auth.user());
|
|
53816
|
+
/** Avatar de usuario que falló al cargar → cae a iniciales. */
|
|
53817
|
+
this.userAvatarFailed = signal(false);
|
|
53818
|
+
/** IDs de orgs cuyo logo falló al cargar → caen al ícono business-outline. */
|
|
53819
|
+
this.failedLogos = signal(new Set());
|
|
53820
|
+
this.userInitials = computed(() => {
|
|
53821
|
+
const name = this.user()?.name ?? this.user()?.email ?? '?';
|
|
53822
|
+
return name.slice(0, 2).toUpperCase();
|
|
53823
|
+
});
|
|
53824
|
+
this.activeOrgId = computed(() => {
|
|
53825
|
+
const u = this.auth.user();
|
|
53826
|
+
return u?.activeOrgId ?? u?.activeOrg ?? '';
|
|
53827
|
+
});
|
|
53828
|
+
this.filteredOrgs = computed(() => {
|
|
53829
|
+
const q = this.query().trim().toLowerCase();
|
|
53830
|
+
const list = this.orgs();
|
|
53831
|
+
if (!q)
|
|
53832
|
+
return list;
|
|
53833
|
+
return list.filter(o => o.name.toLowerCase().includes(q));
|
|
53834
|
+
});
|
|
53835
|
+
this.i18n.registerDefaults(DEFAULT_NAMESPACE$7, SWITCH_ORG_MODAL_I18N);
|
|
53836
|
+
this.loadOrgs();
|
|
53837
|
+
}
|
|
53838
|
+
onQueryChange(value) {
|
|
53839
|
+
this.query.set(value ?? '');
|
|
53840
|
+
}
|
|
53841
|
+
async onSelect(org) {
|
|
53842
|
+
if (this.switchingId() || org.id === this.activeOrgId())
|
|
53843
|
+
return;
|
|
53844
|
+
this.switchingId.set(org.id);
|
|
53845
|
+
try {
|
|
53846
|
+
await this.orgSwitch.switchTo(org.id);
|
|
53847
|
+
this.onSuccess?.();
|
|
53848
|
+
this.dismiss();
|
|
53849
|
+
}
|
|
53850
|
+
catch (err) {
|
|
53851
|
+
this.errors.handle(err, {
|
|
53852
|
+
context: 'account.switchOrg',
|
|
53853
|
+
fallbackKey: 'switchError',
|
|
53854
|
+
i18nNamespace: this.i18nNamespace,
|
|
53855
|
+
});
|
|
53856
|
+
this.switchingId.set(null);
|
|
53857
|
+
}
|
|
53858
|
+
}
|
|
53859
|
+
loadOrgs() {
|
|
53860
|
+
this.loading.set(true);
|
|
53861
|
+
this.orgService
|
|
53862
|
+
.listMyOrgs()
|
|
53863
|
+
.pipe(take(1))
|
|
53864
|
+
.subscribe({
|
|
53865
|
+
next: orgs => {
|
|
53866
|
+
const activeId = this.activeOrgId();
|
|
53867
|
+
this.orgs.set([...orgs].sort((a, b) => (a.id === activeId ? -1 : b.id === activeId ? 1 : 0)));
|
|
53868
|
+
this.loading.set(false);
|
|
53869
|
+
},
|
|
53870
|
+
error: () => this.loading.set(false),
|
|
53871
|
+
});
|
|
53872
|
+
}
|
|
53873
|
+
onProfile() {
|
|
53874
|
+
this.dismiss();
|
|
53875
|
+
this.onProfileClick?.();
|
|
53876
|
+
}
|
|
53877
|
+
onCreateNew() {
|
|
53878
|
+
this.dismiss();
|
|
53879
|
+
this.onCreateOrg?.();
|
|
53880
|
+
}
|
|
53881
|
+
dismiss() {
|
|
53882
|
+
this._modalRef?.dismiss(null, 'cancel');
|
|
53883
|
+
}
|
|
53884
|
+
t(key) {
|
|
53885
|
+
return this.i18n.t(key, this.i18nNamespace);
|
|
53886
|
+
}
|
|
53887
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SwitchOrgModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
53888
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: SwitchOrgModalComponent, isStandalone: true, selector: "val-switch-org-modal", inputs: { _modalRef: "_modalRef", onSuccess: "onSuccess", onProfileClick: "onProfileClick", onCreateOrg: "onCreateOrg", i18nNamespace: "i18nNamespace" }, ngImport: i0, template: `
|
|
53889
|
+
<ion-header>
|
|
53890
|
+
<ion-toolbar>
|
|
53891
|
+
<ion-buttons slot="end">
|
|
53892
|
+
<ion-button fill="clear" color="dark" shape="round" (click)="dismiss()">
|
|
53893
|
+
<strong>{{ t('close') }}</strong>
|
|
53894
|
+
</ion-button>
|
|
53895
|
+
</ion-buttons>
|
|
53896
|
+
</ion-toolbar>
|
|
53897
|
+
</ion-header>
|
|
53898
|
+
|
|
53899
|
+
<ion-content class="ion-padding">
|
|
53900
|
+
<val-display [props]="{ content: t('title'), size: 'small', color: 'dark' }" />
|
|
53901
|
+
<val-title
|
|
53902
|
+
[props]="{
|
|
53903
|
+
content: t('subtitle'),
|
|
53904
|
+
size: 'large',
|
|
53905
|
+
color: '',
|
|
53906
|
+
bold: false,
|
|
53907
|
+
}"
|
|
53908
|
+
/>
|
|
53909
|
+
|
|
53910
|
+
<div class="user-strip">
|
|
53911
|
+
<div class="user-strip__avatar">
|
|
53912
|
+
@if (user()?.avatarUrl && !userAvatarFailed()) {
|
|
53913
|
+
<img [src]="user()!.avatarUrl!" [alt]="user()?.name ?? ''" (error)="userAvatarFailed.set(true)" />
|
|
53914
|
+
} @else {
|
|
53915
|
+
<span>{{ userInitials() }}</span>
|
|
53916
|
+
}
|
|
53917
|
+
</div>
|
|
53918
|
+
<div class="user-strip__info">
|
|
53919
|
+
<span class="user-strip__name">{{ user()?.name || user()?.email || '' }}</span>
|
|
53920
|
+
<span class="user-strip__email">{{ user()?.email || '' }}</span>
|
|
53921
|
+
</div>
|
|
53922
|
+
<button class="user-strip__profile-btn" type="button" (click)="onProfile()">
|
|
53923
|
+
{{ t('profile') }}
|
|
53924
|
+
</button>
|
|
53925
|
+
</div>
|
|
53926
|
+
|
|
53927
|
+
<div class="switch-section">
|
|
53928
|
+
<val-searchbar
|
|
53929
|
+
[props]="{
|
|
53930
|
+
placeholder: t('searchPlaceholder'),
|
|
53931
|
+
debounce: 200,
|
|
53932
|
+
showCancelButton: 'never',
|
|
53933
|
+
}"
|
|
53934
|
+
(filterEvent)="onQueryChange($event)"
|
|
53935
|
+
/>
|
|
53936
|
+
|
|
53937
|
+
@if (loading()) {
|
|
53938
|
+
<div class="switch-state">
|
|
53939
|
+
<ion-spinner name="crescent" />
|
|
53940
|
+
</div>
|
|
53941
|
+
} @else if (filteredOrgs().length === 0) {
|
|
53942
|
+
<val-empty-state
|
|
53943
|
+
[props]="{
|
|
53944
|
+
variant: 'empty',
|
|
53945
|
+
title: t('noResults'),
|
|
53946
|
+
icon: 'business-outline',
|
|
53947
|
+
}"
|
|
53948
|
+
/>
|
|
53949
|
+
} @else {
|
|
53950
|
+
<div class="orgs-list">
|
|
53951
|
+
@for (org of filteredOrgs(); track org.id) {
|
|
53952
|
+
<button
|
|
53953
|
+
type="button"
|
|
53954
|
+
class="org-row"
|
|
53955
|
+
[class.org-row--active]="org.id === activeOrgId()"
|
|
53956
|
+
[disabled]="!!switchingId() || org.id === activeOrgId()"
|
|
53957
|
+
(click)="onSelect(org)"
|
|
53958
|
+
>
|
|
53959
|
+
<div class="org-row__icon">
|
|
53960
|
+
@if (org.logoUrl && !failedLogos().has(org.id)) {
|
|
53961
|
+
<img [src]="org.logoUrl" [alt]="org.name" (error)="onLogoError(org.id)" />
|
|
53962
|
+
} @else {
|
|
53963
|
+
<ion-icon name="business-outline" />
|
|
53964
|
+
}
|
|
53965
|
+
</div>
|
|
53966
|
+
<div class="org-row__body">
|
|
53967
|
+
<span class="org-row__name">{{ org.name }}</span>
|
|
53968
|
+
<span class="org-row__type">{{ org.type }}</span>
|
|
53969
|
+
</div>
|
|
53970
|
+
<div class="org-row__end">
|
|
53971
|
+
@if (switchingId() === org.id) {
|
|
53972
|
+
<ion-spinner name="crescent" class="org-row__spinner" />
|
|
53973
|
+
} @else if (org.id === activeOrgId()) {
|
|
53974
|
+
<span class="org-row__current">{{ t('current') }}</span>
|
|
53975
|
+
<ion-icon name="checkmark-circle-outline" class="org-row__check" />
|
|
53976
|
+
}
|
|
53977
|
+
</div>
|
|
53978
|
+
</button>
|
|
53979
|
+
}
|
|
53980
|
+
</div>
|
|
53981
|
+
}
|
|
53982
|
+
</div>
|
|
53983
|
+
|
|
53984
|
+
@if (onCreateOrg) {
|
|
53985
|
+
<div class="new-org-cta">
|
|
53986
|
+
<ion-button expand="block" fill="outline" color="dark" shape="round" (click)="onCreateNew()">
|
|
53987
|
+
<ion-icon slot="start" name="add-outline" />
|
|
53988
|
+
{{ t('newOrg') }}
|
|
53989
|
+
</ion-button>
|
|
53990
|
+
</div>
|
|
53991
|
+
}
|
|
53992
|
+
</ion-content>
|
|
53993
|
+
`, isInline: true, styles: [".switch-section{margin-top:16px;display:flex;flex-direction:column;gap:12px}.switch-state{display:flex;justify-content:center;padding:24px 0}.orgs-list{display:flex;flex-direction:column;gap:8px}.org-row{display:flex;align-items:center;gap:12px;width:100%;padding:12px 14px;border:1px solid rgba(var(--ion-color-dark-rgb),.14);border-radius:12px;background:var(--ion-card-background, var(--ion-background-color));cursor:pointer;text-align:left;transition:border-color .15s ease,opacity .15s ease}.org-row:not(:disabled):active{opacity:.7}.org-row:disabled{cursor:default}.org-row--active{border-color:var(--ion-color-dark)}.org-row__icon{width:36px;height:36px;border-radius:50%;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:18px;color:var(--ion-color-dark);background:rgba(var(--ion-color-dark-rgb),.08)}.org-row__body{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.org-row__name{font-weight:600;font-size:.95rem;color:var(--ion-color-dark);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.org-row__type{font-size:.8rem;color:rgba(var(--ion-color-dark-rgb),.7)}.org-row__end{display:flex;align-items:center;gap:6px;flex-shrink:0}.org-row__current{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:rgba(var(--ion-color-dark-rgb),.7)}.org-row__check{font-size:1.1rem;color:var(--ion-color-dark)}.org-row__spinner{width:18px;height:18px;color:var(--ion-color-dark)}.org-row__icon img{width:100%;height:100%;object-fit:cover;border-radius:50%}.user-strip{display:flex;align-items:center;gap:12px;padding:12px 0 4px;margin-bottom:8px;border-bottom:1px solid rgba(var(--ion-color-dark-rgb),.1)}.user-strip__avatar{width:44px;height:44px;border-radius:50%;flex-shrink:0;overflow:hidden;background:rgba(var(--ion-color-dark-rgb),.1);display:flex;align-items:center;justify-content:center;font-weight:700;font-size:1rem;color:var(--ion-color-dark)}.user-strip__avatar img{width:100%;height:100%;object-fit:cover}.user-strip__info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.user-strip__name{font-weight:600;font-size:.9rem;color:var(--ion-color-dark);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.user-strip__email{font-size:.78rem;color:rgba(var(--ion-color-dark-rgb),.6);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.user-strip__profile-btn{background:none;border:none;padding:6px 0;font-size:.82rem;font-weight:600;color:var(--ion-color-dark);cursor:pointer;white-space:nowrap;text-decoration:underline;text-underline-offset:3px}.new-org-cta{margin-top:16px;padding-top:16px;border-top:1px solid rgba(var(--ion-color-dark-rgb),.1)}\n"], dependencies: [{ kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { 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: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: EmptyStateComponent, selector: "val-empty-state", inputs: ["props"] }, { kind: "component", type: SearchbarComponent, selector: "val-searchbar", inputs: ["preset", "props"], outputs: ["filterEvent", "focusEvent", "blurEvent"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }] }); }
|
|
53994
|
+
}
|
|
53995
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SwitchOrgModalComponent, decorators: [{
|
|
53996
|
+
type: Component,
|
|
53997
|
+
args: [{ selector: 'val-switch-org-modal', standalone: true, imports: [
|
|
53998
|
+
IonHeader,
|
|
53999
|
+
IonToolbar,
|
|
54000
|
+
IonButtons,
|
|
54001
|
+
IonButton,
|
|
54002
|
+
IonContent,
|
|
54003
|
+
IonSpinner,
|
|
54004
|
+
IonIcon,
|
|
54005
|
+
DisplayComponent,
|
|
54006
|
+
EmptyStateComponent,
|
|
54007
|
+
SearchbarComponent,
|
|
54008
|
+
TitleComponent,
|
|
54009
|
+
], template: `
|
|
54010
|
+
<ion-header>
|
|
54011
|
+
<ion-toolbar>
|
|
54012
|
+
<ion-buttons slot="end">
|
|
54013
|
+
<ion-button fill="clear" color="dark" shape="round" (click)="dismiss()">
|
|
54014
|
+
<strong>{{ t('close') }}</strong>
|
|
54015
|
+
</ion-button>
|
|
54016
|
+
</ion-buttons>
|
|
54017
|
+
</ion-toolbar>
|
|
54018
|
+
</ion-header>
|
|
54019
|
+
|
|
54020
|
+
<ion-content class="ion-padding">
|
|
54021
|
+
<val-display [props]="{ content: t('title'), size: 'small', color: 'dark' }" />
|
|
54022
|
+
<val-title
|
|
54023
|
+
[props]="{
|
|
54024
|
+
content: t('subtitle'),
|
|
54025
|
+
size: 'large',
|
|
54026
|
+
color: '',
|
|
54027
|
+
bold: false,
|
|
54028
|
+
}"
|
|
54029
|
+
/>
|
|
54030
|
+
|
|
54031
|
+
<div class="user-strip">
|
|
54032
|
+
<div class="user-strip__avatar">
|
|
54033
|
+
@if (user()?.avatarUrl && !userAvatarFailed()) {
|
|
54034
|
+
<img [src]="user()!.avatarUrl!" [alt]="user()?.name ?? ''" (error)="userAvatarFailed.set(true)" />
|
|
54035
|
+
} @else {
|
|
54036
|
+
<span>{{ userInitials() }}</span>
|
|
54037
|
+
}
|
|
54038
|
+
</div>
|
|
54039
|
+
<div class="user-strip__info">
|
|
54040
|
+
<span class="user-strip__name">{{ user()?.name || user()?.email || '' }}</span>
|
|
54041
|
+
<span class="user-strip__email">{{ user()?.email || '' }}</span>
|
|
54042
|
+
</div>
|
|
54043
|
+
<button class="user-strip__profile-btn" type="button" (click)="onProfile()">
|
|
54044
|
+
{{ t('profile') }}
|
|
54045
|
+
</button>
|
|
54046
|
+
</div>
|
|
54047
|
+
|
|
54048
|
+
<div class="switch-section">
|
|
54049
|
+
<val-searchbar
|
|
54050
|
+
[props]="{
|
|
54051
|
+
placeholder: t('searchPlaceholder'),
|
|
54052
|
+
debounce: 200,
|
|
54053
|
+
showCancelButton: 'never',
|
|
54054
|
+
}"
|
|
54055
|
+
(filterEvent)="onQueryChange($event)"
|
|
54056
|
+
/>
|
|
54057
|
+
|
|
54058
|
+
@if (loading()) {
|
|
54059
|
+
<div class="switch-state">
|
|
54060
|
+
<ion-spinner name="crescent" />
|
|
54061
|
+
</div>
|
|
54062
|
+
} @else if (filteredOrgs().length === 0) {
|
|
54063
|
+
<val-empty-state
|
|
54064
|
+
[props]="{
|
|
54065
|
+
variant: 'empty',
|
|
54066
|
+
title: t('noResults'),
|
|
54067
|
+
icon: 'business-outline',
|
|
54068
|
+
}"
|
|
54069
|
+
/>
|
|
54070
|
+
} @else {
|
|
54071
|
+
<div class="orgs-list">
|
|
54072
|
+
@for (org of filteredOrgs(); track org.id) {
|
|
54073
|
+
<button
|
|
54074
|
+
type="button"
|
|
54075
|
+
class="org-row"
|
|
54076
|
+
[class.org-row--active]="org.id === activeOrgId()"
|
|
54077
|
+
[disabled]="!!switchingId() || org.id === activeOrgId()"
|
|
54078
|
+
(click)="onSelect(org)"
|
|
54079
|
+
>
|
|
54080
|
+
<div class="org-row__icon">
|
|
54081
|
+
@if (org.logoUrl && !failedLogos().has(org.id)) {
|
|
54082
|
+
<img [src]="org.logoUrl" [alt]="org.name" (error)="onLogoError(org.id)" />
|
|
54083
|
+
} @else {
|
|
54084
|
+
<ion-icon name="business-outline" />
|
|
54085
|
+
}
|
|
54086
|
+
</div>
|
|
54087
|
+
<div class="org-row__body">
|
|
54088
|
+
<span class="org-row__name">{{ org.name }}</span>
|
|
54089
|
+
<span class="org-row__type">{{ org.type }}</span>
|
|
54090
|
+
</div>
|
|
54091
|
+
<div class="org-row__end">
|
|
54092
|
+
@if (switchingId() === org.id) {
|
|
54093
|
+
<ion-spinner name="crescent" class="org-row__spinner" />
|
|
54094
|
+
} @else if (org.id === activeOrgId()) {
|
|
54095
|
+
<span class="org-row__current">{{ t('current') }}</span>
|
|
54096
|
+
<ion-icon name="checkmark-circle-outline" class="org-row__check" />
|
|
54097
|
+
}
|
|
54098
|
+
</div>
|
|
54099
|
+
</button>
|
|
54100
|
+
}
|
|
54101
|
+
</div>
|
|
54102
|
+
}
|
|
54103
|
+
</div>
|
|
54104
|
+
|
|
54105
|
+
@if (onCreateOrg) {
|
|
54106
|
+
<div class="new-org-cta">
|
|
54107
|
+
<ion-button expand="block" fill="outline" color="dark" shape="round" (click)="onCreateNew()">
|
|
54108
|
+
<ion-icon slot="start" name="add-outline" />
|
|
54109
|
+
{{ t('newOrg') }}
|
|
54110
|
+
</ion-button>
|
|
54111
|
+
</div>
|
|
54112
|
+
}
|
|
54113
|
+
</ion-content>
|
|
54114
|
+
`, styles: [".switch-section{margin-top:16px;display:flex;flex-direction:column;gap:12px}.switch-state{display:flex;justify-content:center;padding:24px 0}.orgs-list{display:flex;flex-direction:column;gap:8px}.org-row{display:flex;align-items:center;gap:12px;width:100%;padding:12px 14px;border:1px solid rgba(var(--ion-color-dark-rgb),.14);border-radius:12px;background:var(--ion-card-background, var(--ion-background-color));cursor:pointer;text-align:left;transition:border-color .15s ease,opacity .15s ease}.org-row:not(:disabled):active{opacity:.7}.org-row:disabled{cursor:default}.org-row--active{border-color:var(--ion-color-dark)}.org-row__icon{width:36px;height:36px;border-radius:50%;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:18px;color:var(--ion-color-dark);background:rgba(var(--ion-color-dark-rgb),.08)}.org-row__body{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.org-row__name{font-weight:600;font-size:.95rem;color:var(--ion-color-dark);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.org-row__type{font-size:.8rem;color:rgba(var(--ion-color-dark-rgb),.7)}.org-row__end{display:flex;align-items:center;gap:6px;flex-shrink:0}.org-row__current{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:rgba(var(--ion-color-dark-rgb),.7)}.org-row__check{font-size:1.1rem;color:var(--ion-color-dark)}.org-row__spinner{width:18px;height:18px;color:var(--ion-color-dark)}.org-row__icon img{width:100%;height:100%;object-fit:cover;border-radius:50%}.user-strip{display:flex;align-items:center;gap:12px;padding:12px 0 4px;margin-bottom:8px;border-bottom:1px solid rgba(var(--ion-color-dark-rgb),.1)}.user-strip__avatar{width:44px;height:44px;border-radius:50%;flex-shrink:0;overflow:hidden;background:rgba(var(--ion-color-dark-rgb),.1);display:flex;align-items:center;justify-content:center;font-weight:700;font-size:1rem;color:var(--ion-color-dark)}.user-strip__avatar img{width:100%;height:100%;object-fit:cover}.user-strip__info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.user-strip__name{font-weight:600;font-size:.9rem;color:var(--ion-color-dark);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.user-strip__email{font-size:.78rem;color:rgba(var(--ion-color-dark-rgb),.6);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.user-strip__profile-btn{background:none;border:none;padding:6px 0;font-size:.82rem;font-weight:600;color:var(--ion-color-dark);cursor:pointer;white-space:nowrap;text-decoration:underline;text-underline-offset:3px}.new-org-cta{margin-top:16px;padding-top:16px;border-top:1px solid rgba(var(--ion-color-dark-rgb),.1)}\n"] }]
|
|
54115
|
+
}], ctorParameters: () => [], propDecorators: { _modalRef: [{
|
|
54116
|
+
type: Input
|
|
54117
|
+
}], onSuccess: [{
|
|
54118
|
+
type: Input
|
|
54119
|
+
}], onProfileClick: [{
|
|
54120
|
+
type: Input
|
|
54121
|
+
}], onCreateOrg: [{
|
|
54122
|
+
type: Input
|
|
54123
|
+
}], i18nNamespace: [{
|
|
54124
|
+
type: Input
|
|
54125
|
+
}] } });
|
|
54126
|
+
|
|
54198
54127
|
/**
|
|
54199
54128
|
* Defaults i18n (es/en) embebidos en `val-organization-view`. Auto-registrados en
|
|
54200
54129
|
* el constructor del componente si el consumer no proveyó el namespace
|
|
@@ -54265,6 +54194,7 @@ const ORGANIZATION_VIEW_I18N = {
|
|
|
54265
54194
|
apiKeysFeaturePermsDesc: 'Cada key lleva solo los permisos que tú le asignes — concede el mínimo.',
|
|
54266
54195
|
apiKeysFeatureSecretTitle: 'Secreto único',
|
|
54267
54196
|
apiKeysFeatureSecretDesc: 'El secreto se muestra una sola vez. Guárdalo en un gestor de secretos.',
|
|
54197
|
+
switchOrgCta: 'Cambiar organización',
|
|
54268
54198
|
orgsMoreInfo: 'Aprender más sobre organizaciones',
|
|
54269
54199
|
orgsInfoTitle: '¿Qué son las organizaciones?',
|
|
54270
54200
|
orgsInfoSubtitle: 'Todo lo que necesitas saber',
|
|
@@ -54363,6 +54293,7 @@ const ORGANIZATION_VIEW_I18N = {
|
|
|
54363
54293
|
apiKeysFeaturePermsDesc: 'Each key carries only the permissions you assign — grant the minimum.',
|
|
54364
54294
|
apiKeysFeatureSecretTitle: 'One-time secret',
|
|
54365
54295
|
apiKeysFeatureSecretDesc: 'The secret is shown only once. Store it in a secret manager.',
|
|
54296
|
+
switchOrgCta: 'Switch organization',
|
|
54366
54297
|
orgsMoreInfo: 'Learn more about organizations',
|
|
54367
54298
|
orgsInfoTitle: 'What are organizations?',
|
|
54368
54299
|
orgsInfoSubtitle: 'Everything you need to know',
|
|
@@ -54797,6 +54728,16 @@ class OrganizationViewComponent {
|
|
|
54797
54728
|
}
|
|
54798
54729
|
// "Más información" sobre organizaciones — mismo sheet explicativo que muestra
|
|
54799
54730
|
// account-view sin org, pero disponible siempre (todo user tiene org por defecto).
|
|
54731
|
+
onSwitchOrg() {
|
|
54732
|
+
void this.modalService.open({
|
|
54733
|
+
component: SwitchOrgModalComponent,
|
|
54734
|
+
componentProps: {
|
|
54735
|
+
i18nNamespace: 'Settings.SwitchOrg',
|
|
54736
|
+
},
|
|
54737
|
+
breakpoints: { breakpoints: [0, 0.85], initialBreakpoint: 0.85, showHandle: true },
|
|
54738
|
+
backdropDismiss: true,
|
|
54739
|
+
});
|
|
54740
|
+
}
|
|
54800
54741
|
onOrgInfo() {
|
|
54801
54742
|
void this.modalService.open({
|
|
54802
54743
|
component: OrgInfoSheetComponent,
|
|
@@ -55066,6 +55007,12 @@ class OrganizationViewComponent {
|
|
|
55066
55007
|
<button class="org-more-info-link" type="button" (click)="onOrgInfo()">
|
|
55067
55008
|
{{ tt('orgsMoreInfo') }}
|
|
55068
55009
|
</button>
|
|
55010
|
+
<!-- Cambiar de organización activa (solo si hay más de una). -->
|
|
55011
|
+
<div class="org-switch-row">
|
|
55012
|
+
<ion-button fill="outline" color="dark" shape="round" size="small" (click)="onSwitchOrg()">
|
|
55013
|
+
{{ tt('switchOrgCta') }}
|
|
55014
|
+
</ion-button>
|
|
55015
|
+
</div>
|
|
55069
55016
|
</header>
|
|
55070
55017
|
|
|
55071
55018
|
@if (resolvedConfig().showInfo) {
|
|
@@ -55367,7 +55314,7 @@ class OrganizationViewComponent {
|
|
|
55367
55314
|
(created)="onOrgCreated($event)"
|
|
55368
55315
|
/>
|
|
55369
55316
|
</div>
|
|
55370
|
-
`, isInline: true, styles: [".page{padding:16px 0;max-width:720px;margin:0 auto}.org-more-info-link{background:none;border:none;padding:4px 0;margin-top:4px;font-size:13px;font-weight:600;color:var(--ion-color-primary, #7026df);cursor:pointer;text-align:left}.page-header{margin-bottom:16px}.settings-section{padding:16px 0}.settings-section+.settings-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08))}.section-header-row{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px}.section-body{display:flex;flex-direction:column;gap:10px}.row-actions{margin-top:12px}.row-actions--gap{display:flex;gap:8px}.invite-cta{display:flex;flex-direction:column;gap:16px}.invite-cta__text{display:flex;flex-direction:column;gap:4px}.invite-cta__actions{display:flex;gap:12px;flex-wrap:wrap}.org-info-card{border-radius:14px;background:var(--ion-color-light, #f4f5f8);overflow:hidden}.org-info-logo{display:flex;justify-content:center;padding:8px 0 16px}.org-logo-img{width:80px;height:80px;border-radius:50%;object-fit:cover;border:2px solid var(--ion-color-light)}:host-context(body.dark) .org-info-card,:host-context(html.ion-palette-dark) .org-info-card,:host-context([data-theme=\"dark\"]) .org-info-card{background:#ffffff0d}.org-info-field{padding:12px 16px;display:flex;flex-direction:column;gap:4px;border-bottom:1px solid var(--val-border-color, rgba(0, 0, 0, .06))}.org-info-field:last-child{border-bottom:none}.org-info-label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--ion-color-medium)}.org-info-value{font-size:.95rem;font-weight:500;color:var(--ion-color-dark)}.org-info-value--muted{color:var(--ion-color-medium);font-weight:400}.plan-badge{display:inline-block;font-size:.78rem;font-weight:700;padding:3px 10px;border-radius:20px;width:fit-content}.plan-badge--free{background:var(--ion-color-light-shade, #d7d8da);color:var(--ion-color-dark)}.plan-badge--pro{background:var(--ion-color-primary);color:#fff}.plan-badge--enterprise{background:#f5c542;color:#222}.members-list{display:flex;flex-direction:column;gap:8px}.members-show-more{background:none;border:none;color:var(--ion-color-primary);font-size:14px;font-weight:500;cursor:pointer;padding:8px 0}.rbac-debug{opacity:.7}.rbac-debug__body{display:flex;flex-direction:column;gap:6px;font-family:monospace;font-size:.78rem}.rbac-debug__row{display:flex;gap:8px;align-items:flex-start}.rbac-debug__label{color:var(--ion-color-medium);min-width:72px;flex-shrink:0}.rbac-debug__value{color:var(--ion-color-dark);word-break:break-all}.rbac-debug__value--perms{color:var(--ion-color-medium)}.section-title-danger{display:flex;align-items:center;gap:8px;margin-bottom:12px}.section-title-danger val-title{display:block;margin:0}.danger-icon{display:block;font-size:1.125rem;color:var(--ion-color-warning-shade, #d4a017);flex-shrink:0}\n"], dependencies: [{ kind: "component", type: CreateOrgModalComponent, selector: "val-create-org-modal", inputs: ["i18nNamespace", "isOpen"], outputs: ["dismissed", "created"] }, { kind: "component", type: CtaCardComponent, selector: "val-cta-card", inputs: ["props"], outputs: ["onAction"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: EmptyStateComponent, selector: "val-empty-state", inputs: ["props"] }, { kind: "directive", type: HasPermissionDirective, selector: "[valHasPermission]", inputs: ["valHasPermission"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: SkeletonLayoutComponent, selector: "val-skeleton-layout", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { kind: "component", type: MemberCardComponent, selector: "val-member-card", inputs: ["props"], outputs: ["onAction"] }, { kind: "component", type: PermissionsModalComponent, selector: "val-permissions-modal", inputs: ["isOpen", "config"], outputs: ["dismissed"] }] }); }
|
|
55317
|
+
`, isInline: true, styles: [".page{padding:16px 0;max-width:720px;margin:0 auto}.org-more-info-link{background:none;border:none;padding:4px 0;margin-top:4px;font-size:13px;font-weight:600;color:var(--ion-color-primary, #7026df);cursor:pointer;text-align:left}.page-header{margin-bottom:16px}.settings-section{padding:16px 0}.settings-section+.settings-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08))}.section-header-row{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px}.section-body{display:flex;flex-direction:column;gap:10px}.row-actions{margin-top:12px}.row-actions--gap{display:flex;gap:8px}.invite-cta{display:flex;flex-direction:column;gap:16px}.invite-cta__text{display:flex;flex-direction:column;gap:4px}.invite-cta__actions{display:flex;gap:12px;flex-wrap:wrap}.org-info-card{border-radius:14px;background:var(--ion-color-light, #f4f5f8);overflow:hidden}.org-info-logo{display:flex;justify-content:center;padding:8px 0 16px}.org-logo-img{width:80px;height:80px;border-radius:50%;object-fit:cover;border:2px solid var(--ion-color-light)}:host-context(body.dark) .org-info-card,:host-context(html.ion-palette-dark) .org-info-card,:host-context([data-theme=\"dark\"]) .org-info-card{background:#ffffff0d}.org-info-field{padding:12px 16px;display:flex;flex-direction:column;gap:4px;border-bottom:1px solid var(--val-border-color, rgba(0, 0, 0, .06))}.org-info-field:last-child{border-bottom:none}.org-info-label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--ion-color-medium)}.org-info-value{font-size:.95rem;font-weight:500;color:var(--ion-color-dark)}.org-info-value--muted{color:var(--ion-color-medium);font-weight:400}.plan-badge{display:inline-block;font-size:.78rem;font-weight:700;padding:3px 10px;border-radius:20px;width:fit-content}.plan-badge--free{background:var(--ion-color-light-shade, #d7d8da);color:var(--ion-color-dark)}.plan-badge--pro{background:var(--ion-color-primary);color:#fff}.plan-badge--enterprise{background:#f5c542;color:#222}.members-list{display:flex;flex-direction:column;gap:8px}.members-show-more{background:none;border:none;color:var(--ion-color-primary);font-size:14px;font-weight:500;cursor:pointer;padding:8px 0}.rbac-debug{opacity:.7}.rbac-debug__body{display:flex;flex-direction:column;gap:6px;font-family:monospace;font-size:.78rem}.rbac-debug__row{display:flex;gap:8px;align-items:flex-start}.rbac-debug__label{color:var(--ion-color-medium);min-width:72px;flex-shrink:0}.rbac-debug__value{color:var(--ion-color-dark);word-break:break-all}.rbac-debug__value--perms{color:var(--ion-color-medium)}.section-title-danger{display:flex;align-items:center;gap:8px;margin-bottom:12px}.section-title-danger val-title{display:block;margin:0}.danger-icon{display:block;font-size:1.125rem;color:var(--ion-color-warning-shade, #d4a017);flex-shrink:0}\n"], dependencies: [{ kind: "component", type: CreateOrgModalComponent, selector: "val-create-org-modal", inputs: ["i18nNamespace", "isOpen"], outputs: ["dismissed", "created"] }, { kind: "component", type: CtaCardComponent, selector: "val-cta-card", inputs: ["props"], outputs: ["onAction"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: EmptyStateComponent, selector: "val-empty-state", inputs: ["props"] }, { kind: "directive", type: HasPermissionDirective, selector: "[valHasPermission]", inputs: ["valHasPermission"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: SkeletonLayoutComponent, selector: "val-skeleton-layout", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { kind: "component", type: MemberCardComponent, selector: "val-member-card", inputs: ["props"], outputs: ["onAction"] }, { kind: "component", type: PermissionsModalComponent, selector: "val-permissions-modal", inputs: ["isOpen", "config"], outputs: ["dismissed"] }] }); }
|
|
55371
55318
|
}
|
|
55372
55319
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OrganizationViewComponent, decorators: [{
|
|
55373
55320
|
type: Component,
|
|
@@ -55377,6 +55324,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
55377
55324
|
DisplayComponent,
|
|
55378
55325
|
EmptyStateComponent,
|
|
55379
55326
|
HasPermissionDirective,
|
|
55327
|
+
IonButton,
|
|
55380
55328
|
IonIcon,
|
|
55381
55329
|
SkeletonLayoutComponent,
|
|
55382
55330
|
TitleComponent,
|
|
@@ -55387,6 +55335,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
55387
55335
|
TransferOwnershipModalComponent,
|
|
55388
55336
|
MemberImportModalComponent,
|
|
55389
55337
|
OrgInfoSheetComponent,
|
|
55338
|
+
SwitchOrgModalComponent,
|
|
55390
55339
|
], template: `
|
|
55391
55340
|
<div class="page">
|
|
55392
55341
|
<header class="page-header">
|
|
@@ -55404,6 +55353,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
55404
55353
|
<button class="org-more-info-link" type="button" (click)="onOrgInfo()">
|
|
55405
55354
|
{{ tt('orgsMoreInfo') }}
|
|
55406
55355
|
</button>
|
|
55356
|
+
<!-- Cambiar de organización activa (solo si hay más de una). -->
|
|
55357
|
+
<div class="org-switch-row">
|
|
55358
|
+
<ion-button fill="outline" color="dark" shape="round" size="small" (click)="onSwitchOrg()">
|
|
55359
|
+
{{ tt('switchOrgCta') }}
|
|
55360
|
+
</ion-button>
|
|
55361
|
+
</div>
|
|
55407
55362
|
</header>
|
|
55408
55363
|
|
|
55409
55364
|
@if (resolvedConfig().showInfo) {
|
|
@@ -61944,7 +61899,7 @@ class LegalContentService {
|
|
|
61944
61899
|
const stream = fallback && fallback !== locale
|
|
61945
61900
|
? primary.pipe(catchError$1(() => this.loadOne(slug, fallback, options.basePath)))
|
|
61946
61901
|
: primary;
|
|
61947
|
-
const shared = stream.pipe(shareReplay
|
|
61902
|
+
const shared = stream.pipe(shareReplay({ bufferSize: 1, refCount: false }));
|
|
61948
61903
|
this.cache.set(key, shared);
|
|
61949
61904
|
return shared;
|
|
61950
61905
|
}
|