Mejorando la Experiencia de Inicio de Sesión: Simulando Actividad con Mensajes Dinámicos

En el mundo de la tecnología, la primera impresión es crucial. En un proceso de inicio de sesión de aplicación web, a menudo se recurre a la típica barra de progreso o al icónico spinner de carga para mantener a los usuarios informados sobre el progreso de la autenticación. Sin embargo, hoy queremos presentar una técnica más interesante y atractiva inspirada en juegos como The Sims: la simulación de actividad con mensajes dinámicos.

El codigo que os muestro es real y esta en producción, concretamente en el login de SWPanel de la empresa SW Hosting (espero que si leen el artículo no se enfaden 😄)

Manteniendo al Usuario Entretenido durante el Inicio de Sesión:

En lugar de hacer que los usuarios observen pasivamente una barra de progreso, ¿por qué no darles la sensación de que la aplicación está ocupada realizando múltiples tareas? Esta técnica simula actividad y proporciona una experiencia más interactiva y atractiva.

El Código en Acción:

A continuación, presentaremos el código JavaScript que permite simular mensajes de carga en un proceso de inicio de sesión. Esto es especialmente útil cuando se trata de aplicaciones que pueden tener una autenticación más larga y compleja. Los usuarios sentirán que algo está sucediendo en segundo plano.

function cambio_estado_login(tipo) {
    var temps = 2e3;

    if (document.getElementById('info_login_status')) {
        if (tipo == '2') {
            texto = login_texto_2fa;
        } else {
            texto = login_texto_1;
        }
        clearInterval(timer_status_login);

        var texto_load = texto.split(',');
        text_info_login_status += 1;

        if (text_info_login_status >= texto_load.length) {
            if (tipo == '2') {
                text_info_login_status = 0;
            } else {
                text_info_login_status = 0;
            }
            document.getElementById('info_login_status').innerHTML =
                texto_load[text_info_login_status];
        } else {
            document.getElementById('info_login_status').innerHTML =
                texto_load[text_info_login_status];
            timer_status_login = setInterval(function () {
                cambio_estado_login(tipo);
            }, temps);
        }
    }
}

var login_texto_1='Validando acceso SWPanel';
	login_texto_1 = login_texto_1 + ',' + 'Generando conexión segura de acceso'
	login_texto_1 = login_texto_1 + ',' + 'Cargando configuración de cuenta de cliente'
	login_texto_1 = login_texto_1 + ',' + 'Cargando datos personalizados de entorno'
	login_texto_1 = login_texto_1 + ',' + 'Personalizando tu SWPanel'
	login_texto_1 = login_texto_1 + ',' + 'Analizando servicios activos y recursos'
	login_texto_1 = login_texto_1 + ',' + 'Analizando uso de recursos de los servicios activos'
	login_texto_1 = login_texto_1 + ',' + 'Analizando servicios de Cloud'
	login_texto_1 = login_texto_1 + ',' + 'Analizando escalabilidad y disponibilidad de Cloud'
	login_texto_1 = login_texto_1 + ',' + 'Estudiando opciones y oportunidades de mejora'
	login_texto_1 = login_texto_1 + ',' + 'Analizando cartera de dominios'
	login_texto_1 = login_texto_1 + ',' + 'Preparando informes de caducidad de dominios'
	login_texto_1 = login_texto_1 + ',' + 'Analizando certificados SSL'
	login_texto_1 = login_texto_1 + ',' + 'Preparando informes de caducidad de SSL'
	login_texto_1 = login_texto_1 + ',' + 'Generando dashboard de SWPanel'
	login_texto_1 = login_texto_1 + ',' + 'Generando dashboards de servicios'
	login_texto_1 = login_texto_1 + ',' + 'Generando datos estadísticos'
	login_texto_1 = login_texto_1 + ',' + 'Generando entorno privado de soporte'
	login_texto_1 = login_texto_1 + ',' + 'Generando entorno privado de soporte'
	login_texto_1 = login_texto_1 + ',' + 'Actualizando cache de SWPanel'
	login_texto_1 = login_texto_1 + ',' + 'Revisando notificaciones pendientes'
	login_texto_1 = login_texto_1 + ',' + 'Revisando mensajes de soporte'
	login_texto_1 = login_texto_1 + ',' + 'Revisando estado de tu cuenta de cliente'
	login_texto_1 = login_texto_1 + ',' + 'Iniciando Interface de usuario de SWPanel'
	login_texto_1 = login_texto_1 + ',' + 'Aplicando perfiles de usuarios'
	login_texto_1 = login_texto_1 + ',' + 'Aplicando permisos de SWPanel'
	login_texto_1 = login_texto_1 + ',' + 'Aplicando seguridad'
	login_texto_1 = login_texto_1 + ',' + 'Analizando restricciones de acceso'
	login_texto_1 = login_texto_1 + ',' + 'Generando estadísticas e históricos de acceso'
	login_texto_1 = login_texto_1 + ',' + 'Generando identificador de sesión único'
	login_texto_1 = login_texto_1 + ',' + 'Iniciando tu SWPanel'
var login_texto_2fa = 'Iniciando verificación de doble factor';
	login_texto_2fa = login_texto_2fa + ',' + 'Validando códigos y tokens de seguridad'
	login_texto_2fa = login_texto_2fa + ',' + 'Comprobando identidad de acceso a SWPanel'
	login_texto_2fa = login_texto_2fa + ',' + 'Últimas validaciones de seguridad'
var text_contrato = 'Debes aceptar los términos del contrato de servicios.';

Cómo Funciona:

  • La función cambio_estado_login toma un argumento tipo, que determina los mensajes a mostrar.
  • Los mensajes se dividen en una matriz para que se puedan mostrar uno tras otro.
  • Se usa un contador para rastrear qué mensaje se mostrará a continuación.
  • Si se llega al final de la matriz de mensajes, el contador se reinicia.
  • Se configura un temporizador para llamar a la función nuevamente, simulando la animación de mensajes cambiantes.

Inspiración en The Sims:

Si alguna vez has jugado a The Sims, recordarás los mensajes extravagantes que aparecían en la parte inferior de la pantalla. Aunque exagerados, mantenían a los jugadores entretenidos mientras se realizaban tareas en el juego. Esta técnica toma inspiración de ese enfoque, adaptándolo de manera elegante y atractiva a un proceso de inicio de sesión en una aplicación.

En resumen, la simulación de mensajes de carga es una forma efectiva de mantener a tus usuarios entretenidos durante el proceso de inicio de sesión, proporcionando una experiencia más atractiva en lugar de una barra de progreso estática. Al tomar inspiración de juegos como The Sims, podemos mejorar la impresión del usuario y mantener su atención mientras la aplicación se autentica.

Cómo Filtrar y Gestionar Datos del Local Storage en JavaScript

En este artículo, exploraremos cómo filtrar y gestionar datos almacenados en el Local Storage de tu navegador web utilizando un script JavaScript. Descubre cómo aplicar expresiones regulares para seleccionar datos específicos y cómo calcular el tamaño del Local Storage. ¡Optimiza tus proyectos web y ofrece a tus usuarios una experiencia más eficiente!

Introducción

Aprenderemos a utilizar un script JavaScript para filtrar datos en el Local Storage y calcular su tamaño. Estos conocimientos son esenciales para el desarrollo de aplicaciones web y pueden marcar la diferencia en la experiencia del usuario. Expliquemos el funcionamiento de este script de manera accesible y amigable.

Filtrando Datos del Local Storage

El primer script que vamos a explorar se utiliza para filtrar datos específicos en el Local Storage. Aquí está el código:

const re = /[a-zA-Z]/g;

Object.keys(localStorage).forEach(function (key) {
  if (key.match(re)) {
    // Realizar alguna acción
  }
});

Vamos a analizarlo paso a paso para comprenderlo a fondo:

  1. const re = /[a-zA-Z]/g;: En esta línea, definimos una expresión regular que busca letras en mayúsculas y minúsculas. Este enfoque es fundamental para seleccionar datos específicos en el Local Storage.
  2. Object.keys(localStorage).forEach(function (key) { ... });: Aquí, obtenemos las claves almacenadas en el Local Storage y las recorremos usando un bucle forEach. Es un paso importante para acceder a los datos que deseamos filtrar.
  3. if (key.match(re)) { ... }: En cada iteración, comprobamos si la clave actual coincide con nuestra expresión regular utilizando el método match(). Si la clave contiene al menos una letra, ejecutamos un código personalizado dentro del bloque if.

Calculando el Tamaño del Local Storage

Añadiremos otro script que calcula el tamaño total del Local Storage y lo muestra en kilobytes (KB) o megabytes (MB). Aquí tienes el código:

var allStrings = '';
for (var key in window.localStorage) {
  if (window.localStorage.hasOwnProperty(key)) {
    allStrings += window.localStorage[key];
  }
}

let size = 3 + (allStrings.length * 16) / (8 * 1024);

if (size > 1024) {
  this.localStorageSize = Math.ceil(size / 1024) + ' MB';
} else {
  this.localStorageSize = allStrings
    ? Math.ceil(3 + (allStrings.length * 16) / (8 * 1024)) + ' KB'
    : '0 KB';
}

Este script recorre todas las claves del Local Storage, recopila sus valores y calcula el tamaño total en KB o MB. Esto es útil para monitorear y gestionar el espacio utilizado por tus datos almacenados en el navegador.

Uso y Personalización

Puedes personalizar estos scripts según tus necesidades. Además de realizar una «acción» en el primer script, ahora también puedes mostrar el tamaño total del Local Storage a tus usuarios. Esto es útil para mantener un control sobre el espacio de almacenamiento y tomar decisiones informadas.

.woff2 Failed to load resource 404 NOT FOUND

Me he encontrado un error «común» en diferentes aplicaciones con Angular al colgarlas en servidores IIS. No es un fallo muy importante, pero puede sacar de quicio solucionarlo, ya que cuando debugas en local, no aparece este error.

Para solucionar este error, simplemente debes definir la extensión .woff2 con el mimeType «application/font-woff2» en el IIS.

Para hacer esto simplemente acudimos a la configuración mime del sitio web.

Alternativamente (y mi preferida) puedes establecer esta configuración en el webconfig, de esta manera no necesitarás tocar configuraciones del servidor (perfecto si no tienes acceso a la administración de IIS) y podrás mover la web de un lugar a otro con la seguridad de que funciona.

<system.webServer>
  <staticContent>
    <remove fileExtension=".woff2" />
    <mimeMap fileExtension=".woff2" mimeType="font/woff2" />
  </staticContent>
</system.webServer>

Espero que te sea útil !

Lazy Loading en Angular

¿Para qué necesito Lazy Loading?

La mayoría de veces que creamos un proyecto en Angular (o al menos en mi caso) nos interesa que la aplicación cargue de una sola vez, de manera que sacrificando un pequeño período de tiempo al inicio, conseguimos que la velocidad y la fluidez sea mucho mas alta durante el resto de la navegación.

Para aplicaciones web usadas dentro de una red local, esta opción es más que perfecta, pero ¿qué podemos hacer si nuestra aplicación crece mucho y sobrecarga el navegador? ¿y si un tipo de usuario concreto sólo debe acceder a una parte muy pequeña de la aplicación?

Este problema lo solucionamos usando Lazy Loading, que básicamente significa que la aplicación web no se cargará de una sola vez al arranque, si no que se irá cargando a demanda según la necesidad del usuario.

Empezando: las rutas

Para empezar a trabajar con Lazy Loading lo primero es entender como carga las rutas Angular.

Si ya tenemos un proyecto, vamos a abrir nuestro fichero de rutas y si no es así puedes crear un nuevo proyecto especificando  el parámetro –routing para que te genere automáticamente un fichero de rutas:

ng new --routing

En mi caso, mi fichero es el siguiente:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { InicioComponent } from './inicio/inicio/inicio.component';
import { GalleryShowComponent } from './gallery-show/gallery-show/gallery-show.component';
import { AboutComponent } from './about/about/about.component';
import { GallerySelectorComponent } from './gallery-selector/gallery-selector/gallery-selector.component';

const routes: Routes = [
{ path: 'informatica', loadChildren: './inicio/inicio.module#InicioModule' },
{ path: 'gallery/view', loadChildren: './gallery-show/gallery-show.module#GalleryShowModule' },
{ path: 'about', loadChildren: './about/about.module#AboutModule' },
{ path: 'gallery', loadChildren: './gallery-selector/gallery-selector.module#GallerySelectorModule' },
{ path: '**', redirectTo: '/informatica'}
];

@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }

Aquí lo que estamos viendo es que nuestro módulo de rutas define unas rutas concretas para las diferentes páginas que tendremos, pero en lugar de referenciar una ruta a un componente, lo estamos referenciando a un módulo. Vamos a fijarnos en la galaeria (por ejemplo):

{ path: 'gallery', loadChildren: './gallery-selector/gallery-selector.module#GallerySelectorModule' },

Tenemos por un lado el path, donde especificamos la url y en loadChildren escribiremos la ruta al archivo del módulo que contiene nuestros componentes para esa página. La sintaxis especifica después de la ruta el nombre del módulo (separado por una ‘#’.

LoadChildren lo que nos indica es que el módulo tendrá sus propias rutas definidas, por lo que no las cargamos, simplemente cuando las necesitemos ya las buscará.

Fíjate que cargamos ya los componentes que forman parte de los módulos que vamos a usar.

Hasta aquí fácil no?

Creando nuestros módulos

Ahora tendremos que definir nuestros módulos y escribir en ellos las rutas que cargaremos. Para seguir con el ejemplo, os pondré el contenido del módulo gallery-selector (es el que esta funcionando en esta misma web 😀 )

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { GallerySelectorComponent } from './gallery-selector/gallery-selector.component';
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [
  { path: '', component: GallerySelectorComponent},
];


@NgModule({
  imports: [
    CommonModule, RouterModule.forChild(routes)
  ],
  declarations: [GallerySelectorComponent]
})
export class GallerySelectorModule { }

En este fichero debemos fijarnos sobre todo en cuatro cosas:

  • Importamos los componentes que vamos a usar y forman parte del módulo
  • Definimos una variable routes con las rutas definitivas
  • Importamos Routes y RouterModule
  • Añadimos en imports «RouterModule.forChild(routes)» para que las rutas estén disponibles cuando el archivo de rutas maestro lo consulte.

 

Comandos útiles:

//Generar un módulo nuevo
ng generate module mi-modulo

//Cenerar un componente dentro de un módulo
ng generate component mi-modulo/mi-componente

Probando la configuración

Llegados a este punto nuestra aplicación ya empezará a generar el Lazy loading, pero y si queremos comprobar que realmente funciona?

Sólo tenemos que usar las herramientas de desarrollador de Chrome y fijarnos en las Request que se generan:

Como puedes ver se genera una serie de peticione sque cargan los JS inciales y sólo al visitar un álbum se genera la petición de gallery-show.module.chunk.js

Esto mismo puedes comprobarlo en el apartado de galeria de la web y verlo por ti mismo! (Recuerda que una vez compilado angular renombra los módulos con un hash!)

Como curiosidad, comentar que como convenio se suele poner un + en cada carpeta que contiene un módulo cargado por Lazy Loading. De esta manera tendremos contentos hasta a los más puritanos!