310 lines
12 KiB
JavaScript
310 lines
12 KiB
JavaScript
// ================================
|
|
// DIARIO DE ORACIÓN
|
|
// Persistencia en API (con fallback a localStorage si no hay conexión).
|
|
// Requiere: api-config.js, auth.js
|
|
// ================================
|
|
|
|
const ESTADOS_DIARIO = {
|
|
paz: { icono: '🕊️', label: 'Paz' },
|
|
gratitud: { icono: '🙏', label: 'Gratitud' },
|
|
lucha: { icono: '😔', label: 'Lucha' },
|
|
gozo: { icono: '✨', label: 'Gozo' },
|
|
silencio: { icono: '🌿', label: 'Silencio' }
|
|
};
|
|
|
|
let _usuario = null;
|
|
let _fechaSeleccionada = null;
|
|
|
|
// Cache en memoria para evitar peticiones redundantes durante la sesión.
|
|
const _cache = {};
|
|
|
|
// ── INICIALIZACIÓN ──────────────────────────────────────────
|
|
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
_usuario = verificarAuth();
|
|
if (!_usuario) return;
|
|
|
|
const hoy = new Date();
|
|
_fechaSeleccionada = toFechaISO(hoy);
|
|
|
|
document.getElementById('saludo-usuario').textContent = saludoPersonal(_usuario.nombre, hoy);
|
|
document.getElementById('fecha-entrada').value = _fechaSeleccionada;
|
|
|
|
cargarEntrada(_fechaSeleccionada);
|
|
cargarListaEntradas();
|
|
|
|
document.getElementById('btn-guardar-entrada').addEventListener('click', guardarEntrada);
|
|
document.getElementById('btn-borrar-entrada').addEventListener('click', borrarEntrada);
|
|
document.getElementById('btn-anterior').addEventListener('click', () => navegarFecha(-1));
|
|
document.getElementById('btn-siguiente').addEventListener('click', () => navegarFecha(1));
|
|
|
|
document.getElementById('fecha-entrada').addEventListener('change', e => {
|
|
_fechaSeleccionada = e.target.value;
|
|
cargarEntrada(_fechaSeleccionada);
|
|
});
|
|
|
|
document.querySelectorAll('.btn-estado').forEach(btn => {
|
|
btn.addEventListener('click', () => seleccionarEstado(btn.dataset.estado));
|
|
});
|
|
});
|
|
|
|
// ── SALUDO ──────────────────────────────────────────────────
|
|
|
|
function saludoPersonal(nombre, fecha) {
|
|
const h = fecha.getHours();
|
|
const franja = h < 13 ? 'Buenos días' : h < 20 ? 'Buenas tardes' : 'Buenas noches';
|
|
return `${franja}, ${nombre}. Un momento de silencio contigo.`;
|
|
}
|
|
|
|
// ── API ─────────────────────────────────────────────────────
|
|
|
|
async function _apiGetEntrada(fecha) {
|
|
try {
|
|
const res = await apiCall(`/diario/${fecha}`);
|
|
if (!res) return null;
|
|
if (res.status === 404) return null;
|
|
if (!res.ok) throw new Error('Error al cargar entrada');
|
|
return await res.json();
|
|
} catch (e) {
|
|
return _localGetEntrada(fecha);
|
|
}
|
|
}
|
|
|
|
async function _apiGetTodas() {
|
|
try {
|
|
const res = await apiCall('/diario');
|
|
if (!res || !res.ok) throw new Error('Error al cargar entradas');
|
|
return await res.json();
|
|
} catch (e) {
|
|
return _localGetTodas();
|
|
}
|
|
}
|
|
|
|
async function _apiGuardar(fecha, titulo, texto, estado) {
|
|
try {
|
|
const res = await apiCall('/diario', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ fecha, titulo, texto, estado })
|
|
});
|
|
if (!res || !res.ok) throw new Error('Error al guardar');
|
|
const dto = await res.json();
|
|
_localSetEntrada(fecha, { id: dto.id, fecha, titulo, texto, estado });
|
|
return dto;
|
|
} catch (e) {
|
|
_localSetEntrada(fecha, { fecha, titulo, texto, estado });
|
|
return { fecha, titulo, texto, estado };
|
|
}
|
|
}
|
|
|
|
async function _apiEliminar(fecha) {
|
|
const entrada = _cache[fecha] || _localGetEntrada(fecha);
|
|
if (entrada?.id) {
|
|
try {
|
|
await apiCall(`/diario/${entrada.id}`, { method: 'DELETE' });
|
|
} catch (e) { /* sin conexión: eliminar solo local */ }
|
|
}
|
|
_localEliminarEntrada(fecha);
|
|
delete _cache[fecha];
|
|
}
|
|
|
|
// ── LOCALSTORAGE (fallback / caché offline) ─────────────────
|
|
|
|
function _lsKey() { return `diario_${_usuario.id}`; }
|
|
|
|
function _localGetTodas() {
|
|
try {
|
|
const data = localStorage.getItem(_lsKey());
|
|
const obj = data ? JSON.parse(data) : {};
|
|
return Object.values(obj);
|
|
} catch (e) { return []; }
|
|
}
|
|
|
|
function _localGetEntrada(fecha) {
|
|
try {
|
|
const data = localStorage.getItem(_lsKey());
|
|
const obj = data ? JSON.parse(data) : {};
|
|
return obj[fecha] || null;
|
|
} catch (e) { return null; }
|
|
}
|
|
|
|
function _localSetEntrada(fecha, entrada) {
|
|
try {
|
|
const data = localStorage.getItem(_lsKey());
|
|
const obj = data ? JSON.parse(data) : {};
|
|
obj[fecha] = entrada;
|
|
localStorage.setItem(_lsKey(), JSON.stringify(obj));
|
|
} catch (e) { /* sin espacio */ }
|
|
}
|
|
|
|
function _localEliminarEntrada(fecha) {
|
|
try {
|
|
const data = localStorage.getItem(_lsKey());
|
|
const obj = data ? JSON.parse(data) : {};
|
|
delete obj[fecha];
|
|
localStorage.setItem(_lsKey(), JSON.stringify(obj));
|
|
} catch (e) { /* noop */ }
|
|
}
|
|
|
|
// ── CARGAR ENTRADA ──────────────────────────────────────────
|
|
|
|
async function cargarEntrada(fecha) {
|
|
actualizarFechaDisplay(fecha);
|
|
|
|
document.getElementById('titulo-entrada').value = '';
|
|
document.getElementById('texto-entrada').value = '';
|
|
document.querySelectorAll('.btn-estado').forEach(b => b.classList.remove('activo'));
|
|
document.getElementById('btn-borrar-entrada').style.display = 'none';
|
|
|
|
const entrada = await _apiGetEntrada(fecha);
|
|
_cache[fecha] = entrada;
|
|
|
|
if (entrada) {
|
|
document.getElementById('titulo-entrada').value = entrada.titulo || '';
|
|
document.getElementById('texto-entrada').value = entrada.texto || '';
|
|
if (entrada.estado) {
|
|
const btn = document.querySelector(`.btn-estado[data-estado="${entrada.estado}"]`);
|
|
if (btn) btn.classList.add('activo');
|
|
}
|
|
document.getElementById('btn-borrar-entrada').style.display = 'inline-block';
|
|
}
|
|
}
|
|
|
|
// ── GUARDAR ─────────────────────────────────────────────────
|
|
|
|
async function guardarEntrada() {
|
|
const titulo = document.getElementById('titulo-entrada').value.trim();
|
|
const texto = document.getElementById('texto-entrada').value.trim();
|
|
const estado = getEstadoSeleccionado();
|
|
const btn = document.getElementById('btn-guardar-entrada');
|
|
|
|
if (!texto) {
|
|
mostrarMensajeDiario('Escribe algo antes de guardar 🙏', 'error');
|
|
return;
|
|
}
|
|
|
|
btn.disabled = true;
|
|
btn.textContent = 'Guardando…';
|
|
|
|
const dto = await _apiGuardar(_fechaSeleccionada, titulo, texto, estado);
|
|
_cache[_fechaSeleccionada] = dto;
|
|
|
|
btn.disabled = false;
|
|
btn.textContent = 'Guardar ✝';
|
|
document.getElementById('btn-borrar-entrada').style.display = 'inline-block';
|
|
|
|
cargarListaEntradas();
|
|
mostrarMensajeDiario('Entrada guardada ✝', 'success');
|
|
}
|
|
|
|
// ── BORRAR ───────────────────────────────────────────────────
|
|
|
|
async function borrarEntrada() {
|
|
if (!confirm('¿Eliminar esta entrada del diario?')) return;
|
|
|
|
await _apiEliminar(_fechaSeleccionada);
|
|
|
|
document.getElementById('titulo-entrada').value = '';
|
|
document.getElementById('texto-entrada').value = '';
|
|
document.querySelectorAll('.btn-estado').forEach(b => b.classList.remove('activo'));
|
|
document.getElementById('btn-borrar-entrada').style.display = 'none';
|
|
|
|
cargarListaEntradas();
|
|
mostrarMensajeDiario('Entrada eliminada', 'info');
|
|
}
|
|
|
|
// ── ESTADOS DE ÁNIMO ────────────────────────────────────────
|
|
|
|
function seleccionarEstado(estado) {
|
|
const btn = document.querySelector(`.btn-estado[data-estado="${estado}"]`);
|
|
if (!btn) return;
|
|
const yaActivo = btn.classList.contains('activo');
|
|
document.querySelectorAll('.btn-estado').forEach(b => b.classList.remove('activo'));
|
|
if (!yaActivo) btn.classList.add('activo');
|
|
}
|
|
|
|
function getEstadoSeleccionado() {
|
|
const activo = document.querySelector('.btn-estado.activo');
|
|
return activo ? activo.dataset.estado : null;
|
|
}
|
|
|
|
// ── NAVEGACIÓN ───────────────────────────────────────────────
|
|
|
|
function navegarFecha(delta) {
|
|
const d = new Date(_fechaSeleccionada + 'T12:00:00');
|
|
d.setDate(d.getDate() + delta);
|
|
_fechaSeleccionada = toFechaISO(d);
|
|
document.getElementById('fecha-entrada').value = _fechaSeleccionada;
|
|
cargarEntrada(_fechaSeleccionada);
|
|
}
|
|
|
|
function actualizarFechaDisplay(fecha) {
|
|
const d = new Date(fecha + 'T12:00:00');
|
|
const opts = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
|
|
document.getElementById('display-fecha').textContent = d.toLocaleDateString('es-ES', opts);
|
|
const hoy = toFechaISO(new Date());
|
|
document.getElementById('btn-siguiente').disabled = fecha >= hoy;
|
|
}
|
|
|
|
// ── LISTA DE ENTRADAS ───────────────────────────────────────
|
|
|
|
async function cargarListaEntradas() {
|
|
const lista = document.getElementById('lista-entradas');
|
|
const sinElem = document.getElementById('sin-entradas');
|
|
|
|
const entradas = await _apiGetTodas();
|
|
|
|
const lista_sorted = entradas
|
|
.filter(e => e && e.fecha)
|
|
.sort((a, b) => b.fecha.localeCompare(a.fecha));
|
|
|
|
if (lista_sorted.length === 0) {
|
|
lista.innerHTML = '';
|
|
sinElem.style.display = 'block';
|
|
return;
|
|
}
|
|
|
|
sinElem.style.display = 'none';
|
|
const hoy = toFechaISO(new Date());
|
|
|
|
lista.innerHTML = lista_sorted.map(e => {
|
|
const fecha = e.fecha;
|
|
const d = new Date(fecha + 'T12:00:00');
|
|
const fechaStr = d.toLocaleDateString('es-ES', { weekday: 'short', day: 'numeric', month: 'long' });
|
|
const icono = ESTADOS_DIARIO[e.estado]?.icono || '🕯';
|
|
const preview = (e.texto || '').substring(0, 80) + ((e.texto || '').length > 80 ? '…' : '');
|
|
const esHoy = fecha === hoy;
|
|
|
|
return `
|
|
<li class="entrada-item ${esHoy ? 'entrada-hoy' : ''}" onclick="seleccionarFechaLista('${fecha}')">
|
|
<span class="entrada-icono">${icono}</span>
|
|
<div class="entrada-info">
|
|
<span class="entrada-fecha">${fechaStr}${esHoy ? ' <em>(hoy)</em>' : ''}</span>
|
|
${e.titulo ? `<span class="entrada-titulo">${e.titulo}</span>` : ''}
|
|
<span class="entrada-preview">${preview}</span>
|
|
</div>
|
|
</li>
|
|
`;
|
|
}).join('');
|
|
}
|
|
|
|
function seleccionarFechaLista(fecha) {
|
|
_fechaSeleccionada = fecha;
|
|
document.getElementById('fecha-entrada').value = fecha;
|
|
cargarEntrada(fecha);
|
|
document.getElementById('editor-diario').scrollIntoView({ behavior: 'smooth' });
|
|
}
|
|
|
|
// ── UTILIDADES ───────────────────────────────────────────────
|
|
|
|
function toFechaISO(date) {
|
|
const offset = date.getTimezoneOffset() * 60000;
|
|
return new Date(date - offset).toISOString().split('T')[0];
|
|
}
|
|
|
|
function mostrarMensajeDiario(texto, tipo) {
|
|
const msg = document.getElementById('mensaje-diario');
|
|
msg.textContent = texto;
|
|
msg.className = `mensaje-diario ${tipo}`;
|
|
msg.style.display = 'block';
|
|
setTimeout(() => { msg.style.display = 'none'; }, 3000);
|
|
} |