login-tsi 0.0.7 → 0.0.8
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/fesm2022/login-tsi.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NgClass } from '@angular/common';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { signal, Injectable, inject, input, output, Component, computed, model, HostListener } from '@angular/core';
|
|
3
|
+
import { signal, Injectable, inject, input, output, Component, computed, model, HostListener, InjectionToken, viewChild, DestroyRef, effect, untracked, afterRenderEffect } from '@angular/core';
|
|
4
4
|
import * as i1 from '@angular/forms';
|
|
5
5
|
import { ReactiveFormsModule, FormBuilder, Validators, FormsModule } from '@angular/forms';
|
|
6
6
|
import { trigger, transition, style, animate } from '@angular/animations';
|
|
@@ -319,6 +319,201 @@ class AuthSender {
|
|
|
319
319
|
codsuc;
|
|
320
320
|
}
|
|
321
321
|
|
|
322
|
+
const MFA_API = new InjectionToken('MFA_API');
|
|
323
|
+
function provideMfaApi(factory) {
|
|
324
|
+
return { provide: MFA_API, useFactory: factory };
|
|
325
|
+
}
|
|
326
|
+
function isMfaChallenge(body) {
|
|
327
|
+
return body?.mfaRequerido === true && !!body?.preauthToken;
|
|
328
|
+
}
|
|
329
|
+
function isPushPendiente(body) {
|
|
330
|
+
return body?.result === 'waiting' || body?.result === 'deny' || body?.result === 'expired';
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const INTERVALO_ESTADO_MS = 2000;
|
|
334
|
+
const MAXIMO_ESPERA_MS = 120000;
|
|
335
|
+
const CAMPOS_CODIGO = {
|
|
336
|
+
totp: {
|
|
337
|
+
label: 'Código de verificación', placeholder: '000000', icon: 'fa-mobile-alt', inputmode: 'numeric',
|
|
338
|
+
patron: /^\d{6}$/,
|
|
339
|
+
descri: 'Ingresa el código de 6 dígitos que muestra tu app de autenticación.',
|
|
340
|
+
mensajeInvalido: 'Ingresa el código de 6 dígitos de tu app.',
|
|
341
|
+
mensajeIncorrecto: 'Código incorrecto. Verifica la hora de tu dispositivo.'
|
|
342
|
+
},
|
|
343
|
+
respaldo: {
|
|
344
|
+
label: 'Código de respaldo', placeholder: 'XXXX-XXXX', icon: 'fa-key', inputmode: 'text',
|
|
345
|
+
patron: /^[A-Z0-9]{4}-[A-Z0-9]{4}$/,
|
|
346
|
+
descri: 'Ingresa uno de tus códigos de respaldo. Cada código sirve una sola vez.',
|
|
347
|
+
mensajeInvalido: 'Ingresa un código de respaldo válido (XXXX-XXXX).',
|
|
348
|
+
mensajeIncorrecto: 'Código de respaldo incorrecto o ya utilizado.'
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
const limpiarCodigo = (valor, tipo) => {
|
|
352
|
+
if (tipo == 'totp')
|
|
353
|
+
return valor.replace(/\D/g, '').slice(0, 6);
|
|
354
|
+
const base = valor.toUpperCase().replace(/[^A-Z0-9]/g, '').slice(0, 8);
|
|
355
|
+
return base.length > 4 ? `${base.slice(0, 4)}-${base.slice(4)}` : base;
|
|
356
|
+
};
|
|
357
|
+
const mensajeDe = (err, defecto) => typeof err == 'string' && err ? err : defecto;
|
|
358
|
+
const esperar = (ms, signal) => new Promise(resolve => {
|
|
359
|
+
const id = setTimeout(resolve, ms);
|
|
360
|
+
signal.addEventListener('abort', () => { clearTimeout(id); resolve(); }, { once: true });
|
|
361
|
+
});
|
|
362
|
+
class MdVerificarMfaComponent {
|
|
363
|
+
api = inject(MFA_API);
|
|
364
|
+
challenge = input.required();
|
|
365
|
+
titulo = input('Verificación en dos pasos');
|
|
366
|
+
showCancelar = input(true);
|
|
367
|
+
verificado = output();
|
|
368
|
+
cancelado = output();
|
|
369
|
+
tienePush = computed(() => (this.challenge().tipos ?? []).includes('PUSH'));
|
|
370
|
+
tieneTotp = computed(() => {
|
|
371
|
+
const tipos = this.challenge().tipos ?? [];
|
|
372
|
+
return tipos.length == 0 || tipos.includes('TOTP');
|
|
373
|
+
});
|
|
374
|
+
modo = signal('codigo');
|
|
375
|
+
tipoCodigo = signal('totp');
|
|
376
|
+
campo = computed(() => CAMPOS_CODIGO[this.tipoCodigo()]);
|
|
377
|
+
codigo = signal('');
|
|
378
|
+
codigoError = signal('');
|
|
379
|
+
isEnviando = signal(false);
|
|
380
|
+
estadoPush = signal('idle');
|
|
381
|
+
isPushEnCurso = computed(() => this.estadoPush() == 'enviando' || this.estadoPush() == 'esperando');
|
|
382
|
+
pushError = signal('');
|
|
383
|
+
inputCodigo = viewChild('inputCodigo');
|
|
384
|
+
pushCtrl;
|
|
385
|
+
constructor() {
|
|
386
|
+
inject(DestroyRef).onDestroy(() => this.cancelarPush());
|
|
387
|
+
effect(() => {
|
|
388
|
+
this.challenge();
|
|
389
|
+
untracked(() => this.iniciar());
|
|
390
|
+
});
|
|
391
|
+
afterRenderEffect(() => {
|
|
392
|
+
if (this.modo() != 'codigo' || this.isEnviando())
|
|
393
|
+
return;
|
|
394
|
+
this.tipoCodigo();
|
|
395
|
+
this.codigoError();
|
|
396
|
+
this.inputCodigo()?.nativeElement.focus();
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
iniciar() {
|
|
400
|
+
this.cancelarPush();
|
|
401
|
+
this.pushError.set('');
|
|
402
|
+
if (this.tienePush() && !this.tieneTotp()) {
|
|
403
|
+
this.usarPush();
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
this.usarCodigo('totp');
|
|
407
|
+
}
|
|
408
|
+
onCodigoInput(event) {
|
|
409
|
+
const input = event.target;
|
|
410
|
+
const limpio = limpiarCodigo(input.value, this.tipoCodigo());
|
|
411
|
+
input.value = limpio;
|
|
412
|
+
this.codigo.set(limpio);
|
|
413
|
+
if (this.codigoError())
|
|
414
|
+
this.codigoError.set('');
|
|
415
|
+
}
|
|
416
|
+
usarCodigo(tipo) {
|
|
417
|
+
this.cancelarPush();
|
|
418
|
+
this.modo.set('codigo');
|
|
419
|
+
this.tipoCodigo.set(tipo);
|
|
420
|
+
this.codigo.set('');
|
|
421
|
+
this.codigoError.set('');
|
|
422
|
+
}
|
|
423
|
+
async verificar() {
|
|
424
|
+
if (this.modo() == 'push' || this.isEnviando())
|
|
425
|
+
return;
|
|
426
|
+
const campo = this.campo();
|
|
427
|
+
if (!campo.patron.test(this.codigo())) {
|
|
428
|
+
this.codigoError.set(campo.mensajeInvalido);
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
this.isEnviando.set(true);
|
|
432
|
+
this.codigoError.set('');
|
|
433
|
+
try {
|
|
434
|
+
await this.api.verificarCodigo({ preauthToken: this.challenge().preauthToken, codigo: this.codigo() });
|
|
435
|
+
this.verificado.emit();
|
|
436
|
+
}
|
|
437
|
+
catch (err) {
|
|
438
|
+
this.codigo.set('');
|
|
439
|
+
this.codigoError.set(mensajeDe(err, campo.mensajeIncorrecto));
|
|
440
|
+
}
|
|
441
|
+
finally {
|
|
442
|
+
this.isEnviando.set(false);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
usarPush() {
|
|
446
|
+
this.modo.set('push');
|
|
447
|
+
this.codigoError.set('');
|
|
448
|
+
this.enviarPush();
|
|
449
|
+
}
|
|
450
|
+
async enviarPush() {
|
|
451
|
+
this.cancelarPush();
|
|
452
|
+
const ctrl = new AbortController();
|
|
453
|
+
this.pushCtrl = ctrl;
|
|
454
|
+
this.pushError.set('');
|
|
455
|
+
this.estadoPush.set('enviando');
|
|
456
|
+
const preauthToken = this.challenge().preauthToken;
|
|
457
|
+
try {
|
|
458
|
+
const solicitudId = await this.api.enviarPush(preauthToken);
|
|
459
|
+
if (ctrl.signal.aborted)
|
|
460
|
+
return;
|
|
461
|
+
this.estadoPush.set('esperando');
|
|
462
|
+
const limite = Date.now() + MAXIMO_ESPERA_MS;
|
|
463
|
+
while (Date.now() < limite) {
|
|
464
|
+
const estado = await this.api.estadoPush({ preauthToken, solicitudId });
|
|
465
|
+
if (ctrl.signal.aborted)
|
|
466
|
+
return;
|
|
467
|
+
if (estado != 'waiting') {
|
|
468
|
+
this.resolverPush(estado);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
await esperar(INTERVALO_ESTADO_MS, ctrl.signal);
|
|
472
|
+
if (ctrl.signal.aborted)
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
this.estadoPush.set('expirado');
|
|
476
|
+
this.pushError.set('No respondiste a tiempo la notificación. Vuelve a enviarla.');
|
|
477
|
+
}
|
|
478
|
+
catch (err) {
|
|
479
|
+
if (ctrl.signal.aborted)
|
|
480
|
+
return;
|
|
481
|
+
this.estadoPush.set('idle');
|
|
482
|
+
this.pushError.set(mensajeDe(err, 'No se pudo enviar la notificación.'));
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
cancelar() {
|
|
486
|
+
this.cancelarPush();
|
|
487
|
+
this.cancelado.emit();
|
|
488
|
+
}
|
|
489
|
+
resolverPush(estado) {
|
|
490
|
+
if (estado == 'aprobado') {
|
|
491
|
+
this.estadoPush.set('idle');
|
|
492
|
+
this.verificado.emit();
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
if (estado == 'expired') {
|
|
496
|
+
this.estadoPush.set('expirado');
|
|
497
|
+
this.pushError.set('La solicitud expiró. Vuelve a enviarla.');
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
this.estadoPush.set('rechazado');
|
|
501
|
+
this.pushError.set('Rechazaste la notificación en tu teléfono.');
|
|
502
|
+
}
|
|
503
|
+
cancelarPush() {
|
|
504
|
+
this.pushCtrl?.abort();
|
|
505
|
+
this.pushCtrl = undefined;
|
|
506
|
+
if (this.isPushEnCurso())
|
|
507
|
+
this.estadoPush.set('idle');
|
|
508
|
+
}
|
|
509
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: MdVerificarMfaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
510
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.25", type: MdVerificarMfaComponent, isStandalone: true, selector: "lib-md-verificar-mfa", inputs: { challenge: { classPropertyName: "challenge", publicName: "challenge", isSignal: true, isRequired: true, transformFunction: null }, titulo: { classPropertyName: "titulo", publicName: "titulo", isSignal: true, isRequired: false, transformFunction: null }, showCancelar: { classPropertyName: "showCancelar", publicName: "showCancelar", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { verificado: "verificado", cancelado: "cancelado" }, viewQueries: [{ propertyName: "inputCodigo", first: true, predicate: ["inputCodigo"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"verificar-mfa\">\n <div class=\"auth-card-title mb-3\">{{ titulo() }}</div>\n\n <div class=\"d-flex align-items-center gap-3 mb-3\">\n <span class=\"verificar-mfa__icono\"><i class=\"fas fa-user-shield\"></i></span>\n <div>\n <div class=\"fw-semibold\">{{ challenge().coduser }}</div>\n @if (challenge().empresa) {\n <div class=\"verificar-mfa__muted\">{{ challenge().empresa }}</div>\n }\n </div>\n </div>\n\n @if (modo() == 'push') {\n @switch (estadoPush()) {\n @case ('enviando') {\n <div class=\"duo-push\">\n <span class=\"spinner-border spinner-border-sm text-primary\"></span>\n <div class=\"flex-grow-1\">Enviando notificaci\u00F3n a tu tel\u00E9fono\u2026</div>\n </div>\n }\n @case ('esperando') {\n <div class=\"duo-push duo-push--esperando\">\n <span class=\"duo-push__icono duo-push__icono--pulso\"><i class=\"fas fa-mobile-alt\"></i></span>\n <div class=\"flex-grow-1\">\n <div class=\"fw-semibold\">Revisa tu tel\u00E9fono</div>\n <div class=\"verificar-mfa__muted\">Aprueba la notificaci\u00F3n en TSI Autenticador para ingresar.</div>\n </div>\n </div>\n }\n @default {\n <div class=\"duo-push\">\n <span class=\"duo-push__icono\"><i class=\"fas fa-bell\"></i></span>\n <div class=\"flex-grow-1\">\n <div class=\"fw-semibold\">TSI Autenticador</div>\n <div class=\"verificar-mfa__muted\">Te enviaremos una notificaci\u00F3n para que la apruebes.</div>\n </div>\n </div>\n }\n }\n @if (pushError() && !isPushEnCurso()) {\n <div class=\"codigo-field__error\"><i class=\"fas fa-exclamation-circle\"></i> {{ pushError() }}</div>\n }\n\n <div class=\"verificar-mfa__opciones\">\n @if (tieneTotp()) {\n <button type=\"button\" class=\"verificar-mfa__link\" (click)=\"usarCodigo('totp')\">\n Usar c\u00F3digo de mi app de autenticaci\u00F3n\n </button>\n }\n <button type=\"button\" class=\"verificar-mfa__link verificar-mfa__link--secundario\"\n (click)=\"usarCodigo('respaldo')\">\n \u00BFNo tienes tu tel\u00E9fono? Usa un c\u00F3digo de respaldo\n </button>\n </div>\n } @else {\n <p class=\"verificar-mfa__muted mb-4\">\n @if (tipoCodigo() == 'totp') {\n {{ challenge().mensaje || campo().descri }}\n } @else {\n {{ campo().descri }}\n }\n </p>\n\n <div class=\"codigo-field\" [class.has-error]=\"codigoError()\">\n <span class=\"codigo-field__icon\"><i class=\"fas\" [class]=\"campo().icon\"></i></span>\n <input #inputCodigo id=\"mfa-codigo\" class=\"codigo-field__input\" type=\"text\"\n [placeholder]=\"campo().placeholder\" [value]=\"codigo()\" (input)=\"onCodigoInput($event)\"\n (keydown.enter)=\"verificar()\" [attr.inputmode]=\"campo().inputmode\" autocomplete=\"one-time-code\"\n autocorrect=\"off\" autocapitalize=\"characters\" spellcheck=\"false\" [disabled]=\"isEnviando()\">\n <label for=\"mfa-codigo\" class=\"codigo-field__label\">{{ campo().label }}</label>\n </div>\n @if (codigoError()) {\n <div class=\"codigo-field__error\"><i class=\"fas fa-exclamation-circle\"></i> {{ codigoError() }}</div>\n }\n\n <div class=\"verificar-mfa__opciones\">\n @if (tienePush()) {\n <button type=\"button\" class=\"verificar-mfa__link\" (click)=\"usarPush()\">\n <i class=\"fas fa-bell me-1\"></i>Mejor env\u00EDame una notificaci\u00F3n push\n </button>\n }\n @if (tieneTotp() && tipoCodigo() != 'totp') {\n <button type=\"button\" class=\"verificar-mfa__link\" (click)=\"usarCodigo('totp')\">\n Usar c\u00F3digo de mi app de autenticaci\u00F3n\n </button>\n }\n @if (tipoCodigo() != 'respaldo') {\n <button type=\"button\" class=\"verificar-mfa__link verificar-mfa__link--secundario\"\n (click)=\"usarCodigo('respaldo')\">\n \u00BFNo tienes tu tel\u00E9fono? Usa un c\u00F3digo de respaldo\n </button>\n }\n </div>\n }\n\n <div class=\"verificar-mfa__acciones\">\n @if (modo() == 'push') {\n <button type=\"button\" class=\"auth-btn\" [disabled]=\"isPushEnCurso()\" (click)=\"enviarPush()\">\n <i class=\"fas fa-paper-plane me-1\"></i>\n {{ isPushEnCurso() ? 'Esperando aprobaci\u00F3n\u2026' : 'Reenviar notificaci\u00F3n' }}\n </button>\n } @else {\n <button type=\"button\" class=\"auth-btn\" [disabled]=\"isEnviando()\" (click)=\"verificar()\">\n <i class=\"fas fa-check me-1\"></i>\n {{ isEnviando() ? 'Verificando\u2026' : 'Verificar' }}\n </button>\n }\n @if (showCancelar()) {\n <button type=\"button\" class=\"auth-btn auth-btn--outline\" (click)=\"cancelar()\">Cancelar</button>\n }\n </div>\n</div>\n", styles: [".verificar-mfa{color:var(--text-color)}.verificar-mfa__icono{display:inline-flex;flex-shrink:0;align-items:center;justify-content:center;width:44px;height:44px;border-radius:12px;color:var(--bs-primary);background:rgba(var(--bs-primary-rgb),.1);font-size:20px}.verificar-mfa__muted{font-size:13px;line-height:1.5;color:var(--bs-secondary-color)}.verificar-mfa__link:hover{text-decoration:underline}.verificar-mfa__link{padding:0;border:0;background:none;font-size:13px;font-weight:600;color:var(--bs-primary)}.codigo-field{position:relative}.codigo-field__icon{position:absolute;left:14px;top:50%;transform:translateY(-50%);z-index:2;font-size:15px;color:var(--placeholder-color);pointer-events:none;transition:color .2s}.codigo-field__input{width:100%;height:56px;padding:0 44px;border:1.5px solid var(--font-border-input);border-radius:10px;outline:none;background:var(--background-input);color:var(--color-input);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:22px;font-weight:600;letter-spacing:.45em;text-align:center;transition:border-color .2s,box-shadow .2s,background .2s}.codigo-field__input::placeholder{color:var(--placeholder-color);opacity:.45}.codigo-field__input:focus{border-color:var(--bs-primary);box-shadow:0 0 0 3.5px rgba(var(--bs-primary-rgb),.15);background:var(--background-focus-input)}.codigo-field__input:disabled{opacity:.7}.codigo-field__label{position:absolute;left:12px;top:0;transform:translateY(-50%);z-index:1;margin:0!important;padding:0 4px;font-size:11px!important;font-weight:500!important;line-height:1.2;color:var(--placeholder-color);background:var(--background-card);pointer-events:none;transition:color .15s ease}.codigo-field:focus-within .codigo-field__label,.codigo-field:focus-within .codigo-field__icon{color:var(--bs-primary)}.codigo-field.has-error .codigo-field__input{border-color:var(--bs-danger);box-shadow:0 0 0 3.5px rgba(var(--bs-danger-rgb),.12)}.codigo-field.has-error .codigo-field__icon,.codigo-field.has-error .codigo-field__label{color:var(--bs-danger)}.codigo-field__error{display:flex;align-items:center;gap:6px;margin-top:8px;font-size:13px;font-weight:500;color:var(--bs-danger)}.duo-push{display:flex;align-items:center;gap:12px;padding:14px;border:1.5px solid var(--font-border-input);border-radius:10px;background:var(--background-input);color:var(--text-color);font-size:14px}.duo-push--esperando{border-color:rgba(var(--bs-primary-rgb),.45);background:rgba(var(--bs-primary-rgb),.06)}.duo-push__icono{display:inline-flex;flex-shrink:0;align-items:center;justify-content:center;width:40px;height:40px;border-radius:50%;color:var(--bs-primary);background:rgba(var(--bs-primary-rgb),.1);font-size:18px}.duo-push__icono--pulso{animation:duo-pulso 1.4s ease-in-out infinite}@keyframes duo-pulso{0%,to{box-shadow:0 0 rgba(var(--bs-primary-rgb),.35)}50%{box-shadow:0 0 0 8px rgba(var(--bs-primary-rgb),0)}}@media(prefers-reduced-motion:reduce){.duo-push__icono--pulso{animation:none}}.verificar-mfa__opciones{display:flex;flex-direction:column;align-items:flex-start;gap:8px;margin-top:16px}.verificar-mfa__link--secundario{font-weight:500;color:var(--bs-secondary-color)}.verificar-mfa__acciones{margin-top:24px}\n", "@charset \"UTF-8\";.red_contrasena,.blue_contrasena{position:relative;display:inline-block;font-size:13px;text-decoration:none;padding-bottom:2px;transition:color .3s ease;cursor:pointer}.red_contrasena:after,.blue_contrasena:after{content:\"\";position:absolute;bottom:0;left:50%;width:0;height:1px;background-color:currentColor;transition:all .3s ease;transform:translate(-50%)}.red_contrasena:hover:after,.blue_contrasena:hover:after{width:60%}.red_contrasena{color:#d1326f}.red_contrasena:hover{color:#a82859}.blue_contrasena{color:#398bf7}.blue_contrasena:hover{color:#1e5fc4}.auth-wrapper-login{position:fixed;inset:0;display:grid;grid-template-columns:1.15fr .85fr;overflow:hidden;background:#060d1f}.auth-panel-left{position:relative;overflow:hidden;background:linear-gradient(145deg,#040a18,#0b1a3d 55%,#040e22);display:flex;align-items:center;justify-content:center;padding:48px 40px}.auth-panel-left:before{content:\"\";position:absolute;inset:0;background-image:radial-gradient(circle,rgba(255,255,255,.055) 1px,transparent 1px);background-size:26px 26px;z-index:1;pointer-events:none}.auth-panel-left:after{content:\"\";position:absolute;top:0;left:-120%;width:60%;height:100%;background:linear-gradient(90deg,transparent,rgba(57,139,247,.04),transparent);animation:panelSweep 7s ease-in-out infinite;z-index:1;pointer-events:none}.auth-blob{position:absolute;border-radius:50%;filter:blur(72px);z-index:0;pointer-events:none}.auth-blob-1{width:340px;height:340px;background:radial-gradient(circle,rgba(57,139,247,.45) 0%,transparent 70%);top:-90px;right:-70px;animation:blobDrift 11s ease-in-out infinite}.auth-blob-2{width:240px;height:240px;background:radial-gradient(circle,rgba(124,58,237,.4) 0%,transparent 70%);bottom:60px;left:-50px;animation:blobDrift 14s ease-in-out infinite reverse}.auth-blob-3{width:180px;height:180px;background:radial-gradient(circle,rgba(14,165,233,.35) 0%,transparent 70%);bottom:-50px;right:40px;animation:blobDrift 9s ease-in-out infinite;animation-delay:-4s}.auth-blob-4{width:120px;height:120px;background:radial-gradient(circle,rgba(209,50,111,.25) 0%,transparent 70%);top:50%;left:50%;transform:translate(-50%,-50%);animation:blobDrift 16s ease-in-out infinite;animation-delay:-8s}@keyframes blobDrift{0%,to{transform:translate(0) scale(1)}33%{transform:translate(14px,-20px) scale(1.05)}66%{transform:translate(-10px,12px) scale(.96)}}@keyframes panelSweep{0%{left:-120%}50%{left:160%}to{left:160%}}.auth-brand-panel{position:relative;z-index:2;text-align:center;color:#fff;max-width:340px}.auth-brand-logo{width:100px;height:100px;border-radius:50%;background:#ffffff0d;border:1px solid rgba(255,255,255,.1);display:flex;align-items:center;justify-content:center;margin:0 auto 28px;box-shadow:0 0 0 14px #398bf70f,0 0 50px #398bf733;backdrop-filter:blur(8px)}.auth-brand-logo img{width:64px;height:64px;object-fit:contain;filter:brightness(1.05) drop-shadow(0 0 8px rgba(57,139,247,.4))}.auth-brand-title{font-size:30px;font-weight:700;letter-spacing:-.5px;margin-bottom:10px;background:linear-gradient(135deg,#fff 20%,#93c5fd 80%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}.auth-brand-subtitle{font-size:14px;color:#ffffff73;line-height:1.65;margin-bottom:40px;letter-spacing:.2px}.auth-brand-features{display:flex;flex-direction:column;gap:14px;text-align:left}.auth-brand-feature{display:flex;align-items:center;gap:12px;font-size:13px;color:#fff9}.auth-brand-feature .feat-dot{flex-shrink:0;width:7px;height:7px;border-radius:50%;background:#398bf7;box-shadow:0 0 10px #398bf7b3}.auth-brand-divider{width:60px;height:2px;background:linear-gradient(90deg,transparent,#398bf7,transparent);margin:28px auto 32px;border-radius:2px}.auth-panel-left--dev{background:linear-gradient(145deg,#18040b,#3d0b1d 55%,#220409)}.auth-panel-left--dev:after{background:linear-gradient(90deg,transparent,rgba(209,50,111,.05),transparent)}.auth-panel-left--dev .auth-blob-1{background:radial-gradient(circle,rgba(220,38,38,.52) 0%,transparent 70%)}.auth-panel-left--dev .auth-blob-2{background:radial-gradient(circle,rgba(219,39,119,.44) 0%,transparent 70%)}.auth-panel-left--dev .auth-blob-3{background:radial-gradient(circle,rgba(239,68,68,.38) 0%,transparent 70%)}.auth-panel-left--dev .auth-blob-4{background:radial-gradient(circle,rgba(249,115,22,.28) 0%,transparent 70%)}.auth-panel-left--dev .auth-brand-logo{box-shadow:0 0 0 14px #d1326f12,0 0 50px #d1326f38}.auth-panel-left--dev .auth-brand-logo img{filter:brightness(1.05) drop-shadow(0 0 8px rgba(209,50,111,.45))}.auth-panel-left--dev .auth-brand-title{background:linear-gradient(135deg,#fff 20%,#fca5a5 80%);-webkit-background-clip:text;background-clip:text}.auth-panel-left--dev .auth-brand-divider{background:linear-gradient(90deg,transparent,rgb(209,50,111),transparent)}.auth-panel-left--dev .feat-dot{background:#d1326f;box-shadow:0 0 10px #d1326fb8}.auth-panel-right{position:relative;overflow:hidden;background:var(--background-login)}.auth-panel-right:before{content:\"\";position:absolute;inset:0;background-image:repeating-linear-gradient(-55deg,transparent 0px,transparent 22px,rgba(57,139,247,.045) 22px,rgba(57,139,247,.045) 23px);animation:authLinesMove 10s linear infinite;pointer-events:none;z-index:0}.auth-panel-right:after{content:\"\";position:absolute;top:0;bottom:0;left:-25%;width:25%;background:linear-gradient(90deg,transparent 0%,rgba(57,139,247,.02) 30%,rgba(57,139,247,.045) 50%,rgba(57,139,247,.02) 70%,transparent 100%);animation:authScanLine 7s ease-in-out infinite;animation-delay:3.5s;pointer-events:none;z-index:0}@keyframes authLinesMove{0%{transform:translate(0)}to{transform:translate(46px,46px)}}@keyframes authScanLine{0%{left:-25%}50%{left:120%}to{left:120%}}.auth-panel-bg{position:absolute;inset:0;pointer-events:none;z-index:0;overflow:hidden}.auth-deco{position:absolute;border-radius:50%;pointer-events:none;filter:blur(70px)}.auth-deco-tl{width:300px;height:300px;top:0;left:-120px;transform:translateY(-40%);background:radial-gradient(circle,rgba(57,139,247,.12) 0%,transparent 70%);animation:authOrbPulse 6s ease-in-out infinite}.auth-deco-br{width:340px;height:340px;bottom:0;right:-120px;transform:translateY(40%);background:radial-gradient(circle,rgba(124,58,237,.1) 0%,transparent 70%);animation:authOrbPulse 8s ease-in-out infinite;animation-delay:-4s}@keyframes authOrbPulse{0%,to{opacity:.7}50%{opacity:1}}.auth-form-wrapper{position:absolute;inset:0;overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;align-items:center;z-index:1}.auth-form-wrapper>div{width:100%;max-width:420px;margin:auto;padding:36px 16px;box-sizing:border-box}.auth-panel-right--dev:before{background-image:repeating-linear-gradient(-55deg,transparent 0px,transparent 22px,rgba(209,50,111,.05) 22px,rgba(209,50,111,.05) 23px)}.auth-panel-right--dev:after{background:linear-gradient(90deg,transparent 0%,rgba(209,50,111,.02) 30%,rgba(209,50,111,.045) 50%,rgba(209,50,111,.02) 70%,transparent 100%)}.auth-panel-right--dev .auth-deco-tl{background:radial-gradient(circle,rgba(209,50,111,.12) 0%,transparent 70%)}.auth-panel-right--dev .auth-deco-br{background:radial-gradient(circle,rgba(239,68,68,.1) 0%,transparent 70%)}.auth-test-badge{display:inline-flex;align-items:center;gap:7px;background:#d1326f14;border:1px solid rgba(209,50,111,.25);color:#d1326f;font-size:10.5px;font-weight:700;padding:5px 12px;border-radius:20px;margin-bottom:18px;letter-spacing:.8px}.auth-test-badge .badge-dot{width:6px;height:6px;border-radius:50%;background:#d1326f;animation:badgePulse 1.6s ease-in-out infinite;flex-shrink:0}@keyframes badgePulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.45;transform:scale(.75)}}.auth-card{background:var(--background-card);border-radius:20px;padding:36px 32px 28px;box-shadow:0 4px 28px #00000014;border:1px solid var(--border-color-modal)}.auth-card-title{font-size:22px;font-weight:700;color:var(--text-color);margin-bottom:4px;letter-spacing:-.3px}.auth-card-subtitle{font-size:13px;color:var(--placeholder-color);margin-bottom:26px}.auth-field{position:relative;margin-bottom:1rem}.auth-field .auth-field-icon{position:absolute;left:13px;top:50%;transform:translateY(-50%);color:var(--placeholder-color);font-size:13px;z-index:2;pointer-events:none;transition:color .2s}.auth-field .auth-input{width:100%;padding:15px 40px 15px 37px;background:var(--background-input);border:1.5px solid var(--font-border-input);border-radius:10px;font-size:14px;color:var(--color-input);outline:none;transition:border-color .2s,box-shadow .2s,background .2s}.auth-field .auth-input::placeholder{color:transparent}.auth-field .auth-input:focus{border-color:#398bf7;box-shadow:0 0 0 3.5px #398bf721;background:var(--background-focus-input)}.auth-field .auth-input:focus~.auth-label{top:0;font-size:11px!important;color:#398bf7!important;background:var(--background-card);padding:0 4px;transform:translateY(-50%)}.auth-field .auth-input:focus~.auth-field-icon{color:#398bf7}.auth-field .auth-input:not(:placeholder-shown)~.auth-label{top:0;font-size:11px!important;background:var(--background-card);padding:0 4px;transform:translateY(-50%)}.auth-field .auth-label{position:absolute;left:35px;top:50%;transform:translateY(-50%);color:var(--placeholder-color)!important;font-size:13px!important;font-weight:400!important;pointer-events:none;transition:top .15s ease,font-size .15s ease,color .15s ease,padding .15s ease,background .15s ease;background:transparent;z-index:1;text-align:left!important}.auth-field .auth-toggle-pw{position:absolute;right:10px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--placeholder-color);cursor:pointer;padding:4px 6px;font-size:13px;z-index:2;line-height:1;transition:color .2s}.auth-field .auth-toggle-pw:hover{color:#398bf7}.auth-field.has-error .auth-input{border-color:#dc3545;box-shadow:none}.auth-field.has-error .auth-field-icon{color:#dc3545}.auth-select{width:100%;padding:13px 14px;background:var(--background-input);border:1.5px solid var(--font-border-input);border-radius:10px;font-size:14px;color:var(--color-input);outline:none;transition:border-color .2s,box-shadow .2s;margin-bottom:1rem;cursor:pointer}.auth-select:focus{border-color:#398bf7;box-shadow:0 0 0 3.5px #398bf721}.auth-btn{width:100%;padding:13px;border:none;border-radius:10px;font-size:14px;font-weight:600;cursor:pointer;transition:transform .15s ease,box-shadow .2s ease,opacity .2s;background:linear-gradient(135deg,#398bf7,#1e5fc4);color:#fff;letter-spacing:.3px;margin-bottom:10px;display:block}.auth-btn:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 5px 18px #398bf761}.auth-btn:active:not(:disabled){transform:translateY(0)}.auth-btn:disabled{opacity:.55;cursor:not-allowed}.auth-btn.auth-btn--red{background:linear-gradient(135deg,#d1326f,#a82859)}.auth-btn.auth-btn--red:hover:not(:disabled){box-shadow:0 5px 18px #d1326f61}.auth-btn.auth-btn--outline{background:transparent;border:1.5px solid var(--font-border-input);color:var(--text-color)}.auth-btn.auth-btn--outline:hover:not(:disabled){background:var(--background-btn-light-hover);box-shadow:none;transform:none}.auth-links{display:flex;flex-direction:column;align-items:center;gap:10px;margin-top:16px;padding-top:16px;border-top:1px solid var(--border-color-modal)}.auth-version{text-align:right;margin-top:14px;padding-top:12px;border-top:1px solid var(--border-color-modal)}.auth-version span{font-size:11px;color:var(--placeholder-color)}.auth-error{font-size:11.5px;color:#dc3545;margin:-6px 0 10px 2px;padding:0}.auth-hint{display:flex;align-items:flex-start;gap:6px;font-size:11.5px;color:var(--placeholder-color);margin:-6px 0 14px 2px;padding:0;line-height:1.35}.auth-hint i{margin-top:2px;flex-shrink:0}.auth-validation-list{margin:-4px 0 12px;padding:0;list-style:none}.auth-validation-list li{font-size:11.5px;color:#dc3545;padding:2px 0}.auth-validation-list li:before{content:\"\\2715 \";font-size:10px}.auth-desc{font-size:13px;color:var(--placeholder-color);margin-bottom:20px;line-height:1.65}.auth-section-title{font-size:15px;font-weight:600;color:var(--text-color);margin-bottom:20px}.font-12{font-size:12px}.form-control:focus{border-color:#0199ff9a!important;box-shadow:0 0 5px .2px #65befa44!important}@media(max-width:900px){.auth-wrapper-login{grid-template-columns:1fr;grid-template-rows:auto 1fr;overflow-y:auto;overflow-x:hidden}.auth-panel-left{padding:14px 24px;justify-content:center}.auth-panel-left .auth-brand-subtitle,.auth-panel-left .auth-brand-features,.auth-panel-left .auth-brand-divider{display:none!important}.auth-panel-left .auth-brand-panel{display:flex!important;flex-direction:row!important;align-items:center;gap:0;text-align:left;max-width:none;width:100%;justify-content:center}.auth-panel-left .auth-brand-logo{width:52px;height:52px;margin:0;flex-shrink:0}.auth-panel-left .auth-brand-logo img{width:34px;height:34px}.auth-panel-left .auth-brand-title{font-size:20px;margin-bottom:0;margin-left:.5rem;flex-shrink:1}.auth-panel-right:after{inset:-25% 0 auto;width:100%;height:25%;background:linear-gradient(180deg,transparent 0%,rgba(57,139,247,.02) 30%,rgba(57,139,247,.045) 50%,rgba(57,139,247,.02) 70%,transparent 100%);animation:authScanLineV 7s ease-in-out infinite;animation-delay:3.5s}.auth-panel-right--dev:after{background:linear-gradient(180deg,transparent 0%,rgba(209,50,111,.02) 30%,rgba(209,50,111,.045) 50%,rgba(209,50,111,.02) 70%,transparent 100%)}}@keyframes authScanLineV{0%{top:-25%}50%{top:120%}to{top:120%}}@media(max-width:480px){.auth-panel-left{padding:12px 16px}.auth-panel-left .auth-brand-logo{width:44px;height:44px}.auth-panel-left .auth-brand-logo img{width:28px;height:28px}.auth-panel-left .auth-brand-title{font-size:17px}.auth-form-wrapper>div{padding:20px 12px}.auth-card{padding:24px 18px 20px;border-radius:16px}.font-12{font-size:10px!important}}\n"] });
|
|
511
|
+
}
|
|
512
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: MdVerificarMfaComponent, decorators: [{
|
|
513
|
+
type: Component,
|
|
514
|
+
args: [{ selector: 'lib-md-verificar-mfa', template: "<div class=\"verificar-mfa\">\n <div class=\"auth-card-title mb-3\">{{ titulo() }}</div>\n\n <div class=\"d-flex align-items-center gap-3 mb-3\">\n <span class=\"verificar-mfa__icono\"><i class=\"fas fa-user-shield\"></i></span>\n <div>\n <div class=\"fw-semibold\">{{ challenge().coduser }}</div>\n @if (challenge().empresa) {\n <div class=\"verificar-mfa__muted\">{{ challenge().empresa }}</div>\n }\n </div>\n </div>\n\n @if (modo() == 'push') {\n @switch (estadoPush()) {\n @case ('enviando') {\n <div class=\"duo-push\">\n <span class=\"spinner-border spinner-border-sm text-primary\"></span>\n <div class=\"flex-grow-1\">Enviando notificaci\u00F3n a tu tel\u00E9fono\u2026</div>\n </div>\n }\n @case ('esperando') {\n <div class=\"duo-push duo-push--esperando\">\n <span class=\"duo-push__icono duo-push__icono--pulso\"><i class=\"fas fa-mobile-alt\"></i></span>\n <div class=\"flex-grow-1\">\n <div class=\"fw-semibold\">Revisa tu tel\u00E9fono</div>\n <div class=\"verificar-mfa__muted\">Aprueba la notificaci\u00F3n en TSI Autenticador para ingresar.</div>\n </div>\n </div>\n }\n @default {\n <div class=\"duo-push\">\n <span class=\"duo-push__icono\"><i class=\"fas fa-bell\"></i></span>\n <div class=\"flex-grow-1\">\n <div class=\"fw-semibold\">TSI Autenticador</div>\n <div class=\"verificar-mfa__muted\">Te enviaremos una notificaci\u00F3n para que la apruebes.</div>\n </div>\n </div>\n }\n }\n @if (pushError() && !isPushEnCurso()) {\n <div class=\"codigo-field__error\"><i class=\"fas fa-exclamation-circle\"></i> {{ pushError() }}</div>\n }\n\n <div class=\"verificar-mfa__opciones\">\n @if (tieneTotp()) {\n <button type=\"button\" class=\"verificar-mfa__link\" (click)=\"usarCodigo('totp')\">\n Usar c\u00F3digo de mi app de autenticaci\u00F3n\n </button>\n }\n <button type=\"button\" class=\"verificar-mfa__link verificar-mfa__link--secundario\"\n (click)=\"usarCodigo('respaldo')\">\n \u00BFNo tienes tu tel\u00E9fono? Usa un c\u00F3digo de respaldo\n </button>\n </div>\n } @else {\n <p class=\"verificar-mfa__muted mb-4\">\n @if (tipoCodigo() == 'totp') {\n {{ challenge().mensaje || campo().descri }}\n } @else {\n {{ campo().descri }}\n }\n </p>\n\n <div class=\"codigo-field\" [class.has-error]=\"codigoError()\">\n <span class=\"codigo-field__icon\"><i class=\"fas\" [class]=\"campo().icon\"></i></span>\n <input #inputCodigo id=\"mfa-codigo\" class=\"codigo-field__input\" type=\"text\"\n [placeholder]=\"campo().placeholder\" [value]=\"codigo()\" (input)=\"onCodigoInput($event)\"\n (keydown.enter)=\"verificar()\" [attr.inputmode]=\"campo().inputmode\" autocomplete=\"one-time-code\"\n autocorrect=\"off\" autocapitalize=\"characters\" spellcheck=\"false\" [disabled]=\"isEnviando()\">\n <label for=\"mfa-codigo\" class=\"codigo-field__label\">{{ campo().label }}</label>\n </div>\n @if (codigoError()) {\n <div class=\"codigo-field__error\"><i class=\"fas fa-exclamation-circle\"></i> {{ codigoError() }}</div>\n }\n\n <div class=\"verificar-mfa__opciones\">\n @if (tienePush()) {\n <button type=\"button\" class=\"verificar-mfa__link\" (click)=\"usarPush()\">\n <i class=\"fas fa-bell me-1\"></i>Mejor env\u00EDame una notificaci\u00F3n push\n </button>\n }\n @if (tieneTotp() && tipoCodigo() != 'totp') {\n <button type=\"button\" class=\"verificar-mfa__link\" (click)=\"usarCodigo('totp')\">\n Usar c\u00F3digo de mi app de autenticaci\u00F3n\n </button>\n }\n @if (tipoCodigo() != 'respaldo') {\n <button type=\"button\" class=\"verificar-mfa__link verificar-mfa__link--secundario\"\n (click)=\"usarCodigo('respaldo')\">\n \u00BFNo tienes tu tel\u00E9fono? Usa un c\u00F3digo de respaldo\n </button>\n }\n </div>\n }\n\n <div class=\"verificar-mfa__acciones\">\n @if (modo() == 'push') {\n <button type=\"button\" class=\"auth-btn\" [disabled]=\"isPushEnCurso()\" (click)=\"enviarPush()\">\n <i class=\"fas fa-paper-plane me-1\"></i>\n {{ isPushEnCurso() ? 'Esperando aprobaci\u00F3n\u2026' : 'Reenviar notificaci\u00F3n' }}\n </button>\n } @else {\n <button type=\"button\" class=\"auth-btn\" [disabled]=\"isEnviando()\" (click)=\"verificar()\">\n <i class=\"fas fa-check me-1\"></i>\n {{ isEnviando() ? 'Verificando\u2026' : 'Verificar' }}\n </button>\n }\n @if (showCancelar()) {\n <button type=\"button\" class=\"auth-btn auth-btn--outline\" (click)=\"cancelar()\">Cancelar</button>\n }\n </div>\n</div>\n", styles: [".verificar-mfa{color:var(--text-color)}.verificar-mfa__icono{display:inline-flex;flex-shrink:0;align-items:center;justify-content:center;width:44px;height:44px;border-radius:12px;color:var(--bs-primary);background:rgba(var(--bs-primary-rgb),.1);font-size:20px}.verificar-mfa__muted{font-size:13px;line-height:1.5;color:var(--bs-secondary-color)}.verificar-mfa__link:hover{text-decoration:underline}.verificar-mfa__link{padding:0;border:0;background:none;font-size:13px;font-weight:600;color:var(--bs-primary)}.codigo-field{position:relative}.codigo-field__icon{position:absolute;left:14px;top:50%;transform:translateY(-50%);z-index:2;font-size:15px;color:var(--placeholder-color);pointer-events:none;transition:color .2s}.codigo-field__input{width:100%;height:56px;padding:0 44px;border:1.5px solid var(--font-border-input);border-radius:10px;outline:none;background:var(--background-input);color:var(--color-input);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:22px;font-weight:600;letter-spacing:.45em;text-align:center;transition:border-color .2s,box-shadow .2s,background .2s}.codigo-field__input::placeholder{color:var(--placeholder-color);opacity:.45}.codigo-field__input:focus{border-color:var(--bs-primary);box-shadow:0 0 0 3.5px rgba(var(--bs-primary-rgb),.15);background:var(--background-focus-input)}.codigo-field__input:disabled{opacity:.7}.codigo-field__label{position:absolute;left:12px;top:0;transform:translateY(-50%);z-index:1;margin:0!important;padding:0 4px;font-size:11px!important;font-weight:500!important;line-height:1.2;color:var(--placeholder-color);background:var(--background-card);pointer-events:none;transition:color .15s ease}.codigo-field:focus-within .codigo-field__label,.codigo-field:focus-within .codigo-field__icon{color:var(--bs-primary)}.codigo-field.has-error .codigo-field__input{border-color:var(--bs-danger);box-shadow:0 0 0 3.5px rgba(var(--bs-danger-rgb),.12)}.codigo-field.has-error .codigo-field__icon,.codigo-field.has-error .codigo-field__label{color:var(--bs-danger)}.codigo-field__error{display:flex;align-items:center;gap:6px;margin-top:8px;font-size:13px;font-weight:500;color:var(--bs-danger)}.duo-push{display:flex;align-items:center;gap:12px;padding:14px;border:1.5px solid var(--font-border-input);border-radius:10px;background:var(--background-input);color:var(--text-color);font-size:14px}.duo-push--esperando{border-color:rgba(var(--bs-primary-rgb),.45);background:rgba(var(--bs-primary-rgb),.06)}.duo-push__icono{display:inline-flex;flex-shrink:0;align-items:center;justify-content:center;width:40px;height:40px;border-radius:50%;color:var(--bs-primary);background:rgba(var(--bs-primary-rgb),.1);font-size:18px}.duo-push__icono--pulso{animation:duo-pulso 1.4s ease-in-out infinite}@keyframes duo-pulso{0%,to{box-shadow:0 0 rgba(var(--bs-primary-rgb),.35)}50%{box-shadow:0 0 0 8px rgba(var(--bs-primary-rgb),0)}}@media(prefers-reduced-motion:reduce){.duo-push__icono--pulso{animation:none}}.verificar-mfa__opciones{display:flex;flex-direction:column;align-items:flex-start;gap:8px;margin-top:16px}.verificar-mfa__link--secundario{font-weight:500;color:var(--bs-secondary-color)}.verificar-mfa__acciones{margin-top:24px}\n", "@charset \"UTF-8\";.red_contrasena,.blue_contrasena{position:relative;display:inline-block;font-size:13px;text-decoration:none;padding-bottom:2px;transition:color .3s ease;cursor:pointer}.red_contrasena:after,.blue_contrasena:after{content:\"\";position:absolute;bottom:0;left:50%;width:0;height:1px;background-color:currentColor;transition:all .3s ease;transform:translate(-50%)}.red_contrasena:hover:after,.blue_contrasena:hover:after{width:60%}.red_contrasena{color:#d1326f}.red_contrasena:hover{color:#a82859}.blue_contrasena{color:#398bf7}.blue_contrasena:hover{color:#1e5fc4}.auth-wrapper-login{position:fixed;inset:0;display:grid;grid-template-columns:1.15fr .85fr;overflow:hidden;background:#060d1f}.auth-panel-left{position:relative;overflow:hidden;background:linear-gradient(145deg,#040a18,#0b1a3d 55%,#040e22);display:flex;align-items:center;justify-content:center;padding:48px 40px}.auth-panel-left:before{content:\"\";position:absolute;inset:0;background-image:radial-gradient(circle,rgba(255,255,255,.055) 1px,transparent 1px);background-size:26px 26px;z-index:1;pointer-events:none}.auth-panel-left:after{content:\"\";position:absolute;top:0;left:-120%;width:60%;height:100%;background:linear-gradient(90deg,transparent,rgba(57,139,247,.04),transparent);animation:panelSweep 7s ease-in-out infinite;z-index:1;pointer-events:none}.auth-blob{position:absolute;border-radius:50%;filter:blur(72px);z-index:0;pointer-events:none}.auth-blob-1{width:340px;height:340px;background:radial-gradient(circle,rgba(57,139,247,.45) 0%,transparent 70%);top:-90px;right:-70px;animation:blobDrift 11s ease-in-out infinite}.auth-blob-2{width:240px;height:240px;background:radial-gradient(circle,rgba(124,58,237,.4) 0%,transparent 70%);bottom:60px;left:-50px;animation:blobDrift 14s ease-in-out infinite reverse}.auth-blob-3{width:180px;height:180px;background:radial-gradient(circle,rgba(14,165,233,.35) 0%,transparent 70%);bottom:-50px;right:40px;animation:blobDrift 9s ease-in-out infinite;animation-delay:-4s}.auth-blob-4{width:120px;height:120px;background:radial-gradient(circle,rgba(209,50,111,.25) 0%,transparent 70%);top:50%;left:50%;transform:translate(-50%,-50%);animation:blobDrift 16s ease-in-out infinite;animation-delay:-8s}@keyframes blobDrift{0%,to{transform:translate(0) scale(1)}33%{transform:translate(14px,-20px) scale(1.05)}66%{transform:translate(-10px,12px) scale(.96)}}@keyframes panelSweep{0%{left:-120%}50%{left:160%}to{left:160%}}.auth-brand-panel{position:relative;z-index:2;text-align:center;color:#fff;max-width:340px}.auth-brand-logo{width:100px;height:100px;border-radius:50%;background:#ffffff0d;border:1px solid rgba(255,255,255,.1);display:flex;align-items:center;justify-content:center;margin:0 auto 28px;box-shadow:0 0 0 14px #398bf70f,0 0 50px #398bf733;backdrop-filter:blur(8px)}.auth-brand-logo img{width:64px;height:64px;object-fit:contain;filter:brightness(1.05) drop-shadow(0 0 8px rgba(57,139,247,.4))}.auth-brand-title{font-size:30px;font-weight:700;letter-spacing:-.5px;margin-bottom:10px;background:linear-gradient(135deg,#fff 20%,#93c5fd 80%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}.auth-brand-subtitle{font-size:14px;color:#ffffff73;line-height:1.65;margin-bottom:40px;letter-spacing:.2px}.auth-brand-features{display:flex;flex-direction:column;gap:14px;text-align:left}.auth-brand-feature{display:flex;align-items:center;gap:12px;font-size:13px;color:#fff9}.auth-brand-feature .feat-dot{flex-shrink:0;width:7px;height:7px;border-radius:50%;background:#398bf7;box-shadow:0 0 10px #398bf7b3}.auth-brand-divider{width:60px;height:2px;background:linear-gradient(90deg,transparent,#398bf7,transparent);margin:28px auto 32px;border-radius:2px}.auth-panel-left--dev{background:linear-gradient(145deg,#18040b,#3d0b1d 55%,#220409)}.auth-panel-left--dev:after{background:linear-gradient(90deg,transparent,rgba(209,50,111,.05),transparent)}.auth-panel-left--dev .auth-blob-1{background:radial-gradient(circle,rgba(220,38,38,.52) 0%,transparent 70%)}.auth-panel-left--dev .auth-blob-2{background:radial-gradient(circle,rgba(219,39,119,.44) 0%,transparent 70%)}.auth-panel-left--dev .auth-blob-3{background:radial-gradient(circle,rgba(239,68,68,.38) 0%,transparent 70%)}.auth-panel-left--dev .auth-blob-4{background:radial-gradient(circle,rgba(249,115,22,.28) 0%,transparent 70%)}.auth-panel-left--dev .auth-brand-logo{box-shadow:0 0 0 14px #d1326f12,0 0 50px #d1326f38}.auth-panel-left--dev .auth-brand-logo img{filter:brightness(1.05) drop-shadow(0 0 8px rgba(209,50,111,.45))}.auth-panel-left--dev .auth-brand-title{background:linear-gradient(135deg,#fff 20%,#fca5a5 80%);-webkit-background-clip:text;background-clip:text}.auth-panel-left--dev .auth-brand-divider{background:linear-gradient(90deg,transparent,rgb(209,50,111),transparent)}.auth-panel-left--dev .feat-dot{background:#d1326f;box-shadow:0 0 10px #d1326fb8}.auth-panel-right{position:relative;overflow:hidden;background:var(--background-login)}.auth-panel-right:before{content:\"\";position:absolute;inset:0;background-image:repeating-linear-gradient(-55deg,transparent 0px,transparent 22px,rgba(57,139,247,.045) 22px,rgba(57,139,247,.045) 23px);animation:authLinesMove 10s linear infinite;pointer-events:none;z-index:0}.auth-panel-right:after{content:\"\";position:absolute;top:0;bottom:0;left:-25%;width:25%;background:linear-gradient(90deg,transparent 0%,rgba(57,139,247,.02) 30%,rgba(57,139,247,.045) 50%,rgba(57,139,247,.02) 70%,transparent 100%);animation:authScanLine 7s ease-in-out infinite;animation-delay:3.5s;pointer-events:none;z-index:0}@keyframes authLinesMove{0%{transform:translate(0)}to{transform:translate(46px,46px)}}@keyframes authScanLine{0%{left:-25%}50%{left:120%}to{left:120%}}.auth-panel-bg{position:absolute;inset:0;pointer-events:none;z-index:0;overflow:hidden}.auth-deco{position:absolute;border-radius:50%;pointer-events:none;filter:blur(70px)}.auth-deco-tl{width:300px;height:300px;top:0;left:-120px;transform:translateY(-40%);background:radial-gradient(circle,rgba(57,139,247,.12) 0%,transparent 70%);animation:authOrbPulse 6s ease-in-out infinite}.auth-deco-br{width:340px;height:340px;bottom:0;right:-120px;transform:translateY(40%);background:radial-gradient(circle,rgba(124,58,237,.1) 0%,transparent 70%);animation:authOrbPulse 8s ease-in-out infinite;animation-delay:-4s}@keyframes authOrbPulse{0%,to{opacity:.7}50%{opacity:1}}.auth-form-wrapper{position:absolute;inset:0;overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;align-items:center;z-index:1}.auth-form-wrapper>div{width:100%;max-width:420px;margin:auto;padding:36px 16px;box-sizing:border-box}.auth-panel-right--dev:before{background-image:repeating-linear-gradient(-55deg,transparent 0px,transparent 22px,rgba(209,50,111,.05) 22px,rgba(209,50,111,.05) 23px)}.auth-panel-right--dev:after{background:linear-gradient(90deg,transparent 0%,rgba(209,50,111,.02) 30%,rgba(209,50,111,.045) 50%,rgba(209,50,111,.02) 70%,transparent 100%)}.auth-panel-right--dev .auth-deco-tl{background:radial-gradient(circle,rgba(209,50,111,.12) 0%,transparent 70%)}.auth-panel-right--dev .auth-deco-br{background:radial-gradient(circle,rgba(239,68,68,.1) 0%,transparent 70%)}.auth-test-badge{display:inline-flex;align-items:center;gap:7px;background:#d1326f14;border:1px solid rgba(209,50,111,.25);color:#d1326f;font-size:10.5px;font-weight:700;padding:5px 12px;border-radius:20px;margin-bottom:18px;letter-spacing:.8px}.auth-test-badge .badge-dot{width:6px;height:6px;border-radius:50%;background:#d1326f;animation:badgePulse 1.6s ease-in-out infinite;flex-shrink:0}@keyframes badgePulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.45;transform:scale(.75)}}.auth-card{background:var(--background-card);border-radius:20px;padding:36px 32px 28px;box-shadow:0 4px 28px #00000014;border:1px solid var(--border-color-modal)}.auth-card-title{font-size:22px;font-weight:700;color:var(--text-color);margin-bottom:4px;letter-spacing:-.3px}.auth-card-subtitle{font-size:13px;color:var(--placeholder-color);margin-bottom:26px}.auth-field{position:relative;margin-bottom:1rem}.auth-field .auth-field-icon{position:absolute;left:13px;top:50%;transform:translateY(-50%);color:var(--placeholder-color);font-size:13px;z-index:2;pointer-events:none;transition:color .2s}.auth-field .auth-input{width:100%;padding:15px 40px 15px 37px;background:var(--background-input);border:1.5px solid var(--font-border-input);border-radius:10px;font-size:14px;color:var(--color-input);outline:none;transition:border-color .2s,box-shadow .2s,background .2s}.auth-field .auth-input::placeholder{color:transparent}.auth-field .auth-input:focus{border-color:#398bf7;box-shadow:0 0 0 3.5px #398bf721;background:var(--background-focus-input)}.auth-field .auth-input:focus~.auth-label{top:0;font-size:11px!important;color:#398bf7!important;background:var(--background-card);padding:0 4px;transform:translateY(-50%)}.auth-field .auth-input:focus~.auth-field-icon{color:#398bf7}.auth-field .auth-input:not(:placeholder-shown)~.auth-label{top:0;font-size:11px!important;background:var(--background-card);padding:0 4px;transform:translateY(-50%)}.auth-field .auth-label{position:absolute;left:35px;top:50%;transform:translateY(-50%);color:var(--placeholder-color)!important;font-size:13px!important;font-weight:400!important;pointer-events:none;transition:top .15s ease,font-size .15s ease,color .15s ease,padding .15s ease,background .15s ease;background:transparent;z-index:1;text-align:left!important}.auth-field .auth-toggle-pw{position:absolute;right:10px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--placeholder-color);cursor:pointer;padding:4px 6px;font-size:13px;z-index:2;line-height:1;transition:color .2s}.auth-field .auth-toggle-pw:hover{color:#398bf7}.auth-field.has-error .auth-input{border-color:#dc3545;box-shadow:none}.auth-field.has-error .auth-field-icon{color:#dc3545}.auth-select{width:100%;padding:13px 14px;background:var(--background-input);border:1.5px solid var(--font-border-input);border-radius:10px;font-size:14px;color:var(--color-input);outline:none;transition:border-color .2s,box-shadow .2s;margin-bottom:1rem;cursor:pointer}.auth-select:focus{border-color:#398bf7;box-shadow:0 0 0 3.5px #398bf721}.auth-btn{width:100%;padding:13px;border:none;border-radius:10px;font-size:14px;font-weight:600;cursor:pointer;transition:transform .15s ease,box-shadow .2s ease,opacity .2s;background:linear-gradient(135deg,#398bf7,#1e5fc4);color:#fff;letter-spacing:.3px;margin-bottom:10px;display:block}.auth-btn:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 5px 18px #398bf761}.auth-btn:active:not(:disabled){transform:translateY(0)}.auth-btn:disabled{opacity:.55;cursor:not-allowed}.auth-btn.auth-btn--red{background:linear-gradient(135deg,#d1326f,#a82859)}.auth-btn.auth-btn--red:hover:not(:disabled){box-shadow:0 5px 18px #d1326f61}.auth-btn.auth-btn--outline{background:transparent;border:1.5px solid var(--font-border-input);color:var(--text-color)}.auth-btn.auth-btn--outline:hover:not(:disabled){background:var(--background-btn-light-hover);box-shadow:none;transform:none}.auth-links{display:flex;flex-direction:column;align-items:center;gap:10px;margin-top:16px;padding-top:16px;border-top:1px solid var(--border-color-modal)}.auth-version{text-align:right;margin-top:14px;padding-top:12px;border-top:1px solid var(--border-color-modal)}.auth-version span{font-size:11px;color:var(--placeholder-color)}.auth-error{font-size:11.5px;color:#dc3545;margin:-6px 0 10px 2px;padding:0}.auth-hint{display:flex;align-items:flex-start;gap:6px;font-size:11.5px;color:var(--placeholder-color);margin:-6px 0 14px 2px;padding:0;line-height:1.35}.auth-hint i{margin-top:2px;flex-shrink:0}.auth-validation-list{margin:-4px 0 12px;padding:0;list-style:none}.auth-validation-list li{font-size:11.5px;color:#dc3545;padding:2px 0}.auth-validation-list li:before{content:\"\\2715 \";font-size:10px}.auth-desc{font-size:13px;color:var(--placeholder-color);margin-bottom:20px;line-height:1.65}.auth-section-title{font-size:15px;font-weight:600;color:var(--text-color);margin-bottom:20px}.font-12{font-size:12px}.form-control:focus{border-color:#0199ff9a!important;box-shadow:0 0 5px .2px #65befa44!important}@media(max-width:900px){.auth-wrapper-login{grid-template-columns:1fr;grid-template-rows:auto 1fr;overflow-y:auto;overflow-x:hidden}.auth-panel-left{padding:14px 24px;justify-content:center}.auth-panel-left .auth-brand-subtitle,.auth-panel-left .auth-brand-features,.auth-panel-left .auth-brand-divider{display:none!important}.auth-panel-left .auth-brand-panel{display:flex!important;flex-direction:row!important;align-items:center;gap:0;text-align:left;max-width:none;width:100%;justify-content:center}.auth-panel-left .auth-brand-logo{width:52px;height:52px;margin:0;flex-shrink:0}.auth-panel-left .auth-brand-logo img{width:34px;height:34px}.auth-panel-left .auth-brand-title{font-size:20px;margin-bottom:0;margin-left:.5rem;flex-shrink:1}.auth-panel-right:after{inset:-25% 0 auto;width:100%;height:25%;background:linear-gradient(180deg,transparent 0%,rgba(57,139,247,.02) 30%,rgba(57,139,247,.045) 50%,rgba(57,139,247,.02) 70%,transparent 100%);animation:authScanLineV 7s ease-in-out infinite;animation-delay:3.5s}.auth-panel-right--dev:after{background:linear-gradient(180deg,transparent 0%,rgba(209,50,111,.02) 30%,rgba(209,50,111,.045) 50%,rgba(209,50,111,.02) 70%,transparent 100%)}}@keyframes authScanLineV{0%{top:-25%}50%{top:120%}to{top:120%}}@media(max-width:480px){.auth-panel-left{padding:12px 16px}.auth-panel-left .auth-brand-logo{width:44px;height:44px}.auth-panel-left .auth-brand-logo img{width:28px;height:28px}.auth-panel-left .auth-brand-title{font-size:17px}.auth-form-wrapper>div{padding:20px 12px}.auth-card{padding:24px 18px 20px;border-radius:16px}.font-12{font-size:10px!important}}\n"] }]
|
|
515
|
+
}], ctorParameters: () => [] });
|
|
516
|
+
|
|
322
517
|
/*
|
|
323
518
|
* Public API Surface of login-tsi
|
|
324
519
|
*/
|
|
@@ -327,5 +522,5 @@ class AuthSender {
|
|
|
327
522
|
* Generated bundle index. Do not edit.
|
|
328
523
|
*/
|
|
329
524
|
|
|
330
|
-
export { AuthComponent, AuthSender, ExpiredPasswordComponent, PwaFloatingComponent, PwaInstallService, RecoverPasswordComponent, RefreshFloatingComponent, SelectBranchComponent };
|
|
525
|
+
export { AuthComponent, AuthSender, ExpiredPasswordComponent, MFA_API, MdVerificarMfaComponent, PwaFloatingComponent, PwaInstallService, RecoverPasswordComponent, RefreshFloatingComponent, SelectBranchComponent, isMfaChallenge, isPushPendiente, provideMfaApi };
|
|
331
526
|
//# sourceMappingURL=login-tsi.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login-tsi.mjs","sources":["../../../projects/login-tsi/src/lib/utils/animations.ts","../../../projects/login-tsi/src/lib/pwa-install.service.ts","../../../projects/login-tsi/src/lib/components/pwa-floating/pwa-floating.component.ts","../../../projects/login-tsi/src/lib/components/pwa-floating/pwa-floating.component.html","../../../projects/login-tsi/src/lib/components/refresh-floating/refresh-floating.component.ts","../../../projects/login-tsi/src/lib/components/refresh-floating/refresh-floating.component.html","../../../projects/login-tsi/src/lib/components/auth/auth.component.ts","../../../projects/login-tsi/src/lib/components/auth/auth.component.html","../../../projects/login-tsi/src/lib/components/expired-password/expired-password.component.ts","../../../projects/login-tsi/src/lib/components/expired-password/expired-password.component.html","../../../projects/login-tsi/src/lib/components/recover-password/recover-password.component.ts","../../../projects/login-tsi/src/lib/components/recover-password/recover-password.component.html","../../../projects/login-tsi/src/lib/components/select-branch/select-branch.component.ts","../../../projects/login-tsi/src/lib/components/select-branch/select-branch.component.html","../../../projects/login-tsi/src/lib/models/auth-sender.ts","../../../projects/login-tsi/src/public-api.ts","../../../projects/login-tsi/src/login-tsi.ts"],"sourcesContent":["import { animate, style, transition, trigger } from \"@angular/animations\";\r\n\r\nexport const fadeInOut = trigger('fadeInOut', [\r\n transition(':enter', [\r\n style({ opacity: 0, transform: 'translateY(-5px)' }),\r\n animate('200ms ease-out', style({ opacity: 1, transform: 'translateY(0)' })),\r\n ]),\r\n transition(':leave', [\r\n animate('200ms ease-in', style({ opacity: 0, transform: 'translateY(-5px)' })),\r\n ]),\r\n ])","import { Injectable, signal } from '@angular/core';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class PwaInstallService {\r\n\r\n readonly isAndroid = /Android/i.test(navigator.userAgent)\r\n readonly isIOS = /iPad|iPhone|iPod/i.test(navigator.userAgent)\r\n readonly isSafariMac = /^((?!Chrome|Android).)*Safari/i.test(navigator.userAgent) && /Mac/i.test(navigator.platform)\r\n readonly isChrome = /Chrome|Chromium|Edg/i.test(navigator.userAgent) && !/Android/i.test(navigator.userAgent)\r\n\r\n readonly showButton = signal<boolean>(\r\n !window.matchMedia('(display-mode: standalone)').matches\r\n )\r\n readonly showGuide = signal<boolean>(false)\r\n\r\n private get deferredPrompt(): any { return (window as any).__pwaPrompt ?? null }\r\n\r\n get canAutoInstall(): boolean { return !!this.deferredPrompt }\r\n\r\n async tryInstall(): Promise<void> {\r\n const prompt = this.deferredPrompt\r\n if (!prompt) return\r\n prompt.prompt()\r\n const { outcome } = await prompt.userChoice\r\n if (outcome === 'accepted') this.showButton.set(false)\r\n else (window as any).__pwaPrompt = null\r\n }\r\n\r\n toggleGuide() { this.showGuide.update(v => !v) }\r\n\r\n markAsAdded() {\r\n this.showGuide.set(false)\r\n this.showButton.set(false)\r\n }\r\n}\r\n","import { Component, inject, input, output } from '@angular/core';\r\nimport { PwaInstallService } from '../../pwa-install.service';\r\n\r\n@Component({\r\n selector: 'app-pwa-floating',\r\n templateUrl: './pwa-floating.component.html',\r\n styleUrl: './pwa-floating.component.scss'\r\n})\r\n\r\nexport class PwaFloatingComponent {\r\n\r\n readonly pwa = inject(PwaInstallService)\r\n\r\n appName = input<string>('ERP TSI')\r\n logo = input<string>('assets/images/logo-tsi-tres.png')\r\n chipLabel = input<string>('Instalar app')\r\n\r\n beforeInstall = output<void>()\r\n guideClosed = output<void>()\r\n\r\n onChipClick() {\r\n if (!this.pwa.showGuide()) {\r\n this.beforeInstall.emit()\r\n } else {\r\n this.guideClosed.emit()\r\n }\r\n this.pwa.toggleGuide()\r\n }\r\n\r\n onCloseGuide() {\r\n this.guideClosed.emit()\r\n this.pwa.toggleGuide()\r\n }\r\n\r\n onMarkAsAdded() {\r\n this.guideClosed.emit()\r\n this.pwa.markAsAdded()\r\n }\r\n\r\n}\r\n","@if (pwa.showButton()) {\r\n<div class=\"pwa-wrap\">\r\n\r\n @if (pwa.showGuide()) {\r\n <div class=\"pwa-guide\">\r\n <button class=\"pwa-guide__close\" (click)=\"onCloseGuide()\">\r\n <i class=\"fas fa-xmark\"></i>\r\n </button>\r\n\r\n <div class=\"pwa-guide__header\">\r\n <img [src]=\"logo()\" alt=\"\" class=\"pwa-guide__logo\">\r\n <div>\r\n <p class=\"pwa-guide__title\">Instalar {{ appName() }}</p>\r\n <p class=\"pwa-guide__sub\">Úsalo como una app desde tu dispositivo</p>\r\n </div>\r\n </div>\r\n\r\n @if (!pwa.canAutoInstall) {\r\n <ol class=\"pwa-guide__steps\">\r\n @if (pwa.isIOS) {\r\n <li>Toca el botón <span class=\"pwa-guide__badge\"><i class=\"fas fa-arrow-up-from-bracket\"></i></span> en la barra inferior del navegador</li>\r\n <li>Desplázate y selecciona <strong>\"En la pantalla de inicio\"</strong></li>\r\n <li>Toca <strong>\"Añadir\"</strong> en la esquina superior derecha</li>\r\n } @else if (pwa.isAndroid) {\r\n <li>Toca el menú <span class=\"pwa-guide__badge\"><i class=\"fas fa-ellipsis-vertical\"></i></span> en la esquina superior derecha</li>\r\n <li>Selecciona <strong>\"Instalar aplicación\"</strong> o <strong>\"Añadir a pantalla de inicio\"</strong></li>\r\n <li>Toca <strong>\"Instalar\"</strong> para confirmar</li>\r\n } @else if (pwa.isSafariMac) {\r\n <li>Abre el menú <strong>\"Archivo\"</strong> en la barra superior del Mac</li>\r\n <li>Selecciona <strong>\"Añadir al Dock...\"</strong></li>\r\n <li>Haz clic en <strong>\"Añadir\"</strong> para confirmar</li>\r\n } @else if (pwa.isChrome) {\r\n <li>Busca el ícono <span class=\"pwa-guide__badge\"><i class=\"fas fa-display\"></i></span> al final de la barra de direcciones</li>\r\n <li>Haz clic en él y selecciona <strong>\"Instalar\"</strong></li>\r\n <li>Confirma en el diálogo que aparece</li>\r\n } @else {\r\n <li>Abre el menú <span class=\"pwa-guide__badge\"><i class=\"fas fa-ellipsis-vertical\"></i></span> de tu navegador</li>\r\n <li>Busca <strong>\"Instalar aplicación\"</strong> o <strong>\"Añadir a pantalla de inicio\"</strong></li>\r\n <li>Confirma para instalar</li>\r\n }\r\n </ol>\r\n }\r\n\r\n @if (pwa.canAutoInstall) {\r\n <button class=\"pwa-guide__install\" (click)=\"pwa.tryInstall()\">\r\n <i class=\"fas fa-download\"></i> Instalar ahora\r\n </button>\r\n }\r\n <button class=\"pwa-guide__done\" (click)=\"onMarkAsAdded()\">\r\n <i class=\"fas fa-check\"></i> Ya lo instalé\r\n </button>\r\n </div>\r\n }\r\n\r\n <button class=\"pwa-chip\" (click)=\"onChipClick()\">\r\n <img [src]=\"logo()\" alt=\"\" class=\"pwa-chip__logo\">\r\n <span>{{ chipLabel() }}</span>\r\n </button>\r\n\r\n</div>\r\n}\r\n","import { Component, signal } from '@angular/core';\r\n\r\n@Component({\r\n selector: 'app-refresh-floating',\r\n templateUrl: './refresh-floating.component.html',\r\n styleUrl: './refresh-floating.component.scss'\r\n})\r\n\r\nexport class RefreshFloatingComponent {\r\n\r\n showGuide = signal<boolean>(false)\r\n\r\n toggleGuide() {\r\n this.showGuide.update(v => !v)\r\n }\r\n\r\n actualizar() {\r\n window.location.reload()\r\n }\r\n\r\n async actualizarTotal() {\r\n if ('serviceWorker' in navigator) {\r\n const registrations = await navigator.serviceWorker.getRegistrations()\r\n await Promise.all(registrations.map(r => r.unregister()))\r\n }\r\n if ('caches' in window) {\r\n const names = await caches.keys()\r\n await Promise.all(names.map(name => caches.delete(name)))\r\n }\r\n window.location.href = window.location.pathname + '?_r=' + Date.now()\r\n }\r\n}\r\n","<div class=\"refresh-wrap\">\r\n\r\n @if (showGuide()) {\r\n <div class=\"refresh-guide\">\r\n <button class=\"refresh-guide__close\" (click)=\"toggleGuide()\">\r\n <i class=\"fas fa-xmark\"></i>\r\n </button>\r\n\r\n <p class=\"refresh-guide__title\">Actualizar aplicación</p>\r\n\r\n <button class=\"refresh-guide__option\" (click)=\"actualizar()\">\r\n <i class=\"fas fa-rotate\"></i> Actualizar\r\n </button>\r\n\r\n <button class=\"refresh-guide__option refresh-guide__option--force\" (click)=\"actualizarTotal()\">\r\n <i class=\"fas fa-rotate-right\"></i> Forzar actualización\r\n </button>\r\n </div>\r\n }\r\n\r\n <button class=\"refresh-chip\" (click)=\"toggleGuide()\" title=\"Actualizar\">\r\n <i class=\"fas fa-rotate\"></i>\r\n </button>\r\n\r\n</div>\r\n","import { NgClass } from '@angular/common';\r\nimport { Component, input, output, signal } from '@angular/core';\r\nimport { FormGroup, ReactiveFormsModule } from '@angular/forms';\r\nimport { AuthSender } from '../../models/auth-sender';\r\nimport { fadeInOut } from '../../utils/animations';\r\nimport { LoginEvent } from '../../models/login-event';\r\nimport { PwaFloatingComponent } from '../pwa-floating/pwa-floating.component';\r\nimport { RefreshFloatingComponent } from '../refresh-floating/refresh-floating.component';\r\n\r\n@Component({\r\n selector: 'lib-auth-tsi',\r\n imports: [NgClass, ReactiveFormsModule, PwaFloatingComponent, RefreshFloatingComponent],\r\n templateUrl: './auth.component.html',\r\n styleUrls: ['./auth.component.scss', '../auth.scss'],\r\n animations: [fadeInOut]\r\n})\r\nexport class AuthComponent {\r\n\r\n production = input<boolean>(true)\r\n module = input<string>('ERP') // DEFECTO ERP\r\n versionApp = input<string>('1.0.0') // DEFECTO 1.0.0\r\n product = input<string>() // DEFECTO NULL - ERP\r\n authForm = input.required<FormGroup>();\r\n\r\n aboutList = input<string[]>([\r\n 'Gestión de compras y logística',\r\n 'Control financiero avanzado',\r\n 'Reportes y análisis en tiempo real',\r\n 'Integración con inteligencia artificial'\r\n ])\r\n\r\n /** Muestra el flotante de \"instalar app\" (app-pwa-floating). Por defecto siempre visible. */\r\n showFloatingApp = input<boolean>(true)\r\n /** Muestra el flotante de \"actualización disponible\" (app-refresh-floating). Por defecto siempre visible. */\r\n showFloatingUpdate = input<boolean>(true)\r\n\r\n loginEvent = output<LoginEvent>()\r\n /** Se dispara antes de instalar la PWA — el RUC/usuario ya están en authForm(), el consumidor decide qué guardar. */\r\n beforeInstall = output<void>()\r\n\r\n showPassword = signal<boolean>(false)\r\n\r\n onBeforeInstall = () => this.beforeInstall.emit()\r\n\r\n recover = () => this.loginEvent.emit({type: \"RECOVER\"})\r\n forget = () => this.loginEvent.emit({type: \"FORGET\"})\r\n \r\n togglePassword = () => this.showPassword.set(!this.showPassword())\r\n\r\n login = () => {\r\n if (!this.validacionInit()) return\r\n const dataForm = this.authForm().value\r\n const data: AuthSender = {\r\n ruc: dataForm.ruc,\r\n coduser: dataForm.nomuser,\r\n clave: btoa(dataForm.clave),\r\n producto: this.product()\r\n }\r\n this.loginEvent.emit({type: \"LOGIN\", data})\r\n }\r\n\r\n // authForm = this.formBuilder.group({\r\n // ruc: ['', Validators.required],\r\n // nomuser: ['', Validators.required],\r\n // clave: ['', Validators.required],\r\n // })\r\n\r\n validacion(value: string) {\r\n const authForm = this.authForm()\r\n if (authForm.get(value).touched && authForm.get(value).errors) {\r\n return true\r\n }\r\n return false\r\n }\r\n\r\n validacionInit() {\r\n const dataForm = this.authForm().value\r\n const { ruc, nomuser, clave } = dataForm\r\n\r\n if (!ruc) return this.returnError('Debe ingresar un N° de RUC')\r\n if (!nomuser) return this.returnError('Debe ingresar un usuario')\r\n if (!clave) return this.returnError('Debe ingresar una contraseña')\r\n return true\r\n }\r\n \r\n returnError = (message:string) => {\r\n this.loginEvent.emit({type: \"ERROR\", message})\r\n return false\r\n }\r\n}\r\n","<div class=\"auth-wrapper-login\">\r\n @let produccion = production();\r\n <div class=\"auth-panel-left\" [class.auth-panel-left--dev]=\"!produccion\">\r\n <span class=\"auth-blob auth-blob-1\"></span>\r\n <span class=\"auth-blob auth-blob-2\"></span>\r\n <span class=\"auth-blob auth-blob-3\"></span>\r\n <span class=\"auth-blob auth-blob-4\"></span>\r\n\r\n <div class=\"auth-brand-panel\">\r\n <div class=\"auth-brand-logo\">\r\n <img src=\"assets/images/logo-tsi-tres.png\" alt=\"TSI\" />\r\n </div>\r\n <h1 class=\"auth-brand-title\">{{module()}}</h1>\r\n <p class=\"auth-brand-subtitle\">Plataforma integrada de gestión<br>empresarial</p>\r\n\r\n <div class=\"auth-brand-divider\"></div>\r\n\r\n <div class=\"auth-brand-features\">\r\n @for (item of aboutList(); track $index) {\r\n <div class=\"auth-brand-feature\">\r\n <span class=\"feat-dot\"></span> {{item}}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"auth-panel-right\" [class.auth-panel-right--dev]=\"!produccion\">\r\n <div class=\"auth-panel-bg\">\r\n <span class=\"auth-deco auth-deco-tl\"></span>\r\n <span class=\"auth-deco auth-deco-br\"></span>\r\n </div>\r\n\r\n <div class=\"auth-form-wrapper\">\r\n <div>\r\n @if (!produccion) {\r\n <div>\r\n <span class=\"auth-test-badge\">\r\n <span class=\"badge-dot\"></span> ENTORNO DE PRUEBAS\r\n </span>\r\n </div>\r\n }\r\n\r\n <div class=\"auth-card\">\r\n <h2 class=\"auth-card-title\">Bienvenido de vuelta</h2>\r\n <p class=\"auth-card-subtitle\">Ingresa tus credenciales para continuar</p>\r\n\r\n <form [formGroup]=\"authForm()\" id=\"loginform\">\r\n\r\n <p class=\"auth-hint\">\r\n <i class=\"fas fa-circle-info\"></i>\r\n Si piensas instalar la app, te recomendamos completar el RUC y Usuario antes, estos quedarán guardados y siempre aparecerán completos al abrirla.\r\n </p>\r\n\r\n <div class=\"auth-field\" [class.has-error]=\"validacion('ruc')\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-building\"></i></span>\r\n <input type=\"text\" formControlName=\"ruc\" class=\"auth-input\" placeholder=\" \" maxlength=\"11\"\r\n id=\"f-ruc\" autocomplete=\"off\">\r\n <label for=\"f-ruc\" class=\"auth-label\">RUC</label>\r\n </div>\r\n @if (validacion('ruc')) {\r\n <p class=\"auth-error\" @fadeInOut>Ingresar RUC</p>\r\n }\r\n\r\n <div class=\"auth-field\" [class.has-error]=\"validacion('nomuser')\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-user\"></i></span>\r\n <input type=\"text\" formControlName=\"nomuser\" class=\"auth-input\" placeholder=\" \" id=\"f-user\"\r\n autocomplete=\"off\">\r\n <label for=\"f-user\" class=\"auth-label\">Usuario</label>\r\n </div>\r\n @if (validacion('nomuser')) {\r\n <p class=\"auth-error\" @fadeInOut>Ingresar usuario</p>\r\n }\r\n\r\n <div class=\"auth-field\" [class.has-error]=\"validacion('clave')\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-lock\"></i></span>\r\n <input [type]=\"showPassword() ? 'text' : 'password'\" formControlName=\"clave\"\r\n class=\"auth-input\" placeholder=\" \" id=\"f-clave\" autocomplete=\"off\" autocorrect=\"off\"\r\n autocapitalize=\"off\" spellcheck=\"false\">\r\n <label for=\"f-clave\" class=\"auth-label\">Contraseña</label>\r\n <button type=\"button\" class=\"auth-toggle-pw\" (click)=\"togglePassword()\">\r\n <i [class]=\"showPassword() ? 'fas fa-eye' : 'fas fa-eye-slash'\"></i>\r\n </button>\r\n </div>\r\n @if (validacion('clave')) {\r\n <p class=\"auth-error\" @fadeInOut>Ingresar clave</p>\r\n }\r\n\r\n <button class=\"auth-btn mt-2\" [class.auth-btn--red]=\"!produccion\" (click)=\"login()\">\r\n Ingresar\r\n </button>\r\n\r\n <div class=\"auth-links\">\r\n <a [ngClass]=\"produccion ? 'blue_contrasena' : 'red_contrasena'\"\r\n (click)=\"recover()\">¿Olvidaste tu contraseña?</a>\r\n <a [ngClass]=\"produccion ? 'blue_contrasena' : 'red_contrasena'\"\r\n (click)=\"forget()\">¿Contraseña vencida?</a>\r\n </div>\r\n\r\n </form>\r\n\r\n <div class=\"auth-version\">\r\n <span>v{{versionApp()}}</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n@if (showFloatingApp()) {\r\n<app-pwa-floating [appName]=\"module()\" (beforeInstall)=\"onBeforeInstall()\" />\r\n}\r\n@if (showFloatingUpdate()) {\r\n<app-refresh-floating />\r\n}","import { Component, inject, input, output, signal } from '@angular/core';\r\nimport { AbstractControl, FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';\r\nimport { AuthSender } from '../../models/auth-sender';\r\nimport { fadeInOut } from '../../utils/animations';\r\nimport { LoginEvent } from '../../models/login-event';\r\n\r\n@Component({\r\n selector: 'lib-expired-password',\r\n imports: [ReactiveFormsModule],\r\n templateUrl: './expired-password.component.html',\r\n styleUrls: ['./expired-password.component.scss', '../auth.scss'],\r\n animations: [fadeInOut]\r\n})\r\nexport class ExpiredPasswordComponent {\r\n\r\n private readonly fb = inject(FormBuilder)\r\n\r\n production = input<boolean>(true)\r\n module = input<string>('ERP') // DEFECTO ERP\r\n\r\n loginEvent = output<LoginEvent>()\r\n\r\n passwordVisibility = signal({\r\n claveAntigua: false,\r\n claveNueva: false,\r\n claveNuevaConfirmar: false\r\n })\r\n\r\n expiredForm = this.fb.group({\r\n ruc: ['', [Validators.required, Validators.minLength(11), Validators.maxLength(11)]],\r\n coduser: ['', Validators.required],\r\n claveAntigua: ['', [Validators.required, Validators.maxLength(20)]],\r\n claveNueva: ['', [\r\n Validators.required,\r\n Validators.minLength(8),\r\n this.regexValidator(/[a-z]/, { minuscula: true }),\r\n this.regexValidator(/[A-Z]/, { mayuscula: true }),\r\n this.regexValidator(/[0-9]/, { numero: true }),\r\n this.regexValidator(/[!@#$%^&*(),.?\":{}|<>]/, { especial: true })\r\n ]],\r\n claveNuevaConfirmar: ['', Validators.required]\r\n }, {\r\n validators: this.validatePassword('claveNueva', 'claveNuevaConfirmar')\r\n })\r\n\r\n regexValidator(regex: RegExp, error: any) {\r\n return (control: AbstractControl) => {\r\n if (!control.value) return null\r\n return regex.test(control.value) ? null : error\r\n }\r\n }\r\n\r\n validatePassword(pass1: string, pass2: string) {\r\n return (formGroup: AbstractControl) => {\r\n const c1 = formGroup.get(pass1)?.value\r\n const c2 = formGroup.get(pass2)?.value\r\n if (c1 != c2) {\r\n formGroup.get(pass2)?.setErrors({ coinciden: true })\r\n return { coinciden: true }\r\n }\r\n return null\r\n }\r\n }\r\n\r\n togglePassword(field: 'claveAntigua' | 'claveNueva' | 'claveNuevaConfirmar') {\r\n this.passwordVisibility.update(vis => ({ ...vis, [field]: !vis[field] }));\r\n }\r\n\r\n recover = () => {\r\n if (this.expiredForm.invalid) {\r\n this.loginEvent.emit({type: \"ERROR\", message: 'Debes completar todos los campos y cumplir los requisitos.'})\r\n return\r\n }\r\n \r\n const values = this.expiredForm.value\r\n const sender: AuthSender = {\r\n ruc: values.ruc!,\r\n coduser: values.coduser!,\r\n clave: values.claveAntigua!,\r\n nuevaclave: values.claveNueva!\r\n }\r\n this.loginEvent.emit({ type: \"FORGET\", data: sender })\r\n }\r\n\r\n back = () => {\r\n this.expiredForm.reset()\r\n this.loginEvent.emit({ type: \"BACK\" })\r\n }\r\n}\r\n","<div class=\"auth-wrapper-login\">\r\n @let produccion = production();\r\n <div class=\"auth-panel-left\" [class.auth-panel-left--dev]=\"!produccion\">\r\n <span class=\"auth-blob auth-blob-1\"></span>\r\n <span class=\"auth-blob auth-blob-2\"></span>\r\n <span class=\"auth-blob auth-blob-3\"></span>\r\n <span class=\"auth-blob auth-blob-4\"></span>\r\n\r\n <div class=\"auth-brand-panel\">\r\n <div class=\"auth-brand-logo\">\r\n <img src=\"assets/images/logo-tsi-tres.png\" alt=\"TSI\" />\r\n </div>\r\n <h1 class=\"auth-brand-title\">{{module()}}</h1>\r\n <p class=\"auth-brand-subtitle\">Renueva tu contraseña y mantén tu cuenta segura</p>\r\n\r\n <div class=\"auth-brand-divider\"></div>\r\n\r\n <div class=\"auth-brand-features\">\r\n <div class=\"auth-brand-feature\">\r\n <span class=\"feat-dot\"></span> Mínimo 8 caracteres\r\n </div>\r\n <div class=\"auth-brand-feature\">\r\n <span class=\"feat-dot\"></span> Letras mayúsculas y minúsculas\r\n </div>\r\n <div class=\"auth-brand-feature\">\r\n <span class=\"feat-dot\"></span> Al menos un número y símbolo\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"auth-panel-right\" [class.auth-panel-right--dev]=\"!produccion\">\r\n <div class=\"auth-panel-bg\">\r\n <span class=\"auth-deco auth-deco-tl\"></span>\r\n <span class=\"auth-deco auth-deco-br\"></span>\r\n </div>\r\n\r\n <div class=\"auth-form-wrapper\">\r\n <div>\r\n @if (!produccion) {\r\n <div>\r\n <span class=\"auth-test-badge\">\r\n <span class=\"badge-dot\"></span> ENTORNO DE PRUEBAS\r\n </span>\r\n </div>\r\n }\r\n\r\n <div class=\"auth-card\">\r\n <h2 class=\"auth-card-title\">Renovar contraseña</h2>\r\n <p class=\"auth-card-subtitle\">Proporciona tus datos y elige una nueva clave</p>\r\n\r\n <form [formGroup]=\"expiredForm\">\r\n\r\n <div class=\"auth-field\"\r\n [class.has-error]=\"expiredForm.get('ruc')?.invalid && expiredForm.get('ruc')?.touched\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-building\"></i></span>\r\n <input type=\"text\" class=\"auth-input\" placeholder=\" \" maxlength=\"11\"\r\n formControlName=\"ruc\" id=\"exp-ruc\" onlyNumber autocomplete=\"off\">\r\n <label for=\"exp-ruc\" class=\"auth-label\">RUC</label>\r\n </div>\r\n @if (expiredForm.get('ruc')?.invalid && expiredForm.get('ruc')?.touched) {\r\n <p class=\"auth-error\" @fadeInOut>RUC debe tener 11 dígitos</p>\r\n }\r\n\r\n <div class=\"auth-field\"\r\n [class.has-error]=\"expiredForm.get('coduser')?.invalid && expiredForm.get('coduser')?.touched\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-user\"></i></span>\r\n <input type=\"text\" class=\"auth-input\" placeholder=\" \"\r\n formControlName=\"coduser\" id=\"exp-user\" autocomplete=\"off\">\r\n <label for=\"exp-user\" class=\"auth-label\">Usuario</label>\r\n </div>\r\n @if (expiredForm.get('coduser')?.invalid && expiredForm.get('coduser')?.touched) {\r\n <p class=\"auth-error\" @fadeInOut>El usuario es obligatorio</p>\r\n }\r\n\r\n <div class=\"auth-field\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-lock-open\"></i></span>\r\n <input [type]=\"passwordVisibility().claveAntigua ? 'text' : 'password'\"\r\n class=\"auth-input\" placeholder=\" \" maxlength=\"20\"\r\n formControlName=\"claveAntigua\" id=\"exp-old-pw\" autocomplete=\"new-password\">\r\n <label for=\"exp-old-pw\" class=\"auth-label\">Contraseña antigua</label>\r\n <button type=\"button\" class=\"auth-toggle-pw\" (click)=\"togglePassword('claveAntigua')\">\r\n <i [class]=\"passwordVisibility().claveAntigua ? 'fas fa-eye' : 'fas fa-eye-slash'\"></i>\r\n </button>\r\n </div>\r\n\r\n <div class=\"auth-field\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-lock\"></i></span>\r\n <input [type]=\"passwordVisibility().claveNueva ? 'text' : 'password'\"\r\n class=\"auth-input\" placeholder=\" \" maxlength=\"20\"\r\n formControlName=\"claveNueva\" id=\"exp-new-pw\" autocomplete=\"new-password\">\r\n <label for=\"exp-new-pw\" class=\"auth-label\">Contraseña nueva</label>\r\n <button type=\"button\" class=\"auth-toggle-pw\" (click)=\"togglePassword('claveNueva')\">\r\n <i [class]=\"passwordVisibility().claveNueva ? 'fas fa-eye' : 'fas fa-eye-slash'\"></i>\r\n </button>\r\n </div>\r\n\r\n @if (expiredForm.get('claveNueva')?.value?.length > 0) {\r\n <ul class=\"auth-validation-list\" @fadeInOut>\r\n @if (expiredForm.get('claveNueva')?.errors?.['minlength']) {\r\n <li>Al menos 8 caracteres</li>\r\n }\r\n @if (expiredForm.get('claveNueva')?.errors?.['minuscula']) {\r\n <li>Al menos 1 letra minúscula</li>\r\n }\r\n @if (expiredForm.get('claveNueva')?.errors?.['mayuscula']) {\r\n <li>Al menos 1 letra mayúscula</li>\r\n }\r\n @if (expiredForm.get('claveNueva')?.errors?.['numero']) {\r\n <li>Al menos 1 número</li>\r\n }\r\n @if (expiredForm.get('claveNueva')?.errors?.['especial']) {\r\n <li>Al menos 1 carácter especial</li>\r\n }\r\n </ul>\r\n }\r\n\r\n <div class=\"auth-field\"\r\n [class.has-error]=\"expiredForm.get('claveNuevaConfirmar')?.errors?.['coinciden'] && expiredForm.get('claveNuevaConfirmar')?.touched\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-check-circle\"></i></span>\r\n <input [type]=\"passwordVisibility().claveNuevaConfirmar ? 'text' : 'password'\"\r\n class=\"auth-input\" placeholder=\" \" maxlength=\"20\"\r\n formControlName=\"claveNuevaConfirmar\" id=\"exp-confirm-pw\" autocomplete=\"new-password\">\r\n <label for=\"exp-confirm-pw\" class=\"auth-label\">Confirmar contraseña</label>\r\n <button type=\"button\" class=\"auth-toggle-pw\" (click)=\"togglePassword('claveNuevaConfirmar')\">\r\n <i [class]=\"passwordVisibility().claveNuevaConfirmar ? 'fas fa-eye' : 'fas fa-eye-slash'\"></i>\r\n </button>\r\n </div>\r\n @if (expiredForm.get('claveNuevaConfirmar')?.errors?.['coinciden'] && expiredForm.get('claveNuevaConfirmar')?.touched) {\r\n <p class=\"auth-error\" @fadeInOut>Las contraseñas deben coincidir</p>\r\n }\r\n\r\n <button type=\"button\" class=\"auth-btn\" [class.auth-btn--red]=\"!produccion\"\r\n [disabled]=\"expiredForm.invalid\" (click)=\"recover()\">\r\n Renovar contraseña\r\n </button>\r\n\r\n <button type=\"button\" class=\"auth-btn auth-btn--outline\" (click)=\"back()\">\r\n Volver al inicio de sesión\r\n </button>\r\n\r\n </form>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n","import { Component, inject, input, output } from '@angular/core';\r\nimport { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';\r\nimport { AuthSender } from '../../models/auth-sender';\r\nimport { fadeInOut } from '../../utils/animations';\r\nimport { LoginEvent } from '../../models/login-event';\r\n\r\n@Component({\r\n selector: 'lib-recover-password',\r\n imports: [ReactiveFormsModule],\r\n templateUrl: './recover-password.component.html',\r\n styleUrls: ['./recover-password.component.scss', '../auth.scss'],\r\n animations: [fadeInOut]\r\n})\r\nexport class RecoverPasswordComponent {\r\n\r\n private fb = inject(FormBuilder)\r\n\r\n production = input<boolean>(true)\r\n module = input<string>('ERP') // DEFECTO ERP\r\n\r\n loginEvent = output<LoginEvent>()\r\n\r\n recoverForm = this.fb.group({\r\n ruc: ['', [Validators.required, Validators.minLength(11), Validators.maxLength(11)]],\r\n usuario: ['', Validators.required]\r\n })\r\n\r\n enviar = () => {\r\n if (this.recoverForm.invalid) {\r\n this.loginEvent.emit({ type: \"ERROR\", message: 'Debes completar todos los campos' })\r\n return\r\n }\r\n\r\n const formValues = this.recoverForm.value\r\n const sender: AuthSender = {\r\n ruc: formValues.ruc!,\r\n coduser: formValues.usuario!\r\n }\r\n\r\n this.loginEvent.emit({ type: \"RECOVER\", data: sender })\r\n }\r\n\r\n back = () => this.loginEvent.emit({ type: \"BACK\" })\r\n \r\n}\r\n","<div class=\"auth-wrapper-login\">\r\n @let produccion = production();\r\n <div class=\"auth-panel-left\" [class.auth-panel-left--dev]=\"!produccion\">\r\n <span class=\"auth-blob auth-blob-1\"></span>\r\n <span class=\"auth-blob auth-blob-2\"></span>\r\n <span class=\"auth-blob auth-blob-3\"></span>\r\n <span class=\"auth-blob auth-blob-4\"></span>\r\n\r\n <div class=\"auth-brand-panel\">\r\n <div class=\"auth-brand-logo\">\r\n <img src=\"assets/images/logo-tsi-tres.png\" alt=\"TSI\" />\r\n </div>\r\n <h1 class=\"auth-brand-title\">{{module()}}</h1>\r\n <p class=\"auth-brand-subtitle\">Recupera el acceso a tu cuenta de forma rápida y segura</p>\r\n\r\n <div class=\"auth-brand-divider\"></div>\r\n\r\n <div class=\"auth-brand-features\">\r\n <div class=\"auth-brand-feature\">\r\n <span class=\"feat-dot\"></span> Verificación por correo electrónico\r\n </div>\r\n <div class=\"auth-brand-feature\">\r\n <span class=\"feat-dot\"></span> Proceso seguro y encriptado\r\n </div>\r\n <div class=\"auth-brand-feature\">\r\n <span class=\"feat-dot\"></span> Nueva clave en minutos\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"auth-panel-right\" [class.auth-panel-right--dev]=\"!produccion\">\r\n <div class=\"auth-panel-bg\">\r\n <span class=\"auth-deco auth-deco-tl\"></span>\r\n <span class=\"auth-deco auth-deco-br\"></span>\r\n </div>\r\n\r\n <div class=\"auth-form-wrapper\">\r\n <div>\r\n @if (!produccion) {\r\n <div>\r\n <span class=\"auth-test-badge\">\r\n <span class=\"badge-dot\"></span> ENTORNO DE PRUEBAS\r\n </span>\r\n </div>\r\n }\r\n\r\n <div class=\"auth-card\">\r\n <h2 class=\"auth-card-title\">Recuperar contraseña</h2>\r\n <p class=\"auth-card-subtitle\">\r\n Confírmanos tu RUC y usuario. Enviaremos a tu correo registrado la nueva contraseña.\r\n </p>\r\n\r\n <form [formGroup]=\"recoverForm\">\r\n\r\n <div class=\"auth-field\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-building\"></i></span>\r\n <input type=\"text\" class=\"auth-input\" placeholder=\" \" maxlength=\"11\" formControlName=\"ruc\"\r\n id=\"rec-ruc\" onlyNumber autocomplete=\"off\">\r\n <label for=\"rec-ruc\" class=\"auth-label\">RUC</label>\r\n </div>\r\n\r\n <div class=\"auth-field\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-user\"></i></span>\r\n <input type=\"text\" class=\"auth-input\" placeholder=\" \" formControlName=\"usuario\"\r\n id=\"rec-user\" autocomplete=\"off\">\r\n <label for=\"rec-user\" class=\"auth-label\">Usuario</label>\r\n </div>\r\n\r\n <button type=\"button\" class=\"auth-btn\" [class.auth-btn--red]=\"!produccion\"\r\n [disabled]=\"recoverForm.invalid\" (click)=\"enviar()\">\r\n Enviar instrucciones\r\n </button>\r\n\r\n <button type=\"button\" class=\"auth-btn auth-btn--outline\" (click)=\"back()\">\r\n Volver al inicio de sesión\r\n </button>\r\n\r\n </form>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>","import { Component, computed, HostListener, input, model, output } from '@angular/core';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { LoginEvent } from '../../models/login-event';\r\n\r\n@Component({\r\n selector: 'lib-select-branch',\r\n imports: [FormsModule],\r\n templateUrl: './select-branch.component.html',\r\n styleUrls: ['./select-branch.component.scss', '../auth.scss']\r\n})\r\nexport class SelectBranchComponent {\r\n\r\n production = input<boolean>(true)\r\n module = input<string>('ERP') // DEFECTO ERP\r\n title = computed(() => this.production() ? `MÓDULO: ${this.module()}` : `MÓDULO DE PRUEBA: ${this.module()}`)\r\n\r\n codsuc = model<number>(-1)\r\n sucursalesList = input<any[]>([])\r\n\r\n loginEvent = output<LoginEvent>()\r\n\r\n @HostListener('document:keydown', ['$event'])\r\n handleEnter(_event: KeyboardEvent) {\r\n if(_event.key !== 'Enter') return\r\n if (!this.codsuc) {\r\n return\r\n }\r\n this.goMain()\r\n }\r\n\r\n goMain = () => {\r\n this.loginEvent.emit({type: \"BRANCH\", data: { codsuc: this.codsuc() }})\r\n }\r\n}\r\n","<div class=\"auth-wrapper-login\">\r\n @let produccion = production();\r\n <div class=\"auth-panel-left\" [class.auth-panel-left--dev]=\"!produccion\">\r\n <span class=\"auth-blob auth-blob-1\"></span>\r\n <span class=\"auth-blob auth-blob-2\"></span>\r\n <span class=\"auth-blob auth-blob-3\"></span>\r\n <span class=\"auth-blob auth-blob-4\"></span>\r\n\r\n <div class=\"auth-brand-panel\">\r\n <div class=\"auth-brand-logo\">\r\n <img src=\"assets/images/logo-tsi-tres.png\" alt=\"TSI\" />\r\n </div>\r\n <h1 class=\"auth-brand-title\">{{module()}}</h1>\r\n <p class=\"auth-brand-subtitle\">Selecciona la sucursal desde donde vas a operar hoy</p>\r\n\r\n <div class=\"auth-brand-divider\"></div>\r\n\r\n <div class=\"auth-brand-features\">\r\n <div class=\"auth-brand-feature\">\r\n <span class=\"feat-dot\"></span> Acceso segmentado por sucursal\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"auth-panel-right\" [class.auth-panel-right--dev]=\"!produccion\">\r\n <div class=\"auth-panel-bg\">\r\n <span class=\"auth-deco auth-deco-tl\"></span>\r\n <span class=\"auth-deco auth-deco-br\"></span>\r\n </div>\r\n\r\n <div class=\"auth-form-wrapper\">\r\n <div>\r\n @if (!produccion) {\r\n <div>\r\n <span class=\"auth-test-badge\">\r\n <span class=\"badge-dot\"></span> ENTORNO DE PRUEBAS\r\n </span>\r\n </div>\r\n }\r\n\r\n <div class=\"auth-card\">\r\n <h2 class=\"auth-card-title\">Seleccionar sucursal</h2>\r\n <p class=\"auth-card-subtitle\">{{title()}}</p>\r\n\r\n <select class=\"auth-select\" [(ngModel)]=\"codsuc\">\r\n @for (suc of sucursalesList(); track $index) {\r\n <option [value]=\"suc.codsuc\">{{suc.sucursal}}</option>\r\n }\r\n </select>\r\n\r\n <button class=\"auth-btn\" [class.auth-btn--red]=\"!produccion\" (click)=\"goMain()\">\r\n Continuar\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>","export class AuthSender {\r\n ruc?: string\r\n coduser?: string\r\n clave?: string\r\n nuevaclave?: string\r\n producto?: string\r\n codsuc?: number\r\n}","/*\r\n * Public API Surface of login-tsi\r\n */\r\n\r\nexport * from './lib/components/auth/auth.component';\r\nexport * from './lib/components/expired-password/expired-password.component';\r\nexport * from './lib/components/recover-password/recover-password.component';\r\nexport * from './lib/components/select-branch/select-branch.component';\r\nexport * from './lib/models/auth-sender';\r\nexport * from './lib/models/login-event';\r\nexport * from './lib/models/login-type-event';\r\n\r\n// PWA (instalación, guía, actualización/refresh forzado)\r\nexport * from './lib/components/pwa-floating/pwa-floating.component';\r\nexport * from './lib/components/refresh-floating/refresh-floating.component';\r\nexport * from './lib/pwa-install.service';","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"login-tsi.mjs","sources":["../../../projects/login-tsi/src/lib/utils/animations.ts","../../../projects/login-tsi/src/lib/pwa-install.service.ts","../../../projects/login-tsi/src/lib/components/pwa-floating/pwa-floating.component.ts","../../../projects/login-tsi/src/lib/components/pwa-floating/pwa-floating.component.html","../../../projects/login-tsi/src/lib/components/refresh-floating/refresh-floating.component.ts","../../../projects/login-tsi/src/lib/components/refresh-floating/refresh-floating.component.html","../../../projects/login-tsi/src/lib/components/auth/auth.component.ts","../../../projects/login-tsi/src/lib/components/auth/auth.component.html","../../../projects/login-tsi/src/lib/components/expired-password/expired-password.component.ts","../../../projects/login-tsi/src/lib/components/expired-password/expired-password.component.html","../../../projects/login-tsi/src/lib/components/recover-password/recover-password.component.ts","../../../projects/login-tsi/src/lib/components/recover-password/recover-password.component.html","../../../projects/login-tsi/src/lib/components/select-branch/select-branch.component.ts","../../../projects/login-tsi/src/lib/components/select-branch/select-branch.component.html","../../../projects/login-tsi/src/lib/models/auth-sender.ts","../../../projects/login-tsi/src/lib/models/verificar-mfa.ts","../../../projects/login-tsi/src/lib/components/md-verificar-mfa/md-verificar-mfa.component.ts","../../../projects/login-tsi/src/lib/components/md-verificar-mfa/md-verificar-mfa.component.html","../../../projects/login-tsi/src/public-api.ts","../../../projects/login-tsi/src/login-tsi.ts"],"sourcesContent":["import { animate, style, transition, trigger } from \"@angular/animations\";\r\n\r\nexport const fadeInOut = trigger('fadeInOut', [\r\n transition(':enter', [\r\n style({ opacity: 0, transform: 'translateY(-5px)' }),\r\n animate('200ms ease-out', style({ opacity: 1, transform: 'translateY(0)' })),\r\n ]),\r\n transition(':leave', [\r\n animate('200ms ease-in', style({ opacity: 0, transform: 'translateY(-5px)' })),\r\n ]),\r\n ])","import { Injectable, signal } from '@angular/core';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class PwaInstallService {\r\n\r\n readonly isAndroid = /Android/i.test(navigator.userAgent)\r\n readonly isIOS = /iPad|iPhone|iPod/i.test(navigator.userAgent)\r\n readonly isSafariMac = /^((?!Chrome|Android).)*Safari/i.test(navigator.userAgent) && /Mac/i.test(navigator.platform)\r\n readonly isChrome = /Chrome|Chromium|Edg/i.test(navigator.userAgent) && !/Android/i.test(navigator.userAgent)\r\n\r\n readonly showButton = signal<boolean>(\r\n !window.matchMedia('(display-mode: standalone)').matches\r\n )\r\n readonly showGuide = signal<boolean>(false)\r\n\r\n private get deferredPrompt(): any { return (window as any).__pwaPrompt ?? null }\r\n\r\n get canAutoInstall(): boolean { return !!this.deferredPrompt }\r\n\r\n async tryInstall(): Promise<void> {\r\n const prompt = this.deferredPrompt\r\n if (!prompt) return\r\n prompt.prompt()\r\n const { outcome } = await prompt.userChoice\r\n if (outcome === 'accepted') this.showButton.set(false)\r\n else (window as any).__pwaPrompt = null\r\n }\r\n\r\n toggleGuide() { this.showGuide.update(v => !v) }\r\n\r\n markAsAdded() {\r\n this.showGuide.set(false)\r\n this.showButton.set(false)\r\n }\r\n}\r\n","import { Component, inject, input, output } from '@angular/core';\r\nimport { PwaInstallService } from '../../pwa-install.service';\r\n\r\n@Component({\r\n selector: 'app-pwa-floating',\r\n templateUrl: './pwa-floating.component.html',\r\n styleUrl: './pwa-floating.component.scss'\r\n})\r\n\r\nexport class PwaFloatingComponent {\r\n\r\n readonly pwa = inject(PwaInstallService)\r\n\r\n appName = input<string>('ERP TSI')\r\n logo = input<string>('assets/images/logo-tsi-tres.png')\r\n chipLabel = input<string>('Instalar app')\r\n\r\n beforeInstall = output<void>()\r\n guideClosed = output<void>()\r\n\r\n onChipClick() {\r\n if (!this.pwa.showGuide()) {\r\n this.beforeInstall.emit()\r\n } else {\r\n this.guideClosed.emit()\r\n }\r\n this.pwa.toggleGuide()\r\n }\r\n\r\n onCloseGuide() {\r\n this.guideClosed.emit()\r\n this.pwa.toggleGuide()\r\n }\r\n\r\n onMarkAsAdded() {\r\n this.guideClosed.emit()\r\n this.pwa.markAsAdded()\r\n }\r\n\r\n}\r\n","@if (pwa.showButton()) {\r\n<div class=\"pwa-wrap\">\r\n\r\n @if (pwa.showGuide()) {\r\n <div class=\"pwa-guide\">\r\n <button class=\"pwa-guide__close\" (click)=\"onCloseGuide()\">\r\n <i class=\"fas fa-xmark\"></i>\r\n </button>\r\n\r\n <div class=\"pwa-guide__header\">\r\n <img [src]=\"logo()\" alt=\"\" class=\"pwa-guide__logo\">\r\n <div>\r\n <p class=\"pwa-guide__title\">Instalar {{ appName() }}</p>\r\n <p class=\"pwa-guide__sub\">Úsalo como una app desde tu dispositivo</p>\r\n </div>\r\n </div>\r\n\r\n @if (!pwa.canAutoInstall) {\r\n <ol class=\"pwa-guide__steps\">\r\n @if (pwa.isIOS) {\r\n <li>Toca el botón <span class=\"pwa-guide__badge\"><i class=\"fas fa-arrow-up-from-bracket\"></i></span> en la barra inferior del navegador</li>\r\n <li>Desplázate y selecciona <strong>\"En la pantalla de inicio\"</strong></li>\r\n <li>Toca <strong>\"Añadir\"</strong> en la esquina superior derecha</li>\r\n } @else if (pwa.isAndroid) {\r\n <li>Toca el menú <span class=\"pwa-guide__badge\"><i class=\"fas fa-ellipsis-vertical\"></i></span> en la esquina superior derecha</li>\r\n <li>Selecciona <strong>\"Instalar aplicación\"</strong> o <strong>\"Añadir a pantalla de inicio\"</strong></li>\r\n <li>Toca <strong>\"Instalar\"</strong> para confirmar</li>\r\n } @else if (pwa.isSafariMac) {\r\n <li>Abre el menú <strong>\"Archivo\"</strong> en la barra superior del Mac</li>\r\n <li>Selecciona <strong>\"Añadir al Dock...\"</strong></li>\r\n <li>Haz clic en <strong>\"Añadir\"</strong> para confirmar</li>\r\n } @else if (pwa.isChrome) {\r\n <li>Busca el ícono <span class=\"pwa-guide__badge\"><i class=\"fas fa-display\"></i></span> al final de la barra de direcciones</li>\r\n <li>Haz clic en él y selecciona <strong>\"Instalar\"</strong></li>\r\n <li>Confirma en el diálogo que aparece</li>\r\n } @else {\r\n <li>Abre el menú <span class=\"pwa-guide__badge\"><i class=\"fas fa-ellipsis-vertical\"></i></span> de tu navegador</li>\r\n <li>Busca <strong>\"Instalar aplicación\"</strong> o <strong>\"Añadir a pantalla de inicio\"</strong></li>\r\n <li>Confirma para instalar</li>\r\n }\r\n </ol>\r\n }\r\n\r\n @if (pwa.canAutoInstall) {\r\n <button class=\"pwa-guide__install\" (click)=\"pwa.tryInstall()\">\r\n <i class=\"fas fa-download\"></i> Instalar ahora\r\n </button>\r\n }\r\n <button class=\"pwa-guide__done\" (click)=\"onMarkAsAdded()\">\r\n <i class=\"fas fa-check\"></i> Ya lo instalé\r\n </button>\r\n </div>\r\n }\r\n\r\n <button class=\"pwa-chip\" (click)=\"onChipClick()\">\r\n <img [src]=\"logo()\" alt=\"\" class=\"pwa-chip__logo\">\r\n <span>{{ chipLabel() }}</span>\r\n </button>\r\n\r\n</div>\r\n}\r\n","import { Component, signal } from '@angular/core';\r\n\r\n@Component({\r\n selector: 'app-refresh-floating',\r\n templateUrl: './refresh-floating.component.html',\r\n styleUrl: './refresh-floating.component.scss'\r\n})\r\n\r\nexport class RefreshFloatingComponent {\r\n\r\n showGuide = signal<boolean>(false)\r\n\r\n toggleGuide() {\r\n this.showGuide.update(v => !v)\r\n }\r\n\r\n actualizar() {\r\n window.location.reload()\r\n }\r\n\r\n async actualizarTotal() {\r\n if ('serviceWorker' in navigator) {\r\n const registrations = await navigator.serviceWorker.getRegistrations()\r\n await Promise.all(registrations.map(r => r.unregister()))\r\n }\r\n if ('caches' in window) {\r\n const names = await caches.keys()\r\n await Promise.all(names.map(name => caches.delete(name)))\r\n }\r\n window.location.href = window.location.pathname + '?_r=' + Date.now()\r\n }\r\n}\r\n","<div class=\"refresh-wrap\">\r\n\r\n @if (showGuide()) {\r\n <div class=\"refresh-guide\">\r\n <button class=\"refresh-guide__close\" (click)=\"toggleGuide()\">\r\n <i class=\"fas fa-xmark\"></i>\r\n </button>\r\n\r\n <p class=\"refresh-guide__title\">Actualizar aplicación</p>\r\n\r\n <button class=\"refresh-guide__option\" (click)=\"actualizar()\">\r\n <i class=\"fas fa-rotate\"></i> Actualizar\r\n </button>\r\n\r\n <button class=\"refresh-guide__option refresh-guide__option--force\" (click)=\"actualizarTotal()\">\r\n <i class=\"fas fa-rotate-right\"></i> Forzar actualización\r\n </button>\r\n </div>\r\n }\r\n\r\n <button class=\"refresh-chip\" (click)=\"toggleGuide()\" title=\"Actualizar\">\r\n <i class=\"fas fa-rotate\"></i>\r\n </button>\r\n\r\n</div>\r\n","import { NgClass } from '@angular/common';\r\nimport { Component, input, output, signal } from '@angular/core';\r\nimport { FormGroup, ReactiveFormsModule } from '@angular/forms';\r\nimport { AuthSender } from '../../models/auth-sender';\r\nimport { fadeInOut } from '../../utils/animations';\r\nimport { LoginEvent } from '../../models/login-event';\r\nimport { PwaFloatingComponent } from '../pwa-floating/pwa-floating.component';\r\nimport { RefreshFloatingComponent } from '../refresh-floating/refresh-floating.component';\r\n\r\n@Component({\r\n selector: 'lib-auth-tsi',\r\n imports: [NgClass, ReactiveFormsModule, PwaFloatingComponent, RefreshFloatingComponent],\r\n templateUrl: './auth.component.html',\r\n styleUrls: ['./auth.component.scss', '../auth.scss'],\r\n animations: [fadeInOut]\r\n})\r\nexport class AuthComponent {\r\n\r\n production = input<boolean>(true)\r\n module = input<string>('ERP') // DEFECTO ERP\r\n versionApp = input<string>('1.0.0') // DEFECTO 1.0.0\r\n product = input<string>() // DEFECTO NULL - ERP\r\n authForm = input.required<FormGroup>();\r\n\r\n aboutList = input<string[]>([\r\n 'Gestión de compras y logística',\r\n 'Control financiero avanzado',\r\n 'Reportes y análisis en tiempo real',\r\n 'Integración con inteligencia artificial'\r\n ])\r\n\r\n /** Muestra el flotante de \"instalar app\" (app-pwa-floating). Por defecto siempre visible. */\r\n showFloatingApp = input<boolean>(true)\r\n /** Muestra el flotante de \"actualización disponible\" (app-refresh-floating). Por defecto siempre visible. */\r\n showFloatingUpdate = input<boolean>(true)\r\n\r\n loginEvent = output<LoginEvent>()\r\n /** Se dispara antes de instalar la PWA — el RUC/usuario ya están en authForm(), el consumidor decide qué guardar. */\r\n beforeInstall = output<void>()\r\n\r\n showPassword = signal<boolean>(false)\r\n\r\n onBeforeInstall = () => this.beforeInstall.emit()\r\n\r\n recover = () => this.loginEvent.emit({type: \"RECOVER\"})\r\n forget = () => this.loginEvent.emit({type: \"FORGET\"})\r\n \r\n togglePassword = () => this.showPassword.set(!this.showPassword())\r\n\r\n login = () => {\r\n if (!this.validacionInit()) return\r\n const dataForm = this.authForm().value\r\n const data: AuthSender = {\r\n ruc: dataForm.ruc,\r\n coduser: dataForm.nomuser,\r\n clave: btoa(dataForm.clave),\r\n producto: this.product()\r\n }\r\n this.loginEvent.emit({type: \"LOGIN\", data})\r\n }\r\n\r\n // authForm = this.formBuilder.group({\r\n // ruc: ['', Validators.required],\r\n // nomuser: ['', Validators.required],\r\n // clave: ['', Validators.required],\r\n // })\r\n\r\n validacion(value: string) {\r\n const authForm = this.authForm()\r\n if (authForm.get(value).touched && authForm.get(value).errors) {\r\n return true\r\n }\r\n return false\r\n }\r\n\r\n validacionInit() {\r\n const dataForm = this.authForm().value\r\n const { ruc, nomuser, clave } = dataForm\r\n\r\n if (!ruc) return this.returnError('Debe ingresar un N° de RUC')\r\n if (!nomuser) return this.returnError('Debe ingresar un usuario')\r\n if (!clave) return this.returnError('Debe ingresar una contraseña')\r\n return true\r\n }\r\n \r\n returnError = (message:string) => {\r\n this.loginEvent.emit({type: \"ERROR\", message})\r\n return false\r\n }\r\n}\r\n","<div class=\"auth-wrapper-login\">\r\n @let produccion = production();\r\n <div class=\"auth-panel-left\" [class.auth-panel-left--dev]=\"!produccion\">\r\n <span class=\"auth-blob auth-blob-1\"></span>\r\n <span class=\"auth-blob auth-blob-2\"></span>\r\n <span class=\"auth-blob auth-blob-3\"></span>\r\n <span class=\"auth-blob auth-blob-4\"></span>\r\n\r\n <div class=\"auth-brand-panel\">\r\n <div class=\"auth-brand-logo\">\r\n <img src=\"assets/images/logo-tsi-tres.png\" alt=\"TSI\" />\r\n </div>\r\n <h1 class=\"auth-brand-title\">{{module()}}</h1>\r\n <p class=\"auth-brand-subtitle\">Plataforma integrada de gestión<br>empresarial</p>\r\n\r\n <div class=\"auth-brand-divider\"></div>\r\n\r\n <div class=\"auth-brand-features\">\r\n @for (item of aboutList(); track $index) {\r\n <div class=\"auth-brand-feature\">\r\n <span class=\"feat-dot\"></span> {{item}}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"auth-panel-right\" [class.auth-panel-right--dev]=\"!produccion\">\r\n <div class=\"auth-panel-bg\">\r\n <span class=\"auth-deco auth-deco-tl\"></span>\r\n <span class=\"auth-deco auth-deco-br\"></span>\r\n </div>\r\n\r\n <div class=\"auth-form-wrapper\">\r\n <div>\r\n @if (!produccion) {\r\n <div>\r\n <span class=\"auth-test-badge\">\r\n <span class=\"badge-dot\"></span> ENTORNO DE PRUEBAS\r\n </span>\r\n </div>\r\n }\r\n\r\n <div class=\"auth-card\">\r\n <h2 class=\"auth-card-title\">Bienvenido de vuelta</h2>\r\n <p class=\"auth-card-subtitle\">Ingresa tus credenciales para continuar</p>\r\n\r\n <form [formGroup]=\"authForm()\" id=\"loginform\">\r\n\r\n <p class=\"auth-hint\">\r\n <i class=\"fas fa-circle-info\"></i>\r\n Si piensas instalar la app, te recomendamos completar el RUC y Usuario antes, estos quedarán guardados y siempre aparecerán completos al abrirla.\r\n </p>\r\n\r\n <div class=\"auth-field\" [class.has-error]=\"validacion('ruc')\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-building\"></i></span>\r\n <input type=\"text\" formControlName=\"ruc\" class=\"auth-input\" placeholder=\" \" maxlength=\"11\"\r\n id=\"f-ruc\" autocomplete=\"off\">\r\n <label for=\"f-ruc\" class=\"auth-label\">RUC</label>\r\n </div>\r\n @if (validacion('ruc')) {\r\n <p class=\"auth-error\" @fadeInOut>Ingresar RUC</p>\r\n }\r\n\r\n <div class=\"auth-field\" [class.has-error]=\"validacion('nomuser')\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-user\"></i></span>\r\n <input type=\"text\" formControlName=\"nomuser\" class=\"auth-input\" placeholder=\" \" id=\"f-user\"\r\n autocomplete=\"off\">\r\n <label for=\"f-user\" class=\"auth-label\">Usuario</label>\r\n </div>\r\n @if (validacion('nomuser')) {\r\n <p class=\"auth-error\" @fadeInOut>Ingresar usuario</p>\r\n }\r\n\r\n <div class=\"auth-field\" [class.has-error]=\"validacion('clave')\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-lock\"></i></span>\r\n <input [type]=\"showPassword() ? 'text' : 'password'\" formControlName=\"clave\"\r\n class=\"auth-input\" placeholder=\" \" id=\"f-clave\" autocomplete=\"off\" autocorrect=\"off\"\r\n autocapitalize=\"off\" spellcheck=\"false\">\r\n <label for=\"f-clave\" class=\"auth-label\">Contraseña</label>\r\n <button type=\"button\" class=\"auth-toggle-pw\" (click)=\"togglePassword()\">\r\n <i [class]=\"showPassword() ? 'fas fa-eye' : 'fas fa-eye-slash'\"></i>\r\n </button>\r\n </div>\r\n @if (validacion('clave')) {\r\n <p class=\"auth-error\" @fadeInOut>Ingresar clave</p>\r\n }\r\n\r\n <button class=\"auth-btn mt-2\" [class.auth-btn--red]=\"!produccion\" (click)=\"login()\">\r\n Ingresar\r\n </button>\r\n\r\n <div class=\"auth-links\">\r\n <a [ngClass]=\"produccion ? 'blue_contrasena' : 'red_contrasena'\"\r\n (click)=\"recover()\">¿Olvidaste tu contraseña?</a>\r\n <a [ngClass]=\"produccion ? 'blue_contrasena' : 'red_contrasena'\"\r\n (click)=\"forget()\">¿Contraseña vencida?</a>\r\n </div>\r\n\r\n </form>\r\n\r\n <div class=\"auth-version\">\r\n <span>v{{versionApp()}}</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n@if (showFloatingApp()) {\r\n<app-pwa-floating [appName]=\"module()\" (beforeInstall)=\"onBeforeInstall()\" />\r\n}\r\n@if (showFloatingUpdate()) {\r\n<app-refresh-floating />\r\n}","import { Component, inject, input, output, signal } from '@angular/core';\r\nimport { AbstractControl, FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';\r\nimport { AuthSender } from '../../models/auth-sender';\r\nimport { fadeInOut } from '../../utils/animations';\r\nimport { LoginEvent } from '../../models/login-event';\r\n\r\n@Component({\r\n selector: 'lib-expired-password',\r\n imports: [ReactiveFormsModule],\r\n templateUrl: './expired-password.component.html',\r\n styleUrls: ['./expired-password.component.scss', '../auth.scss'],\r\n animations: [fadeInOut]\r\n})\r\nexport class ExpiredPasswordComponent {\r\n\r\n private readonly fb = inject(FormBuilder)\r\n\r\n production = input<boolean>(true)\r\n module = input<string>('ERP') // DEFECTO ERP\r\n\r\n loginEvent = output<LoginEvent>()\r\n\r\n passwordVisibility = signal({\r\n claveAntigua: false,\r\n claveNueva: false,\r\n claveNuevaConfirmar: false\r\n })\r\n\r\n expiredForm = this.fb.group({\r\n ruc: ['', [Validators.required, Validators.minLength(11), Validators.maxLength(11)]],\r\n coduser: ['', Validators.required],\r\n claveAntigua: ['', [Validators.required, Validators.maxLength(20)]],\r\n claveNueva: ['', [\r\n Validators.required,\r\n Validators.minLength(8),\r\n this.regexValidator(/[a-z]/, { minuscula: true }),\r\n this.regexValidator(/[A-Z]/, { mayuscula: true }),\r\n this.regexValidator(/[0-9]/, { numero: true }),\r\n this.regexValidator(/[!@#$%^&*(),.?\":{}|<>]/, { especial: true })\r\n ]],\r\n claveNuevaConfirmar: ['', Validators.required]\r\n }, {\r\n validators: this.validatePassword('claveNueva', 'claveNuevaConfirmar')\r\n })\r\n\r\n regexValidator(regex: RegExp, error: any) {\r\n return (control: AbstractControl) => {\r\n if (!control.value) return null\r\n return regex.test(control.value) ? null : error\r\n }\r\n }\r\n\r\n validatePassword(pass1: string, pass2: string) {\r\n return (formGroup: AbstractControl) => {\r\n const c1 = formGroup.get(pass1)?.value\r\n const c2 = formGroup.get(pass2)?.value\r\n if (c1 != c2) {\r\n formGroup.get(pass2)?.setErrors({ coinciden: true })\r\n return { coinciden: true }\r\n }\r\n return null\r\n }\r\n }\r\n\r\n togglePassword(field: 'claveAntigua' | 'claveNueva' | 'claveNuevaConfirmar') {\r\n this.passwordVisibility.update(vis => ({ ...vis, [field]: !vis[field] }));\r\n }\r\n\r\n recover = () => {\r\n if (this.expiredForm.invalid) {\r\n this.loginEvent.emit({type: \"ERROR\", message: 'Debes completar todos los campos y cumplir los requisitos.'})\r\n return\r\n }\r\n \r\n const values = this.expiredForm.value\r\n const sender: AuthSender = {\r\n ruc: values.ruc!,\r\n coduser: values.coduser!,\r\n clave: values.claveAntigua!,\r\n nuevaclave: values.claveNueva!\r\n }\r\n this.loginEvent.emit({ type: \"FORGET\", data: sender })\r\n }\r\n\r\n back = () => {\r\n this.expiredForm.reset()\r\n this.loginEvent.emit({ type: \"BACK\" })\r\n }\r\n}\r\n","<div class=\"auth-wrapper-login\">\r\n @let produccion = production();\r\n <div class=\"auth-panel-left\" [class.auth-panel-left--dev]=\"!produccion\">\r\n <span class=\"auth-blob auth-blob-1\"></span>\r\n <span class=\"auth-blob auth-blob-2\"></span>\r\n <span class=\"auth-blob auth-blob-3\"></span>\r\n <span class=\"auth-blob auth-blob-4\"></span>\r\n\r\n <div class=\"auth-brand-panel\">\r\n <div class=\"auth-brand-logo\">\r\n <img src=\"assets/images/logo-tsi-tres.png\" alt=\"TSI\" />\r\n </div>\r\n <h1 class=\"auth-brand-title\">{{module()}}</h1>\r\n <p class=\"auth-brand-subtitle\">Renueva tu contraseña y mantén tu cuenta segura</p>\r\n\r\n <div class=\"auth-brand-divider\"></div>\r\n\r\n <div class=\"auth-brand-features\">\r\n <div class=\"auth-brand-feature\">\r\n <span class=\"feat-dot\"></span> Mínimo 8 caracteres\r\n </div>\r\n <div class=\"auth-brand-feature\">\r\n <span class=\"feat-dot\"></span> Letras mayúsculas y minúsculas\r\n </div>\r\n <div class=\"auth-brand-feature\">\r\n <span class=\"feat-dot\"></span> Al menos un número y símbolo\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"auth-panel-right\" [class.auth-panel-right--dev]=\"!produccion\">\r\n <div class=\"auth-panel-bg\">\r\n <span class=\"auth-deco auth-deco-tl\"></span>\r\n <span class=\"auth-deco auth-deco-br\"></span>\r\n </div>\r\n\r\n <div class=\"auth-form-wrapper\">\r\n <div>\r\n @if (!produccion) {\r\n <div>\r\n <span class=\"auth-test-badge\">\r\n <span class=\"badge-dot\"></span> ENTORNO DE PRUEBAS\r\n </span>\r\n </div>\r\n }\r\n\r\n <div class=\"auth-card\">\r\n <h2 class=\"auth-card-title\">Renovar contraseña</h2>\r\n <p class=\"auth-card-subtitle\">Proporciona tus datos y elige una nueva clave</p>\r\n\r\n <form [formGroup]=\"expiredForm\">\r\n\r\n <div class=\"auth-field\"\r\n [class.has-error]=\"expiredForm.get('ruc')?.invalid && expiredForm.get('ruc')?.touched\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-building\"></i></span>\r\n <input type=\"text\" class=\"auth-input\" placeholder=\" \" maxlength=\"11\"\r\n formControlName=\"ruc\" id=\"exp-ruc\" onlyNumber autocomplete=\"off\">\r\n <label for=\"exp-ruc\" class=\"auth-label\">RUC</label>\r\n </div>\r\n @if (expiredForm.get('ruc')?.invalid && expiredForm.get('ruc')?.touched) {\r\n <p class=\"auth-error\" @fadeInOut>RUC debe tener 11 dígitos</p>\r\n }\r\n\r\n <div class=\"auth-field\"\r\n [class.has-error]=\"expiredForm.get('coduser')?.invalid && expiredForm.get('coduser')?.touched\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-user\"></i></span>\r\n <input type=\"text\" class=\"auth-input\" placeholder=\" \"\r\n formControlName=\"coduser\" id=\"exp-user\" autocomplete=\"off\">\r\n <label for=\"exp-user\" class=\"auth-label\">Usuario</label>\r\n </div>\r\n @if (expiredForm.get('coduser')?.invalid && expiredForm.get('coduser')?.touched) {\r\n <p class=\"auth-error\" @fadeInOut>El usuario es obligatorio</p>\r\n }\r\n\r\n <div class=\"auth-field\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-lock-open\"></i></span>\r\n <input [type]=\"passwordVisibility().claveAntigua ? 'text' : 'password'\"\r\n class=\"auth-input\" placeholder=\" \" maxlength=\"20\"\r\n formControlName=\"claveAntigua\" id=\"exp-old-pw\" autocomplete=\"new-password\">\r\n <label for=\"exp-old-pw\" class=\"auth-label\">Contraseña antigua</label>\r\n <button type=\"button\" class=\"auth-toggle-pw\" (click)=\"togglePassword('claveAntigua')\">\r\n <i [class]=\"passwordVisibility().claveAntigua ? 'fas fa-eye' : 'fas fa-eye-slash'\"></i>\r\n </button>\r\n </div>\r\n\r\n <div class=\"auth-field\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-lock\"></i></span>\r\n <input [type]=\"passwordVisibility().claveNueva ? 'text' : 'password'\"\r\n class=\"auth-input\" placeholder=\" \" maxlength=\"20\"\r\n formControlName=\"claveNueva\" id=\"exp-new-pw\" autocomplete=\"new-password\">\r\n <label for=\"exp-new-pw\" class=\"auth-label\">Contraseña nueva</label>\r\n <button type=\"button\" class=\"auth-toggle-pw\" (click)=\"togglePassword('claveNueva')\">\r\n <i [class]=\"passwordVisibility().claveNueva ? 'fas fa-eye' : 'fas fa-eye-slash'\"></i>\r\n </button>\r\n </div>\r\n\r\n @if (expiredForm.get('claveNueva')?.value?.length > 0) {\r\n <ul class=\"auth-validation-list\" @fadeInOut>\r\n @if (expiredForm.get('claveNueva')?.errors?.['minlength']) {\r\n <li>Al menos 8 caracteres</li>\r\n }\r\n @if (expiredForm.get('claveNueva')?.errors?.['minuscula']) {\r\n <li>Al menos 1 letra minúscula</li>\r\n }\r\n @if (expiredForm.get('claveNueva')?.errors?.['mayuscula']) {\r\n <li>Al menos 1 letra mayúscula</li>\r\n }\r\n @if (expiredForm.get('claveNueva')?.errors?.['numero']) {\r\n <li>Al menos 1 número</li>\r\n }\r\n @if (expiredForm.get('claveNueva')?.errors?.['especial']) {\r\n <li>Al menos 1 carácter especial</li>\r\n }\r\n </ul>\r\n }\r\n\r\n <div class=\"auth-field\"\r\n [class.has-error]=\"expiredForm.get('claveNuevaConfirmar')?.errors?.['coinciden'] && expiredForm.get('claveNuevaConfirmar')?.touched\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-check-circle\"></i></span>\r\n <input [type]=\"passwordVisibility().claveNuevaConfirmar ? 'text' : 'password'\"\r\n class=\"auth-input\" placeholder=\" \" maxlength=\"20\"\r\n formControlName=\"claveNuevaConfirmar\" id=\"exp-confirm-pw\" autocomplete=\"new-password\">\r\n <label for=\"exp-confirm-pw\" class=\"auth-label\">Confirmar contraseña</label>\r\n <button type=\"button\" class=\"auth-toggle-pw\" (click)=\"togglePassword('claveNuevaConfirmar')\">\r\n <i [class]=\"passwordVisibility().claveNuevaConfirmar ? 'fas fa-eye' : 'fas fa-eye-slash'\"></i>\r\n </button>\r\n </div>\r\n @if (expiredForm.get('claveNuevaConfirmar')?.errors?.['coinciden'] && expiredForm.get('claveNuevaConfirmar')?.touched) {\r\n <p class=\"auth-error\" @fadeInOut>Las contraseñas deben coincidir</p>\r\n }\r\n\r\n <button type=\"button\" class=\"auth-btn\" [class.auth-btn--red]=\"!produccion\"\r\n [disabled]=\"expiredForm.invalid\" (click)=\"recover()\">\r\n Renovar contraseña\r\n </button>\r\n\r\n <button type=\"button\" class=\"auth-btn auth-btn--outline\" (click)=\"back()\">\r\n Volver al inicio de sesión\r\n </button>\r\n\r\n </form>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n","import { Component, inject, input, output } from '@angular/core';\r\nimport { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';\r\nimport { AuthSender } from '../../models/auth-sender';\r\nimport { fadeInOut } from '../../utils/animations';\r\nimport { LoginEvent } from '../../models/login-event';\r\n\r\n@Component({\r\n selector: 'lib-recover-password',\r\n imports: [ReactiveFormsModule],\r\n templateUrl: './recover-password.component.html',\r\n styleUrls: ['./recover-password.component.scss', '../auth.scss'],\r\n animations: [fadeInOut]\r\n})\r\nexport class RecoverPasswordComponent {\r\n\r\n private fb = inject(FormBuilder)\r\n\r\n production = input<boolean>(true)\r\n module = input<string>('ERP') // DEFECTO ERP\r\n\r\n loginEvent = output<LoginEvent>()\r\n\r\n recoverForm = this.fb.group({\r\n ruc: ['', [Validators.required, Validators.minLength(11), Validators.maxLength(11)]],\r\n usuario: ['', Validators.required]\r\n })\r\n\r\n enviar = () => {\r\n if (this.recoverForm.invalid) {\r\n this.loginEvent.emit({ type: \"ERROR\", message: 'Debes completar todos los campos' })\r\n return\r\n }\r\n\r\n const formValues = this.recoverForm.value\r\n const sender: AuthSender = {\r\n ruc: formValues.ruc!,\r\n coduser: formValues.usuario!\r\n }\r\n\r\n this.loginEvent.emit({ type: \"RECOVER\", data: sender })\r\n }\r\n\r\n back = () => this.loginEvent.emit({ type: \"BACK\" })\r\n \r\n}\r\n","<div class=\"auth-wrapper-login\">\r\n @let produccion = production();\r\n <div class=\"auth-panel-left\" [class.auth-panel-left--dev]=\"!produccion\">\r\n <span class=\"auth-blob auth-blob-1\"></span>\r\n <span class=\"auth-blob auth-blob-2\"></span>\r\n <span class=\"auth-blob auth-blob-3\"></span>\r\n <span class=\"auth-blob auth-blob-4\"></span>\r\n\r\n <div class=\"auth-brand-panel\">\r\n <div class=\"auth-brand-logo\">\r\n <img src=\"assets/images/logo-tsi-tres.png\" alt=\"TSI\" />\r\n </div>\r\n <h1 class=\"auth-brand-title\">{{module()}}</h1>\r\n <p class=\"auth-brand-subtitle\">Recupera el acceso a tu cuenta de forma rápida y segura</p>\r\n\r\n <div class=\"auth-brand-divider\"></div>\r\n\r\n <div class=\"auth-brand-features\">\r\n <div class=\"auth-brand-feature\">\r\n <span class=\"feat-dot\"></span> Verificación por correo electrónico\r\n </div>\r\n <div class=\"auth-brand-feature\">\r\n <span class=\"feat-dot\"></span> Proceso seguro y encriptado\r\n </div>\r\n <div class=\"auth-brand-feature\">\r\n <span class=\"feat-dot\"></span> Nueva clave en minutos\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"auth-panel-right\" [class.auth-panel-right--dev]=\"!produccion\">\r\n <div class=\"auth-panel-bg\">\r\n <span class=\"auth-deco auth-deco-tl\"></span>\r\n <span class=\"auth-deco auth-deco-br\"></span>\r\n </div>\r\n\r\n <div class=\"auth-form-wrapper\">\r\n <div>\r\n @if (!produccion) {\r\n <div>\r\n <span class=\"auth-test-badge\">\r\n <span class=\"badge-dot\"></span> ENTORNO DE PRUEBAS\r\n </span>\r\n </div>\r\n }\r\n\r\n <div class=\"auth-card\">\r\n <h2 class=\"auth-card-title\">Recuperar contraseña</h2>\r\n <p class=\"auth-card-subtitle\">\r\n Confírmanos tu RUC y usuario. Enviaremos a tu correo registrado la nueva contraseña.\r\n </p>\r\n\r\n <form [formGroup]=\"recoverForm\">\r\n\r\n <div class=\"auth-field\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-building\"></i></span>\r\n <input type=\"text\" class=\"auth-input\" placeholder=\" \" maxlength=\"11\" formControlName=\"ruc\"\r\n id=\"rec-ruc\" onlyNumber autocomplete=\"off\">\r\n <label for=\"rec-ruc\" class=\"auth-label\">RUC</label>\r\n </div>\r\n\r\n <div class=\"auth-field\">\r\n <span class=\"auth-field-icon\"><i class=\"fas fa-user\"></i></span>\r\n <input type=\"text\" class=\"auth-input\" placeholder=\" \" formControlName=\"usuario\"\r\n id=\"rec-user\" autocomplete=\"off\">\r\n <label for=\"rec-user\" class=\"auth-label\">Usuario</label>\r\n </div>\r\n\r\n <button type=\"button\" class=\"auth-btn\" [class.auth-btn--red]=\"!produccion\"\r\n [disabled]=\"recoverForm.invalid\" (click)=\"enviar()\">\r\n Enviar instrucciones\r\n </button>\r\n\r\n <button type=\"button\" class=\"auth-btn auth-btn--outline\" (click)=\"back()\">\r\n Volver al inicio de sesión\r\n </button>\r\n\r\n </form>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>","import { Component, computed, HostListener, input, model, output } from '@angular/core';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { LoginEvent } from '../../models/login-event';\r\n\r\n@Component({\r\n selector: 'lib-select-branch',\r\n imports: [FormsModule],\r\n templateUrl: './select-branch.component.html',\r\n styleUrls: ['./select-branch.component.scss', '../auth.scss']\r\n})\r\nexport class SelectBranchComponent {\r\n\r\n production = input<boolean>(true)\r\n module = input<string>('ERP') // DEFECTO ERP\r\n title = computed(() => this.production() ? `MÓDULO: ${this.module()}` : `MÓDULO DE PRUEBA: ${this.module()}`)\r\n\r\n codsuc = model<number>(-1)\r\n sucursalesList = input<any[]>([])\r\n\r\n loginEvent = output<LoginEvent>()\r\n\r\n @HostListener('document:keydown', ['$event'])\r\n handleEnter(_event: KeyboardEvent) {\r\n if(_event.key !== 'Enter') return\r\n if (!this.codsuc) {\r\n return\r\n }\r\n this.goMain()\r\n }\r\n\r\n goMain = () => {\r\n this.loginEvent.emit({type: \"BRANCH\", data: { codsuc: this.codsuc() }})\r\n }\r\n}\r\n","<div class=\"auth-wrapper-login\">\r\n @let produccion = production();\r\n <div class=\"auth-panel-left\" [class.auth-panel-left--dev]=\"!produccion\">\r\n <span class=\"auth-blob auth-blob-1\"></span>\r\n <span class=\"auth-blob auth-blob-2\"></span>\r\n <span class=\"auth-blob auth-blob-3\"></span>\r\n <span class=\"auth-blob auth-blob-4\"></span>\r\n\r\n <div class=\"auth-brand-panel\">\r\n <div class=\"auth-brand-logo\">\r\n <img src=\"assets/images/logo-tsi-tres.png\" alt=\"TSI\" />\r\n </div>\r\n <h1 class=\"auth-brand-title\">{{module()}}</h1>\r\n <p class=\"auth-brand-subtitle\">Selecciona la sucursal desde donde vas a operar hoy</p>\r\n\r\n <div class=\"auth-brand-divider\"></div>\r\n\r\n <div class=\"auth-brand-features\">\r\n <div class=\"auth-brand-feature\">\r\n <span class=\"feat-dot\"></span> Acceso segmentado por sucursal\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"auth-panel-right\" [class.auth-panel-right--dev]=\"!produccion\">\r\n <div class=\"auth-panel-bg\">\r\n <span class=\"auth-deco auth-deco-tl\"></span>\r\n <span class=\"auth-deco auth-deco-br\"></span>\r\n </div>\r\n\r\n <div class=\"auth-form-wrapper\">\r\n <div>\r\n @if (!produccion) {\r\n <div>\r\n <span class=\"auth-test-badge\">\r\n <span class=\"badge-dot\"></span> ENTORNO DE PRUEBAS\r\n </span>\r\n </div>\r\n }\r\n\r\n <div class=\"auth-card\">\r\n <h2 class=\"auth-card-title\">Seleccionar sucursal</h2>\r\n <p class=\"auth-card-subtitle\">{{title()}}</p>\r\n\r\n <select class=\"auth-select\" [(ngModel)]=\"codsuc\">\r\n @for (suc of sucursalesList(); track $index) {\r\n <option [value]=\"suc.codsuc\">{{suc.sucursal}}</option>\r\n }\r\n </select>\r\n\r\n <button class=\"auth-btn\" [class.auth-btn--red]=\"!produccion\" (click)=\"goMain()\">\r\n Continuar\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>","export class AuthSender {\r\n ruc?: string\r\n coduser?: string\r\n clave?: string\r\n nuevaclave?: string\r\n producto?: string\r\n codsuc?: number\r\n}","import { InjectionToken, Provider } from '@angular/core'\n\nexport interface MfaChallengeResponse {\n mfaRequerido: boolean\n preauthToken: string\n coduser?: string\n empresa?: string\n mensaje?: string\n tipos?: string[]\n}\n\nexport interface MfaLoginSender {\n preauthToken: string\n codigo?: string\n solicitudId?: string\n}\n\nexport interface MfaPushEstadoPendiente {\n result: 'waiting' | 'deny' | 'expired'\n}\n\nexport type MfaEstadoPush = 'aprobado' | 'waiting' | 'deny' | 'expired'\n\nexport interface MfaApi {\n verificarCodigo(sender: MfaLoginSender): Promise<void>\n enviarPush(preauthToken: string): Promise<string>\n estadoPush(sender: MfaLoginSender): Promise<MfaEstadoPush>\n}\n\nexport const MFA_API = new InjectionToken<MfaApi>('MFA_API')\n\nexport function provideMfaApi(factory: () => MfaApi): Provider {\n return { provide: MFA_API, useFactory: factory }\n}\n\nexport function isMfaChallenge(body: any): body is MfaChallengeResponse {\n return body?.mfaRequerido === true && !!body?.preauthToken\n}\n\nexport function isPushPendiente(body: any): body is MfaPushEstadoPendiente {\n return body?.result === 'waiting' || body?.result === 'deny' || body?.result === 'expired'\n}\n","import { afterRenderEffect, Component, computed, DestroyRef, effect, ElementRef, inject, input, output, signal, untracked, viewChild } from '@angular/core';\nimport { MFA_API, MfaChallengeResponse, MfaEstadoPush } from '../../models/verificar-mfa';\n\ntype ModoVerificacion = 'codigo' | 'push'\ntype TipoCodigo = 'totp' | 'respaldo'\ntype EstadoPush = 'idle' | 'enviando' | 'esperando' | 'rechazado' | 'expirado'\n\nconst INTERVALO_ESTADO_MS = 2000\nconst MAXIMO_ESPERA_MS = 120000\n\ninterface CampoCodigo {\n label: string\n placeholder: string\n descri: string\n icon: string\n inputmode: string\n patron: RegExp\n mensajeInvalido: string\n mensajeIncorrecto: string\n}\n\nconst CAMPOS_CODIGO: Record<TipoCodigo, CampoCodigo> = {\n totp: {\n label: 'Código de verificación', placeholder: '000000', icon: 'fa-mobile-alt', inputmode: 'numeric',\n patron: /^\\d{6}$/,\n descri: 'Ingresa el código de 6 dígitos que muestra tu app de autenticación.',\n mensajeInvalido: 'Ingresa el código de 6 dígitos de tu app.',\n mensajeIncorrecto: 'Código incorrecto. Verifica la hora de tu dispositivo.'\n },\n respaldo: {\n label: 'Código de respaldo', placeholder: 'XXXX-XXXX', icon: 'fa-key', inputmode: 'text',\n patron: /^[A-Z0-9]{4}-[A-Z0-9]{4}$/,\n descri: 'Ingresa uno de tus códigos de respaldo. Cada código sirve una sola vez.',\n mensajeInvalido: 'Ingresa un código de respaldo válido (XXXX-XXXX).',\n mensajeIncorrecto: 'Código de respaldo incorrecto o ya utilizado.'\n }\n}\n\nconst limpiarCodigo = (valor: string, tipo: TipoCodigo) => {\n if (tipo == 'totp') return valor.replace(/\\D/g, '').slice(0, 6)\n const base = valor.toUpperCase().replace(/[^A-Z0-9]/g, '').slice(0, 8)\n return base.length > 4 ? `${base.slice(0, 4)}-${base.slice(4)}` : base\n}\n\nconst mensajeDe = (err: unknown, defecto: string) => typeof err == 'string' && err ? err : defecto\n\nconst esperar = (ms: number, signal: AbortSignal) => new Promise<void>(resolve => {\n const id = setTimeout(resolve, ms)\n signal.addEventListener('abort', () => { clearTimeout(id); resolve() }, { once: true })\n})\n\n@Component({\n selector: 'lib-md-verificar-mfa',\n templateUrl: './md-verificar-mfa.component.html',\n styleUrls: ['./md-verificar-mfa.component.scss', '../auth.scss']\n})\nexport class MdVerificarMfaComponent {\n\n private api = inject(MFA_API)\n\n challenge = input.required<MfaChallengeResponse>()\n titulo = input<string>('Verificación en dos pasos')\n showCancelar = input<boolean>(true)\n\n verificado = output<void>()\n cancelado = output<void>()\n\n tienePush = computed(() => (this.challenge().tipos ?? []).includes('PUSH'))\n tieneTotp = computed(() => {\n const tipos = this.challenge().tipos ?? []\n return tipos.length == 0 || tipos.includes('TOTP')\n })\n\n modo = signal<ModoVerificacion>('codigo')\n tipoCodigo = signal<TipoCodigo>('totp')\n campo = computed(() => CAMPOS_CODIGO[this.tipoCodigo()])\n\n codigo = signal<string>('')\n codigoError = signal<string>('')\n isEnviando = signal<boolean>(false)\n\n estadoPush = signal<EstadoPush>('idle')\n isPushEnCurso = computed(() => this.estadoPush() == 'enviando' || this.estadoPush() == 'esperando')\n pushError = signal<string>('')\n\n private inputCodigo = viewChild<ElementRef<HTMLInputElement>>('inputCodigo')\n private pushCtrl?: AbortController\n\n constructor() {\n inject(DestroyRef).onDestroy(() => this.cancelarPush())\n\n effect(() => {\n this.challenge()\n untracked(() => this.iniciar())\n })\n\n afterRenderEffect(() => {\n if (this.modo() != 'codigo' || this.isEnviando()) return\n this.tipoCodigo()\n this.codigoError()\n this.inputCodigo()?.nativeElement.focus()\n })\n }\n\n private iniciar() {\n this.cancelarPush()\n this.pushError.set('')\n if (this.tienePush() && !this.tieneTotp()) {\n this.usarPush()\n return\n }\n this.usarCodigo('totp')\n }\n\n onCodigoInput(event: Event) {\n const input = event.target as HTMLInputElement\n const limpio = limpiarCodigo(input.value, this.tipoCodigo())\n input.value = limpio\n this.codigo.set(limpio)\n if (this.codigoError()) this.codigoError.set('')\n }\n\n usarCodigo(tipo: TipoCodigo) {\n this.cancelarPush()\n this.modo.set('codigo')\n this.tipoCodigo.set(tipo)\n this.codigo.set('')\n this.codigoError.set('')\n }\n\n async verificar() {\n if (this.modo() == 'push' || this.isEnviando()) return\n const campo = this.campo()\n if (!campo.patron.test(this.codigo())) {\n this.codigoError.set(campo.mensajeInvalido)\n return\n }\n this.isEnviando.set(true)\n this.codigoError.set('')\n try {\n await this.api.verificarCodigo({ preauthToken: this.challenge().preauthToken, codigo: this.codigo() })\n this.verificado.emit()\n } catch (err) {\n this.codigo.set('')\n this.codigoError.set(mensajeDe(err, campo.mensajeIncorrecto))\n } finally {\n this.isEnviando.set(false)\n }\n }\n\n usarPush() {\n this.modo.set('push')\n this.codigoError.set('')\n this.enviarPush()\n }\n\n async enviarPush() {\n this.cancelarPush()\n const ctrl = new AbortController()\n this.pushCtrl = ctrl\n this.pushError.set('')\n this.estadoPush.set('enviando')\n const preauthToken = this.challenge().preauthToken\n\n try {\n const solicitudId = await this.api.enviarPush(preauthToken)\n if (ctrl.signal.aborted) return\n this.estadoPush.set('esperando')\n\n const limite = Date.now() + MAXIMO_ESPERA_MS\n while (Date.now() < limite) {\n const estado = await this.api.estadoPush({ preauthToken, solicitudId })\n if (ctrl.signal.aborted) return\n if (estado != 'waiting') {\n this.resolverPush(estado)\n return\n }\n await esperar(INTERVALO_ESTADO_MS, ctrl.signal)\n if (ctrl.signal.aborted) return\n }\n this.estadoPush.set('expirado')\n this.pushError.set('No respondiste a tiempo la notificación. Vuelve a enviarla.')\n } catch (err) {\n if (ctrl.signal.aborted) return\n this.estadoPush.set('idle')\n this.pushError.set(mensajeDe(err, 'No se pudo enviar la notificación.'))\n }\n }\n\n cancelar() {\n this.cancelarPush()\n this.cancelado.emit()\n }\n\n private resolverPush(estado: Exclude<MfaEstadoPush, 'waiting'>) {\n if (estado == 'aprobado') {\n this.estadoPush.set('idle')\n this.verificado.emit()\n return\n }\n if (estado == 'expired') {\n this.estadoPush.set('expirado')\n this.pushError.set('La solicitud expiró. Vuelve a enviarla.')\n return\n }\n this.estadoPush.set('rechazado')\n this.pushError.set('Rechazaste la notificación en tu teléfono.')\n }\n\n private cancelarPush() {\n this.pushCtrl?.abort()\n this.pushCtrl = undefined\n if (this.isPushEnCurso()) this.estadoPush.set('idle')\n }\n\n}\n","<div class=\"verificar-mfa\">\n <div class=\"auth-card-title mb-3\">{{ titulo() }}</div>\n\n <div class=\"d-flex align-items-center gap-3 mb-3\">\n <span class=\"verificar-mfa__icono\"><i class=\"fas fa-user-shield\"></i></span>\n <div>\n <div class=\"fw-semibold\">{{ challenge().coduser }}</div>\n @if (challenge().empresa) {\n <div class=\"verificar-mfa__muted\">{{ challenge().empresa }}</div>\n }\n </div>\n </div>\n\n @if (modo() == 'push') {\n @switch (estadoPush()) {\n @case ('enviando') {\n <div class=\"duo-push\">\n <span class=\"spinner-border spinner-border-sm text-primary\"></span>\n <div class=\"flex-grow-1\">Enviando notificación a tu teléfono…</div>\n </div>\n }\n @case ('esperando') {\n <div class=\"duo-push duo-push--esperando\">\n <span class=\"duo-push__icono duo-push__icono--pulso\"><i class=\"fas fa-mobile-alt\"></i></span>\n <div class=\"flex-grow-1\">\n <div class=\"fw-semibold\">Revisa tu teléfono</div>\n <div class=\"verificar-mfa__muted\">Aprueba la notificación en TSI Autenticador para ingresar.</div>\n </div>\n </div>\n }\n @default {\n <div class=\"duo-push\">\n <span class=\"duo-push__icono\"><i class=\"fas fa-bell\"></i></span>\n <div class=\"flex-grow-1\">\n <div class=\"fw-semibold\">TSI Autenticador</div>\n <div class=\"verificar-mfa__muted\">Te enviaremos una notificación para que la apruebes.</div>\n </div>\n </div>\n }\n }\n @if (pushError() && !isPushEnCurso()) {\n <div class=\"codigo-field__error\"><i class=\"fas fa-exclamation-circle\"></i> {{ pushError() }}</div>\n }\n\n <div class=\"verificar-mfa__opciones\">\n @if (tieneTotp()) {\n <button type=\"button\" class=\"verificar-mfa__link\" (click)=\"usarCodigo('totp')\">\n Usar código de mi app de autenticación\n </button>\n }\n <button type=\"button\" class=\"verificar-mfa__link verificar-mfa__link--secundario\"\n (click)=\"usarCodigo('respaldo')\">\n ¿No tienes tu teléfono? Usa un código de respaldo\n </button>\n </div>\n } @else {\n <p class=\"verificar-mfa__muted mb-4\">\n @if (tipoCodigo() == 'totp') {\n {{ challenge().mensaje || campo().descri }}\n } @else {\n {{ campo().descri }}\n }\n </p>\n\n <div class=\"codigo-field\" [class.has-error]=\"codigoError()\">\n <span class=\"codigo-field__icon\"><i class=\"fas\" [class]=\"campo().icon\"></i></span>\n <input #inputCodigo id=\"mfa-codigo\" class=\"codigo-field__input\" type=\"text\"\n [placeholder]=\"campo().placeholder\" [value]=\"codigo()\" (input)=\"onCodigoInput($event)\"\n (keydown.enter)=\"verificar()\" [attr.inputmode]=\"campo().inputmode\" autocomplete=\"one-time-code\"\n autocorrect=\"off\" autocapitalize=\"characters\" spellcheck=\"false\" [disabled]=\"isEnviando()\">\n <label for=\"mfa-codigo\" class=\"codigo-field__label\">{{ campo().label }}</label>\n </div>\n @if (codigoError()) {\n <div class=\"codigo-field__error\"><i class=\"fas fa-exclamation-circle\"></i> {{ codigoError() }}</div>\n }\n\n <div class=\"verificar-mfa__opciones\">\n @if (tienePush()) {\n <button type=\"button\" class=\"verificar-mfa__link\" (click)=\"usarPush()\">\n <i class=\"fas fa-bell me-1\"></i>Mejor envíame una notificación push\n </button>\n }\n @if (tieneTotp() && tipoCodigo() != 'totp') {\n <button type=\"button\" class=\"verificar-mfa__link\" (click)=\"usarCodigo('totp')\">\n Usar código de mi app de autenticación\n </button>\n }\n @if (tipoCodigo() != 'respaldo') {\n <button type=\"button\" class=\"verificar-mfa__link verificar-mfa__link--secundario\"\n (click)=\"usarCodigo('respaldo')\">\n ¿No tienes tu teléfono? Usa un código de respaldo\n </button>\n }\n </div>\n }\n\n <div class=\"verificar-mfa__acciones\">\n @if (modo() == 'push') {\n <button type=\"button\" class=\"auth-btn\" [disabled]=\"isPushEnCurso()\" (click)=\"enviarPush()\">\n <i class=\"fas fa-paper-plane me-1\"></i>\n {{ isPushEnCurso() ? 'Esperando aprobación…' : 'Reenviar notificación' }}\n </button>\n } @else {\n <button type=\"button\" class=\"auth-btn\" [disabled]=\"isEnviando()\" (click)=\"verificar()\">\n <i class=\"fas fa-check me-1\"></i>\n {{ isEnviando() ? 'Verificando…' : 'Verificar' }}\n </button>\n }\n @if (showCancelar()) {\n <button type=\"button\" class=\"auth-btn auth-btn--outline\" (click)=\"cancelar()\">Cancelar</button>\n }\n </div>\n</div>\n","/*\r\n * Public API Surface of login-tsi\r\n */\r\n\r\nexport * from './lib/components/auth/auth.component';\r\nexport * from './lib/components/expired-password/expired-password.component';\r\nexport * from './lib/components/recover-password/recover-password.component';\r\nexport * from './lib/components/select-branch/select-branch.component';\r\nexport * from './lib/models/auth-sender';\r\nexport * from './lib/models/login-event';\r\nexport * from './lib/models/login-type-event';\r\n\r\n// PWA (instalación, guía, actualización/refresh forzado)\r\nexport * from './lib/components/pwa-floating/pwa-floating.component';\r\nexport * from './lib/components/refresh-floating/refresh-floating.component';\r\nexport * from './lib/pwa-install.service';\nexport * from './lib/components/md-verificar-mfa/md-verificar-mfa.component';\nexport * from './lib/models/verificar-mfa';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { MfaChallengeResponse } from '../../models/verificar-mfa';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
type ModoVerificacion = 'codigo' | 'push';
|
|
4
|
+
type TipoCodigo = 'totp' | 'respaldo';
|
|
5
|
+
type EstadoPush = 'idle' | 'enviando' | 'esperando' | 'rechazado' | 'expirado';
|
|
6
|
+
interface CampoCodigo {
|
|
7
|
+
label: string;
|
|
8
|
+
placeholder: string;
|
|
9
|
+
descri: string;
|
|
10
|
+
icon: string;
|
|
11
|
+
inputmode: string;
|
|
12
|
+
patron: RegExp;
|
|
13
|
+
mensajeInvalido: string;
|
|
14
|
+
mensajeIncorrecto: string;
|
|
15
|
+
}
|
|
16
|
+
export declare class MdVerificarMfaComponent {
|
|
17
|
+
private api;
|
|
18
|
+
challenge: import("@angular/core").InputSignal<MfaChallengeResponse>;
|
|
19
|
+
titulo: import("@angular/core").InputSignal<string>;
|
|
20
|
+
showCancelar: import("@angular/core").InputSignal<boolean>;
|
|
21
|
+
verificado: import("@angular/core").OutputEmitterRef<void>;
|
|
22
|
+
cancelado: import("@angular/core").OutputEmitterRef<void>;
|
|
23
|
+
tienePush: import("@angular/core").Signal<boolean>;
|
|
24
|
+
tieneTotp: import("@angular/core").Signal<boolean>;
|
|
25
|
+
modo: import("@angular/core").WritableSignal<ModoVerificacion>;
|
|
26
|
+
tipoCodigo: import("@angular/core").WritableSignal<TipoCodigo>;
|
|
27
|
+
campo: import("@angular/core").Signal<CampoCodigo>;
|
|
28
|
+
codigo: import("@angular/core").WritableSignal<string>;
|
|
29
|
+
codigoError: import("@angular/core").WritableSignal<string>;
|
|
30
|
+
isEnviando: import("@angular/core").WritableSignal<boolean>;
|
|
31
|
+
estadoPush: import("@angular/core").WritableSignal<EstadoPush>;
|
|
32
|
+
isPushEnCurso: import("@angular/core").Signal<boolean>;
|
|
33
|
+
pushError: import("@angular/core").WritableSignal<string>;
|
|
34
|
+
private inputCodigo;
|
|
35
|
+
private pushCtrl?;
|
|
36
|
+
constructor();
|
|
37
|
+
private iniciar;
|
|
38
|
+
onCodigoInput(event: Event): void;
|
|
39
|
+
usarCodigo(tipo: TipoCodigo): void;
|
|
40
|
+
verificar(): Promise<void>;
|
|
41
|
+
usarPush(): void;
|
|
42
|
+
enviarPush(): Promise<void>;
|
|
43
|
+
cancelar(): void;
|
|
44
|
+
private resolverPush;
|
|
45
|
+
private cancelarPush;
|
|
46
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<MdVerificarMfaComponent, never>;
|
|
47
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<MdVerificarMfaComponent, "lib-md-verificar-mfa", never, { "challenge": { "alias": "challenge"; "required": true; "isSignal": true; }; "titulo": { "alias": "titulo"; "required": false; "isSignal": true; }; "showCancelar": { "alias": "showCancelar"; "required": false; "isSignal": true; }; }, { "verificado": "verificado"; "cancelado": "cancelado"; }, never, never, true, never>;
|
|
48
|
+
}
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { InjectionToken, Provider } from '@angular/core';
|
|
2
|
+
export interface MfaChallengeResponse {
|
|
3
|
+
mfaRequerido: boolean;
|
|
4
|
+
preauthToken: string;
|
|
5
|
+
coduser?: string;
|
|
6
|
+
empresa?: string;
|
|
7
|
+
mensaje?: string;
|
|
8
|
+
tipos?: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface MfaLoginSender {
|
|
11
|
+
preauthToken: string;
|
|
12
|
+
codigo?: string;
|
|
13
|
+
solicitudId?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface MfaPushEstadoPendiente {
|
|
16
|
+
result: 'waiting' | 'deny' | 'expired';
|
|
17
|
+
}
|
|
18
|
+
export type MfaEstadoPush = 'aprobado' | 'waiting' | 'deny' | 'expired';
|
|
19
|
+
export interface MfaApi {
|
|
20
|
+
verificarCodigo(sender: MfaLoginSender): Promise<void>;
|
|
21
|
+
enviarPush(preauthToken: string): Promise<string>;
|
|
22
|
+
estadoPush(sender: MfaLoginSender): Promise<MfaEstadoPush>;
|
|
23
|
+
}
|
|
24
|
+
export declare const MFA_API: InjectionToken<MfaApi>;
|
|
25
|
+
export declare function provideMfaApi(factory: () => MfaApi): Provider;
|
|
26
|
+
export declare function isMfaChallenge(body: any): body is MfaChallengeResponse;
|
|
27
|
+
export declare function isPushPendiente(body: any): body is MfaPushEstadoPendiente;
|
package/package.json
CHANGED
package/public-api.d.ts
CHANGED
|
@@ -8,3 +8,5 @@ export * from './lib/models/login-type-event';
|
|
|
8
8
|
export * from './lib/components/pwa-floating/pwa-floating.component';
|
|
9
9
|
export * from './lib/components/refresh-floating/refresh-floating.component';
|
|
10
10
|
export * from './lib/pwa-install.service';
|
|
11
|
+
export * from './lib/components/md-verificar-mfa/md-verificar-mfa.component';
|
|
12
|
+
export * from './lib/models/verificar-mfa';
|