Auto-guardado local, no vuelvas a perder nada

Imagínate esta situación: estás trabajando en un informe importante en un editor en línea y, de repente, ¡la conexión a Internet se cae! ¿El resultado? Podrías perder todo tu trabajo. Para evitar este dolor de cabeza digital, el guardado local se convierte en tu mejor amigo. Así que, en un tono amigable y serio, exploremos esta característica y cómo funciona en un editor de informes en Angular.

El Guardado Local: Tu Compañero de Confianza

En este mundo de interrupciones y problemas técnicos constantes, el guardado local es como un héroe digital. Es una función que te permite guardar una copia de tu trabajo en tu dispositivo, asegurando que no se pierda en las nubes de Internet. El código que te voy a mostrar te enseña cómo implementar el guardado local en una aplicación Angular, especialmente en un editor de informes. ¿Las ventajas? Son muchas y muy valiosas.

1. Protección contra la Pérdida de Datos

Nada es más desalentador que perder horas de trabajo debido a problemas de conexión. Con el guardado local, esta pesadilla se desvanece. El código que vamos a ver se encarga de guardar automáticamente el informe en tu dispositivo, garantizando que tus datos estén a salvo, incluso cuando la tormenta digital hace de las suyas.

2. Flexibilidad y Continuidad

El guardado local también te da la libertad que necesitas. ¿Necesitas seguir trabajando en tu informe en un vuelo o en un lugar con una conexión limitada? No hay problema. Con el guardado local, puedes seguir trabajando sin problemas, sin importar dónde estés. Esto te asegura que tu trabajo siga avanzando sin contratiempos.

3. Protección contra Errores Humanos

Quién no ha borrado accidentalmente una sección importante de un informe o ha sobrescrito información crucial. Con el guardado local, los errores humanos son menos aterradores. El sistema te permite restaurar versiones anteriores de tu trabajo, lo que actúa como un salvavidas cuando cometes un error. Así, se reducen las situaciones de estrés y desesperación.

4. Ahorro de Tiempo y Estrés

La amenaza constante de perder datos puede ser estresante y llevar a perder tiempo valioso. El guardado local, en cambio, te ofrece tranquilidad al asegurarte de que tus datos estén respaldados en tu propio dispositivo. Esto ahorra tiempo y esfuerzo, algo realmente valioso en entornos profesionales y personales.

El Código en Acción: Implementación en Angular

Ahora que hemos hablado de los beneficios del guardado local, veamos cómo funciona en una aplicación Angular. En el componente «AutosaveComponent,» el código se encarga de guardar automáticamente el informe en tu dispositivo y de recuperar versiones anteriores en caso de problemas. A continuación, te muestro el código completo y una breve explicación de cómo funciona:

import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import * as moment from 'moment';
import { AuthUserService } from 'projects/cris9/src/app/services/authUser.service';

@Component({
  selector: "app-autosave",
  templateUrl: "./autosave.component.html",
  styleUrls: ["./autosave.component.css"],
})
export class AutosaveComponent implements OnInit {
  @Input()
  set report(value: string) {
    this._report = {report: value, TTL: moment().format("DD/MM/yyyy HH:mm:ss") };
  }

@Input() set report(value: string): Aquí definimos un «setter» para la entrada «report» que nos permite capturar el valor del informe y su marca de tiempo actual. Esto nos ayudará a mantener un registro de los cambios.

@Input() set AN(value: string) { this._AN = value; }

@Input() set AN(value: string): Similar al anterior, este «setter» captura el valor de «AN,» que es parte del contexto del informe.

@Output() restoreTemplate = new EventEmitter<string>();

@Output() restoreTemplate: Esta línea define un evento de salida que nos permitirá restaurar una versión anterior del informe si es necesario.

constructor(private _authUser: AuthUserService) {}

constructor(private _authUser: AuthUserService): Aquí estamos inyectando el servicio «_authUser» para poder utilizarlo en nuestras funciones.

  lastTime;
  lastResult: boolean;
  saving: boolean;
  notSavedYet;
  private _report;
  private _AN;
  private _refreshInterval;

Variables: Estamos declarando varias variables que se usarán en todo el componente para realizar un seguimiento del estado del guardado y la información del informe.

  ngOnInit(): void {
    // Verificar si existe un informe anterior
    if (this.checkExist()) {
      // Iniciar temporizador
      this._refreshInterval = setInterval(() => {
        this.autosave();
      }, 15000);
    }
  }

ngOnInit(): Esta es una función del ciclo de vida de Angular. Aquí comenzamos por verificar si existe un informe anterior (la función checkExist lo hará por nosotros). Si hay un informe anterior, iniciamos un temporizador para el guardado automático con un intervalo de 15 segundos (15000 milisegundos).

  checkExist(): Boolean {
    try {
      if (
        localStorage.getItem(this._authUser.getUser() + "-" + this._AN) !=
          null &&
        localStorage.getItem(
          this._authUser.getUser() + "-" + this._AN + "-" + "lastDate"
        ) != null
      ) {

checkExist(): Esta función verifica si existen datos previamente guardados. Revisamos si hay una entrada en el almacenamiento local para el usuario y para «AN» (parte del contexto del informe), así como la marca de tiempo de la última modificación.

        if (
          (JSON.stringify(JSON.parse(localStorage.getItem(this._authUser.getUser() + "-" + this._AN)).report) != JSON.stringify(this._report.report)) &&
          confirm(
            "Se ha encontrado una versión local del informe con fecha " +
              localStorage.getItem(
                this._authUser.getUser() + "-" + this._AN + "-" + "lastDate"
              ) + " que no ha sido guardada en el servidor." +
              "\n¿Quieres cargarla?\n\n" +
              "** Si no cargas el informe recuperado, se descartará y se sobrescribirá **"
          )
        ) {

Continuación de checkExist(): Aquí, comparamos el informe actual con el informe guardado localmente para ver si ha habido cambios. Si se detectan cambios, mostramos un mensaje de confirmación para cargar la versión local. Si el usuario confirma, recuperamos el informe local y actualizamos el estado.

          this._report = JSON.parse(
            localStorage.getItem(this._authUser.getUser() + "-" + this._AN)
          );
          this.lastTime = localStorage.getItem(
            this._authUser.getUser() + "-" + this._AN + "-" + "lastDate"
          );
          this.lastResult = true;
          this.notSavedYet = false;
          this.restoreTemplate.emit(JSON.stringify(this._report.report));
        }
      } else {
        localStorage.removeItem(this._authUser.getUser() + "-" + this._AN);
        localStorage.removeItem(
          this._authUser.getUser() + "-" + this._AN + "-" + "lastDate"
        );
        this.notSavedYet = true;
      }

Continuación de checkExist(): Si el usuario decide cargar la versión local, aquí actualizamos el estado del informe y marcamos que no se ha guardado aún en el servidor. Si no hay datos locales, eliminamos cualquier información antigua y marcamos que aún no se ha guardado.

      return true;
    } catch (exception) {
      console.log(exception);
      alert("Lo sentimos, se ha producido un error al recuperar el informe :(");
      localStorage.removeItem(this._authUser.getUser() + "-" + this._AN);
      localStorage.removeItem(
        this._authUser.getUser() + "-" + this._AN + "-" + "lastDate"
      );
      this.notSavedYet = true;
      return true;
    }
  }

Continuación de checkExist(): En caso de que ocurra algún error durante la verificación, manejamos la excepción y mostramos un mensaje de alerta. Luego, limpiamos los datos locales y marcamos que no se ha guardado.

autosave() {
    try {
      this.saving = true;
      localStorage.setItem(
        this._authUser.getUser() + "-" + this._AN,
           JSON.stringify(this._report));
      localStorage.setItem(
        this._authUser.getUser() + "-" + this._AN + "-" + "lastDate",
        moment().format("DD/MM/yyyy HH:mm:ss")
      );
      this.lastTime = moment().format("DD/MM/yyyy HH:mm:ss");
      this.lastResult = true;
      this.saving = false;
      this.notSavedYet = false;
    } catch (exception) {
      this.lastTime = moment().format("DD/MM/yyyy HH:mm:ss");
      this.lastResult = false;
      this sving = false;
      this.notSavedYet = false;
    }
  }
}

autosave(): Esta función se encarga de guardar automáticamente el informe en el dispositivo del usuario. Primero, marcamos que estamos en proceso de guardado y luego almacenamos el informe y la marca de tiempo en el almacenamiento local. Si todo va bien, actualizamos el estado y marcamos que no se ha guardado en el servidor. Si ocurre un error, manejamos la excepción y marcamos que no se ha guardado.

Conclusión

En resumen, el guardado local es una función esencial para garantizar la seguridad y la continuidad en la creación de informes en línea. Protege contra la pérdida de datos, ofrece flexibilidad, previene errores humanos y ahorra tiempo. La implementación de esta característica, como se muestra en el código de Angular, es una excelente decisión para crear un editor en línea más amigable y eficiente.

Nuestra intención es ayudarte a que tu experiencia en la creación de informes sea lo más agradable y sin preocupaciones posible. Con el guardado local, puedes estar seguro de que tu trabajo está en buenas manos, incluso cuando las nubes digitales amenazan con tormenta.

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.