201 lines
6.9 KiB
PHP
201 lines
6.9 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="es">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title><?php echo $_ENV['APP_NAME']; ?></title>
|
|
<!-- Bootstrap CSS -->
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
|
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
|
<!-- FontAwesome -->
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
|
<!-- Custom CSS -->
|
|
<link rel="stylesheet" href="/assets/css/main.css">
|
|
<!-- Fonts -->
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link
|
|
href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
|
|
rel="stylesheet">
|
|
|
|
<script>
|
|
// Precharged JS code for the app
|
|
|
|
/**
|
|
* @function showMessage
|
|
* @description Muestra un mensaje usando SweetAlert2
|
|
* @param {string} message - Mensaje a mostrar
|
|
* @param {string} [type='success'] - Tipo de mensaje ('success', 'error', etc.)
|
|
*/
|
|
const showMessage = (message, type = 'success') => {
|
|
Swal.fire({
|
|
toast: true,
|
|
position: 'top-end',
|
|
icon: type,
|
|
title: message,
|
|
showConfirmButton: false,
|
|
timer: 3000,
|
|
timerProgressBar: true,
|
|
});
|
|
};
|
|
|
|
/**
|
|
* @function formatDate
|
|
* @description Formatea una fecha en formato corto
|
|
* @param {string} dateStr - Fecha en formato ISO
|
|
* @returns {string} Fecha formateada
|
|
*/
|
|
const formatDate = (dateStr) => {
|
|
return new Date(dateStr).toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });
|
|
};
|
|
|
|
/**
|
|
* @function escapeHtml
|
|
* @description Escapa caracteres HTML para prevenir XSS
|
|
* @param {string} text - Texto a escapar
|
|
* @returns {string} Texto escapado
|
|
*/
|
|
const escapeHtml = (text) => {
|
|
const map = {
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>',
|
|
'"': '"',
|
|
"'": '''
|
|
};
|
|
return text.replace(/[&<>"']/g, (m) => map[m]);
|
|
};
|
|
|
|
/**
|
|
* @typedef {Object} StateManager
|
|
* @description Gestor de estado que maneja el almacenamiento y persistencia de datos de la aplicación
|
|
*/
|
|
const StateManager = (() => {
|
|
const state = {};
|
|
|
|
/**
|
|
* @private
|
|
* @function initialize
|
|
* @description Inicializa el estado desde localStorage si existen datos persistidos
|
|
* @returns {void}
|
|
*/
|
|
const initialize = () => {
|
|
const persistedState = JSON.parse(localStorage.getItem('appState'));
|
|
if (persistedState) {
|
|
Object.assign(state, persistedState);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @private
|
|
* @function persistState
|
|
* @description Persiste el estado actual en localStorage
|
|
* @returns {void}
|
|
*/
|
|
const persistState = () => {
|
|
localStorage.setItem('appState', JSON.stringify(state));
|
|
};
|
|
|
|
/**
|
|
* @function get
|
|
* @description Obtiene un valor del estado
|
|
* @param {string} key - Clave del valor a obtener
|
|
* @param {*} [defaultValue=null] - Valor por defecto si la clave no existe
|
|
* @returns {*} El valor almacenado o el valor por defecto
|
|
*/
|
|
const get = (key, defaultValue = null) => {
|
|
return state[key] !== undefined ? state[key] : defaultValue;
|
|
};
|
|
|
|
/**
|
|
* @function set
|
|
* @description Establece un valor en el estado y lo persiste
|
|
* @param {string} key - Clave bajo la cual almacenar el valor
|
|
* @param {*} value - Valor a almacenar
|
|
* @returns {void}
|
|
*/
|
|
const set = (key, value) => {
|
|
state[key] = value;
|
|
persistState();
|
|
};
|
|
|
|
/**
|
|
* @function update
|
|
* @description Actualiza propiedades específicas de un objeto en el estado
|
|
* @param {string} key - Clave del objeto a actualizar
|
|
* @param {Object} updates - Objeto con las actualizaciones a realizar
|
|
* @returns {void}
|
|
* @throws {Warning} Si el valor no es un objeto o no existe
|
|
*/
|
|
const update = (key, updates) => {
|
|
if (typeof state[key] === 'object' && !Array.isArray(state[key])) {
|
|
Object.assign(state[key], updates);
|
|
persistState();
|
|
} else {
|
|
console.warn(`El valor de ${key} no es un objeto o no existe.`);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @function remove
|
|
* @description Elimina una clave y su valor del estado
|
|
* @param {string} key - Clave a eliminar
|
|
* @returns {void}
|
|
*/
|
|
const remove = (key) => {
|
|
delete state[key];
|
|
persistState();
|
|
};
|
|
|
|
/**
|
|
* @function clear
|
|
* @description Limpia todo el estado y el almacenamiento persistente
|
|
* @returns {void}
|
|
*/
|
|
const clear = () => {
|
|
for (let key in state) {
|
|
delete state[key];
|
|
}
|
|
localStorage.removeItem('appState');
|
|
};
|
|
|
|
/**
|
|
* @function has
|
|
* @description Verifica si una clave existe en el estado
|
|
* @param {string} key - Clave a verificar
|
|
* @returns {boolean} True si la clave existe, false en caso contrario
|
|
*/
|
|
const has = (key) => {
|
|
return state.hasOwnProperty(key);
|
|
};
|
|
|
|
/**
|
|
* @function getState
|
|
* @description Obtiene una copia del estado completo
|
|
* @returns {Object} Copia del estado actual
|
|
*/
|
|
const getState = () => {
|
|
return { ...state };
|
|
};
|
|
|
|
// Inicializamos la store
|
|
initialize();
|
|
|
|
return {
|
|
get,
|
|
set,
|
|
update,
|
|
remove,
|
|
clear,
|
|
has,
|
|
getState,
|
|
};
|
|
})();
|
|
</script>
|
|
|
|
</head>
|
|
|
|
<body class="bg-body-secondary">
|
|
|
|
<?php include __DIR__ . "/../components/navbar.php"; ?>
|