381 lines
14 KiB
JavaScript
381 lines
14 KiB
JavaScript
// ================================
|
|
// INTENCIONES DE ORACIÓN
|
|
// Ámbitos: personal / parroquia / grupo
|
|
// Requiere: api-config.js, auth.js
|
|
// ================================
|
|
|
|
const iconos = ["vela.png", "flor.png", "cruz.png"];
|
|
|
|
let ambitoActual = "personal";
|
|
let grupoActualId = null;
|
|
let usuario = null;
|
|
|
|
// ── INICIALIZACIÓN ──────────────────────────────────────────
|
|
|
|
function init() {
|
|
usuario = verificarAuth();
|
|
if (!usuario) return; // verificarAuth ya redirige a login si no hay sesión
|
|
|
|
configurarPestanas();
|
|
configurarSelectorGrupo();
|
|
cargarIntenciones();
|
|
|
|
document.getElementById("btn-guardar").addEventListener("click", guardarIntencion);
|
|
document.getElementById("nueva-intencion").addEventListener("keydown", e => {
|
|
if (e.key === "Enter") guardarIntencion();
|
|
});
|
|
|
|
document.getElementById("btn-guardar-difunto").addEventListener("click", agregarDifunto);
|
|
document.getElementById("difunto-nombre").addEventListener("keydown", e => {
|
|
if (e.key === "Enter") agregarDifunto();
|
|
});
|
|
}
|
|
|
|
// ── PESTAÑAS ────────────────────────────────────────────────
|
|
|
|
function configurarPestanas() {
|
|
// Mostrar pestaña de parroquia si el usuario pertenece a una
|
|
if (usuario.parroquia) {
|
|
const tabParroquia = document.getElementById("tab-parroquia");
|
|
tabParroquia.style.display = "";
|
|
tabParroquia.textContent = `⛪ ${usuario.parroquia.nombre}`;
|
|
}
|
|
|
|
// Mostrar pestaña de comunidad si el usuario tiene grupos
|
|
if (usuario.grupos && usuario.grupos.length > 0) {
|
|
document.getElementById("tab-grupo").style.display = "";
|
|
}
|
|
|
|
document.querySelectorAll(".pestana").forEach(btn => {
|
|
btn.addEventListener("click", () => {
|
|
document.querySelectorAll(".pestana").forEach(b => b.classList.remove("activa"));
|
|
btn.classList.add("activa");
|
|
ambitoActual = btn.dataset.ambito;
|
|
|
|
const esDifuntos = ambitoActual === "difuntos";
|
|
document.getElementById("panel-difuntos").style.display = esDifuntos ? "block" : "none";
|
|
document.getElementById("formulario-intencion").style.display = esDifuntos ? "none" : "flex";
|
|
document.getElementById("muro-intenciones").style.display = esDifuntos ? "none" : "flex";
|
|
document.getElementById("sin-intenciones").style.display = "none";
|
|
|
|
if (esDifuntos) {
|
|
cargarDifuntos();
|
|
} else {
|
|
actualizarSelectorGrupo();
|
|
cargarIntenciones();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// ── SELECTOR DE GRUPO ───────────────────────────────────────
|
|
|
|
function configurarSelectorGrupo() {
|
|
if (!usuario.grupos || usuario.grupos.length === 0) return;
|
|
|
|
const select = document.getElementById("select-grupo");
|
|
usuario.grupos.forEach(g => {
|
|
const option = document.createElement("option");
|
|
option.value = g.id;
|
|
option.textContent = g.nombre;
|
|
select.appendChild(option);
|
|
});
|
|
|
|
grupoActualId = usuario.grupos[0].id;
|
|
|
|
select.addEventListener("change", () => {
|
|
grupoActualId = parseInt(select.value);
|
|
cargarIntenciones();
|
|
});
|
|
}
|
|
|
|
function actualizarSelectorGrupo() {
|
|
const selector = document.getElementById("selector-grupo");
|
|
selector.style.display = ambitoActual === "grupo" ? "block" : "none";
|
|
}
|
|
|
|
// La clave del fallback de intenciones también es por usuario
|
|
function keyIntenciones() {
|
|
return `intenciones_${usuario ? usuario.id : "anonimo"}`;
|
|
}
|
|
|
|
// ── CARGA DE INTENCIONES ─────────────────────────────────────
|
|
|
|
async function cargarIntenciones() {
|
|
const muro = document.getElementById("muro-intenciones");
|
|
const sinIntenciones = document.getElementById("sin-intenciones");
|
|
muro.innerHTML = "";
|
|
|
|
let endpoint;
|
|
if (ambitoActual === "personal") {
|
|
endpoint = "/intenciones/personales";
|
|
} else if (ambitoActual === "parroquia") {
|
|
endpoint = `/intenciones/parroquia/${usuario.parroquia.id}`;
|
|
} else {
|
|
if (!grupoActualId) return;
|
|
endpoint = `/intenciones/grupo/${grupoActualId}`;
|
|
}
|
|
|
|
try {
|
|
const response = await apiCall(endpoint);
|
|
if (!response || !response.ok) {
|
|
sinIntenciones.style.display = "block";
|
|
return;
|
|
}
|
|
|
|
const intenciones = await response.json();
|
|
|
|
if (intenciones.length === 0) {
|
|
sinIntenciones.style.display = "block";
|
|
return;
|
|
}
|
|
|
|
sinIntenciones.style.display = "none";
|
|
intenciones.forEach(i => crearHexagono(i));
|
|
|
|
} catch (e) {
|
|
// Si no hay conexión, mostrar las intenciones personales del localStorage como fallback
|
|
if (ambitoActual === "personal") {
|
|
const local = JSON.parse(localStorage.getItem(keyIntenciones()) || localStorage.getItem("intenciones") || "[]");
|
|
if (local.length === 0) {
|
|
sinIntenciones.style.display = "block";
|
|
} else {
|
|
local.forEach(i => crearHexagono({ texto: i.texto, icono: i.icono, esPropia: true }));
|
|
}
|
|
} else {
|
|
sinIntenciones.style.display = "block";
|
|
}
|
|
}
|
|
}
|
|
|
|
// ── GUARDAR INTENCIÓN ────────────────────────────────────────
|
|
|
|
async function guardarIntencion() {
|
|
const input = document.getElementById("nueva-intencion");
|
|
const texto = input.value.trim();
|
|
if (!texto) return;
|
|
|
|
const icono = iconos[Math.floor(Math.random() * iconos.length)];
|
|
const body = { texto, icono, ambito: ambitoActual };
|
|
|
|
if (ambitoActual === "parroquia") body.parroquiaId = usuario.parroquia.id;
|
|
if (ambitoActual === "grupo") body.grupoId = grupoActualId;
|
|
|
|
try {
|
|
const response = await apiCall("/intenciones", {
|
|
method: "POST",
|
|
body: JSON.stringify(body)
|
|
});
|
|
|
|
if (response && response.ok) {
|
|
const nueva = await response.json();
|
|
crearHexagono({ ...nueva, esPropia: true });
|
|
document.getElementById("sin-intenciones").style.display = "none";
|
|
}
|
|
|
|
} catch (e) {
|
|
// Fallback local solo para intenciones personales
|
|
if (ambitoActual === "personal") {
|
|
const local = JSON.parse(localStorage.getItem(keyIntenciones()) || "[]");
|
|
local.push({ texto, icono });
|
|
localStorage.setItem(keyIntenciones(), JSON.stringify(local));
|
|
crearHexagono({ texto, icono, esPropia: true, id: null });
|
|
document.getElementById("sin-intenciones").style.display = "none";
|
|
}
|
|
}
|
|
|
|
input.value = "";
|
|
}
|
|
|
|
// ── HEXÁGONO ─────────────────────────────────────────────────
|
|
|
|
function crearHexagono(intencion) {
|
|
const muro = document.getElementById("muro-intenciones");
|
|
const hex = document.createElement("div");
|
|
hex.className = "hexagono";
|
|
hex.dataset.texto = intencion.texto;
|
|
hex.dataset.icono = intencion.icono || iconos[0];
|
|
hex.dataset.autor = intencion.autorNombre || "";
|
|
hex.dataset.id = intencion.id || "";
|
|
hex.dataset.esPropia = intencion.esPropia || (intencion.usuarioId === usuario?.id) ? "true" : "false";
|
|
|
|
hex.innerHTML = `<img src="img/iconos/${hex.dataset.icono}" class="icono-intencion" alt="icono intención">`;
|
|
muro.appendChild(hex);
|
|
}
|
|
|
|
// ── DIFUNTOS ─────────────────────────────────────────────────
|
|
|
|
// Caché en memoria para evitar peticiones redundantes
|
|
let _difuntosCache = null;
|
|
|
|
async function _apiGetDifuntos() {
|
|
try {
|
|
const res = await apiCall('/difuntos/personales');
|
|
if (!res || !res.ok) throw new Error('Error al cargar difuntos');
|
|
const data = await res.json();
|
|
_difuntosCache = data;
|
|
// Sincronizar localStorage como caché offline
|
|
localStorage.setItem(keyDifuntos(), JSON.stringify(data));
|
|
return data;
|
|
} catch (e) {
|
|
// Fallback a localStorage si no hay conexión
|
|
return JSON.parse(localStorage.getItem(keyDifuntos()) || '[]');
|
|
}
|
|
}
|
|
|
|
// La clave incluye el id del usuario para que cada cuenta tenga sus propios difuntos
|
|
function keyDifuntos() {
|
|
return `difuntos_personales_${usuario ? usuario.id : 'anonimo'}`;
|
|
}
|
|
|
|
async function agregarDifunto() {
|
|
const nombre = document.getElementById("difunto-nombre").value.trim();
|
|
if (!nombre) return;
|
|
|
|
const nacimiento = document.getElementById("difunto-nacimiento").value || null;
|
|
const defuncion = document.getElementById("difunto-defuncion").value || null;
|
|
|
|
try {
|
|
const res = await apiCall('/difuntos/personales', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ nombre, nacimiento, defuncion })
|
|
});
|
|
if (res && res.ok) {
|
|
_difuntosCache = null; // invalidar caché
|
|
} else {
|
|
// Guardar local si falla
|
|
const difuntos = JSON.parse(localStorage.getItem(keyDifuntos()) || '[]');
|
|
difuntos.push({ id: Date.now().toString(), nombre, nacimiento, defuncion });
|
|
localStorage.setItem(keyDifuntos(), JSON.stringify(difuntos));
|
|
}
|
|
} catch (e) {
|
|
const difuntos = JSON.parse(localStorage.getItem(keyDifuntos()) || '[]');
|
|
difuntos.push({ id: Date.now().toString(), nombre, nacimiento, defuncion });
|
|
localStorage.setItem(keyDifuntos(), JSON.stringify(difuntos));
|
|
}
|
|
|
|
document.getElementById("difunto-nombre").value = "";
|
|
document.getElementById("difunto-nacimiento").value = "";
|
|
document.getElementById("difunto-defuncion").value = "";
|
|
|
|
cargarDifuntos();
|
|
}
|
|
|
|
async function eliminarDifunto(id) {
|
|
try {
|
|
const res = await apiCall(`/difuntos/personales/${id}`, { method: 'DELETE' });
|
|
if (res && (res.ok || res.status === 204)) {
|
|
_difuntosCache = null;
|
|
// Sincronizar localStorage
|
|
const local = JSON.parse(localStorage.getItem(keyDifuntos()) || '[]');
|
|
localStorage.setItem(keyDifuntos(), JSON.stringify(local.filter(d => String(d.id) !== String(id))));
|
|
return;
|
|
}
|
|
} catch (e) { /* sin conexión: eliminar solo local */ }
|
|
// Fallback: solo localStorage
|
|
const difuntos = JSON.parse(localStorage.getItem(keyDifuntos()) || '[]').filter(d => String(d.id) !== String(id));
|
|
localStorage.setItem(keyDifuntos(), JSON.stringify(difuntos));
|
|
}
|
|
|
|
async function cargarDifuntos() {
|
|
const lista = document.getElementById("lista-difuntos");
|
|
const sinDifuntos = document.getElementById("sin-difuntos");
|
|
const difuntos = _difuntosCache || await _apiGetDifuntos();
|
|
|
|
lista.innerHTML = "";
|
|
|
|
if (difuntos.length === 0) {
|
|
sinDifuntos.style.display = "block";
|
|
return;
|
|
}
|
|
sinDifuntos.style.display = "none";
|
|
|
|
difuntos.forEach(d => {
|
|
const li = document.createElement("li");
|
|
li.className = "item-difunto";
|
|
|
|
const etiquetas = [];
|
|
if (d.nacimiento) {
|
|
const f = new Date(d.nacimiento + "T12:00:00");
|
|
etiquetas.push(`<span class="difunto-fecha">🎂 ${f.toLocaleDateString("es-ES", { day: "numeric", month: "long", year: "numeric" })}</span>`);
|
|
}
|
|
if (d.defuncion) {
|
|
const f = new Date(d.defuncion + "T12:00:00");
|
|
etiquetas.push(`<span class="difunto-fecha">✝ ${f.toLocaleDateString("es-ES", { day: "numeric", month: "long", year: "numeric" })}</span>`);
|
|
}
|
|
|
|
li.innerHTML = `
|
|
<div class="difunto-info">
|
|
<span class="difunto-nombre">🕯 ${d.nombre}</span>
|
|
${etiquetas.join("")}
|
|
</div>
|
|
<button class="btn-eliminar-difunto" data-id="${d.id}" title="Eliminar">✕</button>
|
|
`;
|
|
lista.appendChild(li);
|
|
});
|
|
|
|
lista.querySelectorAll(".btn-eliminar-difunto").forEach(btn => {
|
|
btn.addEventListener("click", async () => {
|
|
await eliminarDifunto(btn.dataset.id);
|
|
cargarDifuntos();
|
|
});
|
|
});
|
|
}
|
|
|
|
// ── MODAL ────────────────────────────────────────────────────
|
|
|
|
const modal = document.getElementById("modal-intencion");
|
|
const cerrar = document.getElementById("cerrar-modal");
|
|
const textoModal = document.getElementById("texto-modal");
|
|
const iconoModal = document.getElementById("icono-modal");
|
|
const autorModal = document.getElementById("autor-modal");
|
|
const btnBorrar = document.getElementById("btn-borrar-modal");
|
|
|
|
let intencionActivaId = null;
|
|
|
|
document.addEventListener("click", e => {
|
|
const hex = e.target.closest(".hexagono");
|
|
if (!hex) return;
|
|
|
|
textoModal.textContent = hex.dataset.texto;
|
|
iconoModal.src = "img/iconos/" + hex.dataset.icono;
|
|
autorModal.textContent = hex.dataset.autor ? `— ${hex.dataset.autor}` : "";
|
|
intencionActivaId = hex.dataset.id || null;
|
|
|
|
// Solo mostrar botón borrar si es la propia intención
|
|
btnBorrar.style.display = hex.dataset.esPropia === "true" ? "inline-block" : "none";
|
|
|
|
modal.classList.add("visible");
|
|
});
|
|
|
|
cerrar.onclick = () => modal.classList.remove("visible");
|
|
modal.onclick = e => { if (e.target === modal) modal.classList.remove("visible"); };
|
|
|
|
btnBorrar.onclick = async () => {
|
|
if (!intencionActivaId) return;
|
|
|
|
try {
|
|
const response = await apiCall(`/intenciones/${intencionActivaId}`, { method: "DELETE" });
|
|
if (response && response.ok) {
|
|
modal.classList.remove("visible");
|
|
cargarIntenciones();
|
|
}
|
|
} catch (e) {
|
|
// Fallback local
|
|
const local = JSON.parse(localStorage.getItem(keyIntenciones()) || "[]");
|
|
const idx = local.findIndex(i => i.texto === textoModal.textContent);
|
|
if (idx !== -1) {
|
|
local.splice(idx, 1);
|
|
localStorage.setItem(keyIntenciones(), JSON.stringify(local));
|
|
}
|
|
modal.classList.remove("visible");
|
|
cargarIntenciones();
|
|
}
|
|
};
|
|
|
|
// ── ARRANQUE (se llama desde header.js tras cargar el header) ──
|
|
// header.js invoca las funciones de inicialización tras insertar el header.
|
|
// Para intenciones, usamos DOMContentLoaded como punto de entrada seguro.
|
|
document.addEventListener("DOMContentLoaded", init);
|
|
|