{"id":754,"date":"2025-11-16T18:05:07","date_gmt":"2025-11-16T18:05:07","guid":{"rendered":"https:\/\/bodafranyjose.com\/?page_id=754"},"modified":"2026-04-13T17:03:27","modified_gmt":"2026-04-13T17:03:27","slug":"tareas","status":"publish","type":"page","link":"https:\/\/bodafranyjose.com\/index.php\/tareas\/","title":{"rendered":"Tareas"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"754\" class=\"elementor elementor-754\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-9d16f88 e-flex e-con-boxed e-con e-parent\" data-id=\"9d16f88\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-bd1b2a5 elementor-widget elementor-widget-html\" data-id=\"bd1b2a5\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<style>\n  .tareas-container {\n    background: #fff;\n    border-radius: 22px;\n    box-shadow: 0 6px 24px rgba(0,0,0,0.07);\n    padding: 22px 18px;\n    max-width: 950px;\n    margin: 0 auto;\n    font-family: 'Poppins', sans-serif;\n    color: #333;\n  }\n\n  .tareas-head {\n    text-align: center;\n    margin-bottom: 14px;\n  }\n\n  .tareas-title {\n    color: #b67b91;\n    margin: 0 0 5px;\n    font-size: 1.72rem;\n    font-weight: 700;\n    line-height: 1.15;\n  }\n\n  .tareas-subtitle {\n    color: #666;\n    margin: 0;\n    font-size: 0.9rem;\n    font-weight: 600;\n    line-height: 1.28;\n  }\n\n  .resumen-dashboard {\n    display: grid;\n    grid-template-columns: repeat(6, minmax(0, 1fr));\n    gap: 9px;\n    margin-bottom: 12px;\n  }\n\n  .resumen-card {\n    background: #faf6f8;\n    border: 1px solid transparent;\n    border-radius: 13px;\n    text-align: center;\n    padding: 8px 7px;\n    box-shadow: 0 2px 9px rgba(0,0,0,0.04);\n    cursor: pointer;\n    transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease, background 0.2s ease;\n  }\n\n  .resumen-card:hover {\n    transform: translateY(-1px);\n    box-shadow: 0 5px 14px rgba(0,0,0,0.07);\n  }\n\n  .resumen-card.active {\n    background: #fff;\n    border-color: #b67b91;\n    box-shadow: 0 5px 16px rgba(182,123,145,0.16);\n  }\n\n  .resumen-card h3 {\n    font-size: 0.72rem;\n    color: #b67b91;\n    margin: 0 0 4px;\n    font-weight: 700;\n    line-height: 1.1;\n  }\n\n  .resumen-card span {\n    font-size: 1.08rem;\n    font-weight: 800;\n    color: #333;\n    line-height: 1.1;\n  }\n\n  .resumen-card.total { background: #f4f0f8; }\n  .resumen-card.fran { background: #eef7f2; }\n  .resumen-card.jose { background: #f7eef3; }\n  .resumen-card.ambos { background: #f8f7ee; }\n  .resumen-card.otros { background: #f2f2f2; }\n  .resumen-card.completadas { background: #eaf8f0; }\n\n  .resumen-card.active.total,\n  .resumen-card.active.fran,\n  .resumen-card.active.jose,\n  .resumen-card.active.ambos,\n  .resumen-card.active.otros,\n  .resumen-card.active.completadas {\n    background: #fff;\n  }\n\n  .tareas-toolbar {\n    display: grid;\n    grid-template-columns: auto 1fr auto auto;\n    gap: 9px;\n    align-items: center;\n    margin-bottom: 12px;\n  }\n\n.buscar-wrap {\n  position: relative;\n}\n\n.buscar-wrap::before,\n.buscar-wrap::after {\n  content: none;\n  display: none;\n}\n\n.buscar-tarea,\n.ordenar-tarea {\n  width: 100%;\n  min-height: 41px;\n  padding: 9px 11px;\n  border-radius: 10px;\n  border: 1px solid #e2d4da;\n  font-size: 16px;\n  box-sizing: border-box;\n  background: #fff;\n  font-family: 'Poppins', sans-serif;\n  font-weight: 400;\n}\n\n.buscar-tarea {\n  padding-left: 11px;\n}\n\n.buscar-tarea::placeholder {\n  color: #888;\n  font-weight: 300;\n}\n\n\n  .btn-main,\n  .btn-secondary,\n  .btn-close,\n  .btn-danger {\n    border-radius: 10px;\n    cursor: pointer;\n    font-family: 'Poppins', sans-serif;\n    font-weight: 700;\n    font-size: 0.86rem;\n    transition: 0.25s ease;\n    white-space: nowrap;\n    min-height: 41px;\n  }\n\n  .btn-main,\n  .btn-close {\n    background: #b67b91;\n    color: #fff;\n    border: none;\n    padding: 9px 13px;\n  }\n\n  .btn-main:hover,\n  .btn-close:hover {\n    background: #a56b82;\n  }\n\n  .btn-secondary {\n    background: #fff;\n    color: #b67b91;\n    border: 1px solid #e5c9d4;\n    padding: 8px 12px;\n  }\n\n  .btn-secondary:hover {\n    background: #f9f0f4;\n    border-color: #b67b91;\n  }\n\n  .btn-danger {\n    background: #fff;\n    color: #a5447d;\n    border: 1px solid #f0c8d6;\n    padding: 8px 12px;\n  }\n\n  .btn-danger:hover {\n    background: #fcefee;\n    color: #8f3568;\n  }\n\n  .tareas-lista {\n    display: grid;\n    gap: 7px;\n  }\n\n  .tarea-row {\n    width: 100%;\n    display: grid;\n    grid-template-columns: 28px 1fr auto;\n    gap: 9px;\n    align-items: center;\n    border: 1px solid #f0e6ea;\n    border-radius: 14px;\n    background: #fff;\n    padding: 9px 10px;\n    box-shadow: 0 2px 10px rgba(0,0,0,0.035);\n    font-family: 'Poppins', sans-serif;\n    color: #333;\n    transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;\n  }\n\n  .tarea-row:hover {\n    transform: translateY(-1px);\n    box-shadow: 0 4px 14px rgba(0,0,0,0.055);\n  }\n\n  .tarea-row.completada {\n    border-color: #d9efd9;\n    background: linear-gradient(90deg, #f7fcf8, #fff);\n  }\n\n  .tarea-check {\n    transform: scale(1.08);\n    accent-color: #b67b91;\n    cursor: pointer;\n    margin: 0;\n  }\n\n  .tarea-info {\n    min-width: 0;\n    cursor: pointer;\n  }\n\n  .texto-tarea {\n    display: block;\n    font-weight: 800;\n    color: #444;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n    line-height: 1.18;\n    font-size: 0.95rem;\n  }\n\n  .tarea-row.completada .texto-tarea {\n    text-decoration: line-through;\n    color: #777;\n  }\n\n  .tarea-side {\n    display: flex;\n    align-items: center;\n    gap: 7px;\n    cursor: pointer;\n  }\n\n  .badge {\n    display: inline-flex;\n    align-items: center;\n    background: #fff;\n    color: #b67b91;\n    border: 1px solid #f0e6ea;\n    border-radius: 999px;\n    padding: 3px 8px;\n    font-size: 0.68rem;\n    font-weight: 800;\n    line-height: 1.1;\n    white-space: nowrap;\n  }\n\n  .badge.ok { color: #3c8d56; border-color: #d9efd9; }\n  .badge.warn { color: #a5447d; border-color: #f0c8d6; }\n  .badge.fran { color: #3c8d56; }\n  .badge.jose { color: #a5447d; }\n  .badge.ambos { color: #b6912e; }\n  .badge.otrapersona { color: #555; }\n\n  .row-chevron {\n    color: #b67b91;\n    font-size: 1.1rem;\n    font-weight: 800;\n    line-height: 1;\n  }\n\n  .sin-resultados {\n    text-align: center;\n    color: #b67b91;\n    margin: 14px 0;\n    background: #faf6f8;\n    border-radius: 14px;\n    padding: 16px;\n    font-weight: 700;\n  }\n\n  .tarea-modal {\n    display: none;\n    position: fixed;\n    z-index: 99999;\n    inset: 0;\n    background: rgba(45, 35, 40, 0.38);\n    padding: 18px;\n    box-sizing: border-box;\n    align-items: center;\n    justify-content: center;\n  }\n\n  .tarea-modal.active {\n    display: flex;\n  }\n\n  .tarea-modal-card {\n    width: min(560px, 100%);\n    max-height: calc(100vh - 36px);\n    overflow-y: auto;\n    background: #fff;\n    border-radius: 18px;\n    box-shadow: 0 18px 45px rgba(0,0,0,0.22);\n    border: 1px solid #f0e6ea;\n  }\n\n  .ficha-head {\n    display: grid;\n    grid-template-columns: 1fr 40px;\n    gap: 10px;\n    align-items: center;\n    padding: 14px 14px 12px;\n    background: #faf6f8;\n    border-bottom: 1px solid #f0e6ea;\n    border-radius: 18px 18px 0 0;\n  }\n\n  .ficha-title {\n    margin: 0;\n    color: #b67b91;\n    font-size: 1.08rem;\n    font-weight: 800;\n    line-height: 1.2;\n  }\n\n  .ficha-subtitle {\n    margin: 3px 0 0;\n    color: #666;\n    font-size: 0.8rem;\n    font-weight: 600;\n  }\n\n  .ficha-x {\n    width: 40px;\n    height: 40px;\n    border: 1px solid #f0e6ea;\n    border-radius: 10px;\n    background: #fff;\n    color: #b67b91;\n    cursor: pointer;\n    font-weight: 800;\n    font-size: 1.08rem;\n    line-height: 1;\n    padding: 0;\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    appearance: none;\n  }\n\n  .ficha-body {\n    padding: 14px;\n  }\n\n  .ficha-grid {\n    display: grid;\n    grid-template-columns: 1fr 1fr;\n    gap: 10px;\n  }\n\n  .ficha-field {\n    min-width: 0;\n  }\n\n  .ficha-field.full {\n    grid-column: 1 \/ -1;\n  }\n\n  .ficha-field label,\n  .ficha-check {\n    display: block;\n    color: #b67b91;\n    font-weight: 800;\n    font-size: 0.82rem;\n    margin-bottom: 5px;\n  }\n\n  .ficha-input,\n  .ficha-textarea,\n  .ficha-select {\n    width: 100%;\n    min-height: 42px;\n    padding: 9px 10px;\n    border-radius: 10px;\n    border: 1px solid #e2d4da;\n    font-size: 16px;\n    box-sizing: border-box;\n    background: #fff;\n    font-family: 'Poppins', sans-serif;\n  }\n\n  .ficha-textarea {\n    min-height: 88px;\n    resize: vertical;\n  }\n\n  .ficha-check {\n    display: flex;\n    align-items: center;\n    gap: 8px;\n    min-height: 42px;\n    padding: 9px 10px;\n    border: 1px solid #f0e6ea;\n    border-radius: 10px;\n    background: #faf6f8;\n    color: #444;\n    cursor: pointer;\n    box-sizing: border-box;\n  }\n\n  .ficha-check input {\n    accent-color: #b67b91;\n  }\n\n  .ficha-actions {\n    display: grid;\n    grid-template-columns: 1fr;\n    gap: 9px;\n    margin-top: 14px;\n  }\n\n  .ficha-danger-zone {\n    margin-top: 13px;\n    padding-top: 13px;\n    border-top: 1px solid #f4e5eb;\n  }\n\n  .ficha-danger-zone .btn-danger {\n    width: 100%;\n  }\n\n  @media (max-width: 900px) {\n    .resumen-dashboard {\n      grid-template-columns: repeat(3, minmax(0, 1fr));\n    }\n\n    .tareas-toolbar {\n      grid-template-columns: auto 1fr auto;\n    }\n\n    .ordenar-tarea {\n      grid-column: 1 \/ -1;\n    }\n  }\n\n  @media (max-width: 768px) {\n    .tareas-container {\n      padding: 16px 12px;\n      border-radius: 18px;\n    }\n\n    .tareas-head {\n      margin-bottom: 10px;\n    }\n\n    .tareas-title {\n      font-size: 1.36rem;\n      margin-bottom: 4px;\n    }\n\n    .tareas-subtitle {\n      font-size: 0.78rem;\n      line-height: 1.25;\n      max-width: 340px;\n      margin: 0 auto;\n    }\n\n    .resumen-dashboard {\n      grid-template-columns: repeat(3, minmax(0, 1fr));\n      gap: 6px;\n      margin-bottom: 10px;\n    }\n\n    .resumen-card {\n      padding: 7px 4px;\n      border-radius: 11px;\n      min-height: 48px;\n    }\n\n    .resumen-card h3 {\n      font-size: 0.56rem;\n      margin-bottom: 3px;\n    }\n\n    .resumen-card span {\n      font-size: 0.88rem;\n    }\n\n    .tareas-toolbar {\n      grid-template-columns: 1fr 1fr;\n      gap: 8px;\n      margin-bottom: 10px;\n    }\n\n    .tareas-toolbar .btn-main {\n      grid-column: 1 \/ -1;\n    }\n\n    .buscar-wrap {\n      grid-column: 1 \/ -1;\n    }\n\n    .ordenar-tarea {\n      grid-column: auto;\n    }\n\n    .btn-main,\n    .btn-secondary {\n      width: 100%;\n    }\n\n    .tareas-lista {\n      gap: 6px;\n    }\n\n    .tarea-row {\n      grid-template-columns: 24px 1fr auto;\n      gap: 8px;\n      padding: 8px 9px;\n      border-radius: 13px;\n      min-height: 46px;\n    }\n\n    .tarea-check {\n      transform: scale(1.05);\n    }\n\n    .texto-tarea {\n      font-size: 0.9rem;\n    }\n\n    .badge {\n      font-size: 0.6rem;\n      padding: 3px 6px;\n    }\n\n    .tarea-side {\n      gap: 5px;\n    }\n\n    .row-chevron {\n      font-size: 1rem;\n    }\n\n    .tarea-modal {\n      padding: 10px;\n      align-items: flex-end;\n    }\n\n    .tarea-modal-card {\n      max-height: calc(100vh - 20px);\n      border-radius: 18px;\n    }\n\n    .ficha-head {\n      padding: 13px 13px 11px;\n    }\n\n    .ficha-title {\n      font-size: 1rem;\n    }\n\n    .ficha-body {\n      padding: 12px;\n    }\n\n    .ficha-grid {\n      grid-template-columns: 1fr;\n      gap: 9px;\n    }\n\n    .btn-close,\n    .btn-danger,\n    .btn-main {\n      width: 100%;\n    }\n  }\n\n  @media (max-width: 380px) {\n    .resumen-card h3 {\n      font-size: 0.52rem;\n    }\n\n    .resumen-card span {\n      font-size: 0.82rem;\n    }\n\n    .tareas-toolbar {\n      grid-template-columns: 1fr;\n    }\n\n    .badge {\n      display: none;\n    }\n  }\n<\/style>\n\n<div class=\"tareas-container\">\n  <div class=\"tareas-head\">\n    <h2 class=\"tareas-title\">\ud83d\udcdd Tareas de la Boda<\/h2>\n    <p class=\"tareas-subtitle\">Organiza pendientes, responsables y tareas completadas.<\/p>\n  <\/div>\n\n  <div class=\"resumen-dashboard\">\n    <div class=\"resumen-card total active\" onclick=\"filtrarTareas('total')\">\n      <h3>Total<\/h3><span id=\"totalTareas\">0<\/span>\n    <\/div>\n    <div class=\"resumen-card fran\" onclick=\"filtrarTareas('Fran')\">\n      <h3>Fran<\/h3><span id=\"tareasFran\">0<\/span>\n    <\/div>\n    <div class=\"resumen-card jose\" onclick=\"filtrarTareas('Jos\u00e9')\">\n      <h3>Jos\u00e9<\/h3><span id=\"tareasJose\">0<\/span>\n    <\/div>\n    <div class=\"resumen-card ambos\" onclick=\"filtrarTareas('Ambos')\">\n      <h3>Ambos<\/h3><span id=\"tareasAmbos\">0<\/span>\n    <\/div>\n    <div class=\"resumen-card otros\" onclick=\"filtrarTareas('Otra persona')\">\n      <h3>Otros<\/h3><span id=\"tareasOtros\">0<\/span>\n    <\/div>\n    <div class=\"resumen-card completadas\" onclick=\"filtrarTareas('Completadas')\">\n      <h3>Hechas<\/h3><span id=\"tareasCompletadas\">0<\/span>\n    <\/div>\n  <\/div>\n\n  <div class=\"tareas-toolbar\">\n    <button class=\"btn-main\" onclick=\"abrirNuevaTarea()\">\u2795 A\u00f1adir tarea<\/button>\n\n    <div class=\"buscar-wrap\">\n      <input type=\"text\" id=\"buscarTarea\" class=\"buscar-tarea\" placeholder=\"Buscar tarea...\" oninput=\"actualizarBusqueda(this.value)\">\n    <\/div>\n\n    <select id=\"ordenTareas\" class=\"ordenar-tarea\" onchange=\"actualizarOrden(this.value)\">\n      <option value=\"pendientes\">Pendientes primero<\/option>\n      <option value=\"responsable\">Responsable<\/option>\n      <option value=\"nombre\">Nombre<\/option>\n      <option value=\"hechas\">Hechas primero<\/option>\n    <\/select>\n\n    <button class=\"btn-secondary\" onclick=\"exportarTareas()\">\ud83d\udce4 Exportar<\/button>\n  <\/div>\n\n  <div id=\"listaTareas\" class=\"tareas-lista\"><\/div>\n<\/div>\n\n<div class=\"tarea-modal\" id=\"nuevaTareaModal\" onclick=\"cerrarNuevaTareaDesdeFondo(event)\">\n  <div class=\"tarea-modal-card\" role=\"dialog\" aria-modal=\"true\">\n    <div class=\"ficha-head\">\n      <div>\n        <h3 class=\"ficha-title\">A\u00f1adir tarea<\/h3>\n        <p class=\"ficha-subtitle\">Crea una tarea nueva en la lista.<\/p>\n      <\/div>\n      <button class=\"ficha-x\" onclick=\"cerrarNuevaTarea()\">\u2715<\/button>\n    <\/div>\n\n    <div class=\"ficha-body\">\n      <div class=\"ficha-grid\">\n        <div class=\"ficha-field full\">\n          <label>Tarea<\/label>\n          <input type=\"text\" id=\"nuevaTarea\" class=\"ficha-input\" placeholder=\"Nueva tarea...\">\n        <\/div>\n\n        <div class=\"ficha-field\">\n          <label>Responsable<\/label>\n          <select id=\"nuevoResponsable\" class=\"ficha-select\">\n            <option value=\"Ambos\">Ambos<\/option>\n            <option value=\"Fran\">Fran<\/option>\n            <option value=\"Jos\u00e9\">Jos\u00e9<\/option>\n            <option value=\"Otra persona\">Otra persona<\/option>\n          <\/select>\n        <\/div>\n\n        <div class=\"ficha-field\">\n          <label class=\"ficha-check\">\n            <input type=\"checkbox\" id=\"nuevaCompletada\">\n            Tarea hecha\n          <\/label>\n        <\/div>\n\n        <div class=\"ficha-field full\">\n          <label>Notas<\/label>\n          <textarea id=\"nuevasNotas\" class=\"ficha-textarea\" placeholder=\"Notas...\"><\/textarea>\n        <\/div>\n      <\/div>\n\n      <div class=\"ficha-actions\">\n        <button class=\"btn-main\" onclick=\"agregarTarea()\">Guardar tarea<\/button>\n        <button class=\"btn-secondary\" onclick=\"cerrarNuevaTarea()\">Cancelar<\/button>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/div>\n\n<div class=\"tarea-modal\" id=\"tareaModal\" onclick=\"cerrarFichaDesdeFondo(event)\">\n  <div class=\"tarea-modal-card\" role=\"dialog\" aria-modal=\"true\">\n    <div class=\"ficha-head\">\n      <div>\n        <h3 class=\"ficha-title\" id=\"fichaTitulo\">Editar tarea<\/h3>\n        <p class=\"ficha-subtitle\">Los cambios se guardan autom\u00e1ticamente.<\/p>\n      <\/div>\n      <button class=\"ficha-x\" onclick=\"cerrarFicha()\">\u2715<\/button>\n    <\/div>\n\n    <div class=\"ficha-body\">\n      <div class=\"ficha-grid\">\n        <div class=\"ficha-field full\">\n          <label>Tarea<\/label>\n          <input type=\"text\" id=\"fichaTexto\" class=\"ficha-input\" oninput=\"actualizarTextoFicha('texto', this.value)\">\n        <\/div>\n\n        <div class=\"ficha-field\">\n          <label>Responsable<\/label>\n          <select id=\"fichaResponsable\" class=\"ficha-select\" onchange=\"actualizarResponsableFicha(this.value)\">\n            <option value=\"Fran\">Fran<\/option>\n            <option value=\"Jos\u00e9\">Jos\u00e9<\/option>\n            <option value=\"Ambos\">Ambos<\/option>\n            <option value=\"Otra persona\">Otra persona<\/option>\n          <\/select>\n        <\/div>\n\n        <div class=\"ficha-field\">\n          <label class=\"ficha-check\">\n            <input type=\"checkbox\" id=\"fichaCompletada\" onchange=\"actualizarCompletadaFicha(this.checked)\">\n            Tarea hecha\n          <\/label>\n        <\/div>\n\n        <div class=\"ficha-field full\">\n          <label>Notas<\/label>\n          <textarea id=\"fichaNotas\" class=\"ficha-textarea\" placeholder=\"Notas...\" oninput=\"actualizarTextoFicha('notas', this.value)\"><\/textarea>\n        <\/div>\n      <\/div>\n\n      <div class=\"ficha-actions\">\n        <button class=\"btn-close\" onclick=\"cerrarFicha()\">Cerrar ficha<\/button>\n      <\/div>\n\n      <div class=\"ficha-danger-zone\">\n        <button class=\"btn-danger\" onclick=\"eliminarTareaEditando()\">Eliminar tarea<\/button>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\nconst JSON_URL = 'https:\/\/bodafranyjose.com\/wp-content\/uploads\/tareas\/tareas.json';\nconst GUARDAR_URL = 'https:\/\/bodafranyjose.com\/wp-content\/uploads\/tareas\/guardar_tareas.php?key=bodafest2025KEY';\n\nlet tareas = [];\nlet filtroActivo = 'total';\nlet busquedaActiva = '';\nlet ordenActivo = 'pendientes';\nlet guardadoTimer = null;\nlet tareaEditando = null;\n\nfunction escaparHTML(valor) {\n  return String(valor || \"\")\n    .replace(\/&\/g, \"&amp;\")\n    .replace(\/<\/g, \"&lt;\")\n    .replace(\/>\/g, \"&gt;\")\n    .replace(\/\"\/g, \"&quot;\")\n    .replace(\/'\/g, \"&#039;\");\n}\n\nfunction normalizarTexto(valor) {\n  return String(valor || \"\")\n    .normalize(\"NFD\")\n    .replace(\/[\\u0300-\\u036f]\/g, \"\")\n    .trim()\n    .toLowerCase();\n}\n\nfunction normalizarResponsable(valor) {\n  return String(valor || \"\")\n    .normalize(\"NFD\")\n    .replace(\/[\\u0300-\\u036f]\/g, \"\")\n    .replace(\/\\s+\/g, \"\")\n    .toLowerCase();\n}\n\nfunction limpiarCSV(valor) {\n  return String(valor || \"\")\n    .replace(\/\"\/g, '\"\"')\n    .replace(\/\\n\/g, \" \")\n    .replace(\/\\r\/g, \" \");\n}\n\nfunction programarGuardado() {\n  if (guardadoTimer) {\n    clearTimeout(guardadoTimer);\n  }\n\n  guardadoTimer = setTimeout(function () {\n    guardarCambios(true);\n  }, 650);\n}\n\nasync function cargarTareas() {\n  try {\n    const res = await fetch(JSON_URL + '?v=' + Date.now());\n    tareas = await res.json();\n\n    if (!Array.isArray(tareas)) {\n      tareas = [];\n    }\n\n    tareas = tareas.map(function (tarea) {\n      return Object.assign({}, tarea, {\n        texto: tarea.texto || \"\",\n        responsable: tarea.responsable || \"Ambos\",\n        notas: tarea.notas || \"\",\n        completada: Boolean(tarea.completada)\n      });\n    });\n  } catch (e) {\n    console.error(\"Error cargando tareas:\", e);\n    tareas = [];\n  }\n\n  renderTareas();\n}\n\nfunction ordenarLista(lista) {\n  return lista.slice().sort(function (a, b) {\n    if (ordenActivo === 'pendientes') {\n      if (Boolean(a.completada) !== Boolean(b.completada)) {\n        return a.completada ? 1 : -1;\n      }\n    }\n\n    if (ordenActivo === 'hechas') {\n      if (Boolean(a.completada) !== Boolean(b.completada)) {\n        return a.completada ? -1 : 1;\n      }\n    }\n\n    if (ordenActivo === 'responsable') {\n      const responsable = String(a.responsable || \"\").localeCompare(String(b.responsable || \"\"), \"es\");\n      if (responsable !== 0) {\n        return responsable;\n      }\n    }\n\n    return String(a.texto || \"\").localeCompare(String(b.texto || \"\"), \"es\");\n  });\n}\n\nfunction renderTareas() {\n  const contenedor = document.getElementById(\"listaTareas\");\n  contenedor.innerHTML = \"\";\n\n  const termino = normalizarTexto(busquedaActiva);\n\n  let tareasFiltradas = tareas\n    .map(function (t, index) {\n      return Object.assign({}, t, { index: index });\n    })\n    .filter(function (t) {\n      if (filtroActivo === 'completadas' && !t.completada) return false;\n      if (filtroActivo !== 'total' && filtroActivo !== 'completadas' && normalizarResponsable(t.responsable) !== filtroActivo) return false;\n\n      if (!termino) return true;\n\n      return normalizarTexto(t.texto).includes(termino) ||\n        normalizarTexto(t.notas).includes(termino) ||\n        normalizarTexto(t.responsable).includes(termino);\n    });\n\n  tareasFiltradas = ordenarLista(tareasFiltradas);\n  actualizarResumen();\n\n  if (tareasFiltradas.length === 0) {\n    contenedor.innerHTML = '<p class=\"sin-resultados\">Sin tareas en este filtro.<\/p>';\n    return;\n  }\n\n  tareasFiltradas.forEach(function (t) {\n    const i = t.index;\n    const texto = t.texto || \"\";\n    const responsable = t.responsable || \"Ambos\";\n    const claseColor = normalizarResponsable(responsable);\n    const estadoBadge = t.completada ? '<span class=\"badge ok\">Hecha<\/span>' : '<span class=\"badge warn\">Pend.<\/span>';\n\n    const item = document.createElement(\"div\");\n    item.className = \"tarea-row \" + claseColor + \" \" + (t.completada ? \"completada\" : \"pendiente\");\n\n    item.innerHTML = `\n      <input type=\"checkbox\" class=\"tarea-check\" ${t.completada ? \"checked\" : \"\"}\n        onchange=\"toggleCompletada(event, ${i})\">\n\n      <div class=\"tarea-info\" onclick=\"abrirFicha(${i})\">\n        <span class=\"texto-tarea\">${escaparHTML(texto)}<\/span>\n      <\/div>\n\n      <div class=\"tarea-side\" onclick=\"abrirFicha(${i})\">\n        ${estadoBadge}\n        <span class=\"badge ${claseColor}\">${escaparHTML(responsable)}<\/span>\n        <span class=\"row-chevron\">\u203a<\/span>\n      <\/div>\n    `;\n\n    contenedor.appendChild(item);\n  });\n}\n\nfunction abrirNuevaTarea() {\n  const modal = document.getElementById(\"nuevaTareaModal\");\n  const textoInput = document.getElementById(\"nuevaTarea\");\n\n  if (modal) {\n    modal.classList.add(\"active\");\n    document.body.style.overflow = \"hidden\";\n  }\n\n  if (textoInput) {\n    setTimeout(function () {\n      textoInput.focus();\n    }, 100);\n  }\n}\n\nfunction cerrarNuevaTarea() {\n  const modal = document.getElementById(\"nuevaTareaModal\");\n\n  if (modal) {\n    modal.classList.remove(\"active\");\n  }\n\n  document.body.style.overflow = \"\";\n}\n\nfunction cerrarNuevaTareaDesdeFondo(event) {\n  if (event.target && event.target.id === \"nuevaTareaModal\") {\n    cerrarNuevaTarea();\n  }\n}\n\nfunction abrirFicha(i) {\n  if (!tareas[i]) {\n    return;\n  }\n\n  tareaEditando = i;\n\n  const tarea = tareas[i];\n  const modal = document.getElementById(\"tareaModal\");\n  const titulo = document.getElementById(\"fichaTitulo\");\n  const texto = document.getElementById(\"fichaTexto\");\n  const responsable = document.getElementById(\"fichaResponsable\");\n  const completada = document.getElementById(\"fichaCompletada\");\n  const notas = document.getElementById(\"fichaNotas\");\n\n  titulo.textContent = tarea.texto || \"Editar tarea\";\n  texto.value = tarea.texto || \"\";\n  responsable.value = tarea.responsable || \"Ambos\";\n  completada.checked = Boolean(tarea.completada);\n  notas.value = tarea.notas || \"\";\n\n  if (modal) {\n    modal.classList.add(\"active\");\n    document.body.style.overflow = \"hidden\";\n  }\n}\n\nfunction cerrarFicha() {\n  const modal = document.getElementById(\"tareaModal\");\n\n  if (modal) {\n    modal.classList.remove(\"active\");\n  }\n\n  document.body.style.overflow = \"\";\n  tareaEditando = null;\n  renderTareas();\n}\n\nfunction cerrarFichaDesdeFondo(event) {\n  if (event.target && event.target.id === \"tareaModal\") {\n    cerrarFicha();\n  }\n}\n\nfunction actualizarTextoFicha(campo, valor) {\n  if (tareaEditando === null || !tareas[tareaEditando]) {\n    return;\n  }\n\n  tareas[tareaEditando][campo] = valor;\n\n  if (campo === \"texto\") {\n    const titulo = document.getElementById(\"fichaTitulo\");\n    if (titulo) {\n      titulo.textContent = valor || \"Editar tarea\";\n    }\n  }\n\n  actualizarResumen();\n  programarGuardado();\n}\n\nfunction actualizarResponsableFicha(valor) {\n  if (tareaEditando === null || !tareas[tareaEditando]) {\n    return;\n  }\n\n  tareas[tareaEditando].responsable = valor;\n  actualizarResumen();\n  programarGuardado();\n}\n\nfunction actualizarCompletadaFicha(activo) {\n  if (tareaEditando === null || !tareas[tareaEditando]) {\n    return;\n  }\n\n  tareas[tareaEditando].completada = Boolean(activo);\n  actualizarResumen();\n  programarGuardado();\n}\n\nasync function eliminarTareaEditando() {\n  if (tareaEditando === null || !tareas[tareaEditando]) {\n    return;\n  }\n\n  await eliminarTarea(tareaEditando);\n  cerrarFicha();\n}\n\nasync function toggleCompletada(e, i) {\n  if (!tareas[i]) {\n    return;\n  }\n\n  tareas[i].completada = e.target.checked;\n  actualizarResumen();\n  await guardarCambios(true);\n  renderTareas();\n}\n\nfunction actualizarBusqueda(valor) {\n  busquedaActiva = valor;\n  renderTareas();\n}\n\nfunction actualizarOrden(valor) {\n  ordenActivo = valor;\n  renderTareas();\n}\n\nasync function agregarTarea() {\n  const textoInput = document.getElementById(\"nuevaTarea\");\n  const responsableInput = document.getElementById(\"nuevoResponsable\");\n  const notasInput = document.getElementById(\"nuevasNotas\");\n  const completadaInput = document.getElementById(\"nuevaCompletada\");\n\n  const texto = textoInput.value.trim();\n  const responsable = responsableInput.value;\n  const notas = notasInput.value.trim();\n  const completada = completadaInput.checked;\n\n  if (!texto) {\n    alert(\"\u26a0\ufe0f Escribe una tarea antes de a\u00f1adir.\");\n    return;\n  }\n\n  tareas.push({\n    texto,\n    responsable,\n    notas,\n    completada\n  });\n\n  textoInput.value = \"\";\n  responsableInput.value = \"Ambos\";\n  notasInput.value = \"\";\n  completadaInput.checked = false;\n\n  cerrarNuevaTarea();\n  renderTareas();\n  await guardarCambios(true);\n}\n\nasync function eliminarTarea(i) {\n  if (!tareas[i]) {\n    return;\n  }\n\n  const texto = tareas[i].texto || \"esta tarea\";\n\n  if (confirm(`\u00bfSeguro que deseas eliminar \"${texto}\"?`)) {\n    tareas.splice(i, 1);\n    renderTareas();\n    await guardarCambios(true);\n  }\n}\n\nasync function guardarCambios(silencioso = false) {\n  try {\n    const res = await fetch(GUARDAR_URL, {\n      method: 'POST',\n      headers: { 'Content-Type': 'application\/json' },\n      body: JSON.stringify(tareas)\n    });\n\n    if (!res.ok) {\n      throw new Error(\"Error HTTP \" + res.status);\n    }\n\n    actualizarResumen();\n\n    if (!silencioso) {\n      alert(\"\u2705 Cambios guardados\");\n    }\n  } catch (e) {\n    console.error(\"\u274c Error al guardar tareas:\", e);\n\n    if (!silencioso) {\n      alert(\"\u274c Error al guardar\");\n    }\n  }\n}\n\nfunction actualizarResumen() {\n  const total = tareas.length;\n  const fran = tareas.filter(t => t.responsable === \"Fran\").length;\n  const jose = tareas.filter(t => t.responsable === \"Jos\u00e9\").length;\n  const ambos = tareas.filter(t => t.responsable === \"Ambos\").length;\n  const otros = tareas.filter(t => t.responsable === \"Otra persona\").length;\n  const completadas = tareas.filter(t => t.completada).length;\n\n  document.getElementById(\"totalTareas\").textContent = total;\n  document.getElementById(\"tareasFran\").textContent = fran;\n  document.getElementById(\"tareasJose\").textContent = jose;\n  document.getElementById(\"tareasAmbos\").textContent = ambos;\n  document.getElementById(\"tareasOtros\").textContent = otros;\n  document.getElementById(\"tareasCompletadas\").textContent = completadas;\n}\n\nfunction filtrarTareas(tipo) {\n  filtroActivo = normalizarResponsable(tipo);\n\n  document.querySelectorAll('.resumen-card').forEach(card => {\n    card.classList.remove('active');\n  });\n\n  let selector = '.resumen-card.total';\n\n  if (filtroActivo === 'fran') {\n    selector = '.resumen-card.fran';\n  } else if (filtroActivo === 'jose') {\n    selector = '.resumen-card.jose';\n  } else if (filtroActivo === 'ambos') {\n    selector = '.resumen-card.ambos';\n  } else if (filtroActivo === 'otrapersona') {\n    selector = '.resumen-card.otros';\n  } else if (filtroActivo === 'completadas') {\n    selector = '.resumen-card.completadas';\n  }\n\n  const activeCard = document.querySelector(selector);\n\n  if (activeCard) {\n    activeCard.classList.add('active');\n  }\n\n  renderTareas();\n}\n\nfunction exportarTareas() {\n  const filas = [];\n\n  filas.push([\n    \"Tarea\",\n    \"Responsable\",\n    \"Estado\",\n    \"Notas\"\n  ]);\n\n  tareas\n    .slice()\n    .sort((a, b) => {\n      if (Boolean(a.completada) !== Boolean(b.completada)) {\n        return a.completada ? 1 : -1;\n      }\n\n      return String(a.responsable || \"\").localeCompare(String(b.responsable || \"\"), \"es\");\n    })\n    .forEach(tarea => {\n      filas.push([\n        tarea.texto || \"\",\n        tarea.responsable || \"\",\n        tarea.completada ? \"Hecha\" : \"Pendiente\",\n        tarea.notas || \"\"\n      ]);\n    });\n\n  const csv = filas\n    .map(fila => fila.map(celda => `\"${limpiarCSV(celda)}\"`).join(\";\"))\n    .join(\"\\n\");\n\n  const blob = new Blob([\"\\uFEFF\" + csv], {\n    type: \"text\/csv;charset=utf-8;\"\n  });\n\n  const url = URL.createObjectURL(blob);\n  const enlace = document.createElement(\"a\");\n\n  enlace.href = url;\n  enlace.download = \"tareas-boda-fran-y-jose.csv\";\n  enlace.click();\n\n  URL.revokeObjectURL(url);\n}\n\ncargarTareas();\n\nwindow.guardarCambios = guardarCambios;\n<\/script>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>\ud83d\udcdd Tareas de la Boda Organiza pendientes, responsables y tareas completadas. Total 0 Fran 0 Jos\u00e9 0 Ambos 0 Otros 0 Hechas 0 \u2795 A\u00f1adir tarea Pendientes primeroResponsableNombreHechas primero \ud83d\udce4 Exportar A\u00f1adir tarea Crea una tarea nueva en la lista. \u2715 Tarea Responsable AmbosFranJos\u00e9Otra persona Tarea hecha Notas Guardar tarea Cancelar Editar tarea Los cambios [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-754","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Tareas -<\/title>\n<meta name=\"robots\" content=\"noindex, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<meta property=\"og:locale\" content=\"es_ES\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Tareas -\" \/>\n<meta property=\"og:description\" content=\"\ud83d\udcdd Tareas de la Boda Organiza pendientes, responsables y tareas completadas. Total 0 Fran 0 Jos\u00e9 0 Ambos 0 Otros 0 Hechas 0 \u2795 A\u00f1adir tarea Pendientes primeroResponsableNombreHechas primero \ud83d\udce4 Exportar A\u00f1adir tarea Crea una tarea nueva en la lista. \u2715 Tarea Responsable AmbosFranJos\u00e9Otra persona Tarea hecha Notas Guardar tarea Cancelar Editar tarea Los cambios [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/bodafranyjose.com\/index.php\/tareas\/\" \/>\n<meta property=\"article:modified_time\" content=\"2026-04-13T17:03:27+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Tiempo de lectura\" \/>\n\t<meta name=\"twitter:data1\" content=\"12 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/bodafranyjose.com\\\/index.php\\\/tareas\\\/\",\"url\":\"https:\\\/\\\/bodafranyjose.com\\\/index.php\\\/tareas\\\/\",\"name\":\"Tareas -\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/bodafranyjose.com\\\/#website\"},\"datePublished\":\"2025-11-16T18:05:07+00:00\",\"dateModified\":\"2026-04-13T17:03:27+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/bodafranyjose.com\\\/index.php\\\/tareas\\\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/bodafranyjose.com\\\/index.php\\\/tareas\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/bodafranyjose.com\\\/index.php\\\/tareas\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Portada\",\"item\":\"https:\\\/\\\/bodafranyjose.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Tareas\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/bodafranyjose.com\\\/#website\",\"url\":\"https:\\\/\\\/bodafranyjose.com\\\/\",\"name\":\"\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/bodafranyjose.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Tareas -","robots":{"index":"noindex","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"og_locale":"es_ES","og_type":"article","og_title":"Tareas -","og_description":"\ud83d\udcdd Tareas de la Boda Organiza pendientes, responsables y tareas completadas. Total 0 Fran 0 Jos\u00e9 0 Ambos 0 Otros 0 Hechas 0 \u2795 A\u00f1adir tarea Pendientes primeroResponsableNombreHechas primero \ud83d\udce4 Exportar A\u00f1adir tarea Crea una tarea nueva en la lista. \u2715 Tarea Responsable AmbosFranJos\u00e9Otra persona Tarea hecha Notas Guardar tarea Cancelar Editar tarea Los cambios [&hellip;]","og_url":"https:\/\/bodafranyjose.com\/index.php\/tareas\/","article_modified_time":"2026-04-13T17:03:27+00:00","twitter_card":"summary_large_image","twitter_misc":{"Tiempo de lectura":"12 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/bodafranyjose.com\/index.php\/tareas\/","url":"https:\/\/bodafranyjose.com\/index.php\/tareas\/","name":"Tareas -","isPartOf":{"@id":"https:\/\/bodafranyjose.com\/#website"},"datePublished":"2025-11-16T18:05:07+00:00","dateModified":"2026-04-13T17:03:27+00:00","breadcrumb":{"@id":"https:\/\/bodafranyjose.com\/index.php\/tareas\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/bodafranyjose.com\/index.php\/tareas\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/bodafranyjose.com\/index.php\/tareas\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Portada","item":"https:\/\/bodafranyjose.com\/"},{"@type":"ListItem","position":2,"name":"Tareas"}]},{"@type":"WebSite","@id":"https:\/\/bodafranyjose.com\/#website","url":"https:\/\/bodafranyjose.com\/","name":"","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/bodafranyjose.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"}]}},"_links":{"self":[{"href":"https:\/\/bodafranyjose.com\/index.php\/wp-json\/wp\/v2\/pages\/754","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bodafranyjose.com\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/bodafranyjose.com\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/bodafranyjose.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bodafranyjose.com\/index.php\/wp-json\/wp\/v2\/comments?post=754"}],"version-history":[{"count":37,"href":"https:\/\/bodafranyjose.com\/index.php\/wp-json\/wp\/v2\/pages\/754\/revisions"}],"predecessor-version":[{"id":991,"href":"https:\/\/bodafranyjose.com\/index.php\/wp-json\/wp\/v2\/pages\/754\/revisions\/991"}],"wp:attachment":[{"href":"https:\/\/bodafranyjose.com\/index.php\/wp-json\/wp\/v2\/media?parent=754"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}