Turnos de Intervenciones — App
PWA (Progressive Web App) para gestionar y consultar los turnos de intervenciones desde el celular. Una vez desplegada en GitHub Pages, se instala como una app nativa en cualquier teléfono.
✨ Funcionalidades
- 📅 Tres vistas estilo Google Calendar: Mes, Semana y Día
- 🧑🤝🧑 Equipo de intervención + Equipo de apoyo: al tocar cualquier día (en cualquier vista) ves quién está a cargo y quién es el apoyo (calculado automáticamente — el del día siguiente; si se repite, salta al próximo día con un equipo distinto)
- 🔄 Reemplazos rápidos: las píldoras del equipo de intervención son tap-able. Tocás un nombre y elegís el reemplazo de los 15 del roster — para cuando alguien no puede ese día.
- 🎲 Generador de mes inteligente:
- Pantalla previa para definir los equipos (parejas) y el máximo de días por mes de cada uno
- Lógica: L+Ma, Mi+J, V, S+D. El fin de semana rota globalmente entre los equipos (cada finde le toca a un equipo distinto en secuencia)
- Los días de semana se balancean automáticamente al equipo menos usado del mes
- Respeta los topes (máx/mes) y los feriados ya marcados
- 🟡 Feriados: botón "Marcar como feriado" en el panel del día. El día se pinta de amarillo con marca "F"
- 🔍 Filtros: por persona y por equipo del mes (combinables)
- ↶ Deshacer: hasta los últimos 10 cambios por día
- 🖥️ Responsive: en celular es compacta; en compu se expande tipo Google Calendar (1400px)
- 🎨 Equipos coloreados según el código histórico del Excel
- 📱 Instalable como app en Android e iOS (PWA)
- ☁️ Sincronización opcional en la nube (Firebase): los datos viajan entre PC y celular automáticamente
- 💾 Todos los datos quedan guardados en el teléfono (localStorage)
- 🔄 Exportar/importar backups en JSON
- 📶 Funciona sin internet una vez instalada
- 🗂️ Trae cargados ~35 meses históricos del Excel original
- 👆 Navegación rápida: flechas, swipe horizontal, o tap en el título para elegir mes/año
- 🔢 Número de versión visible en el menú
🧭 Menú
Los botones de abajo siguen el orden en que se arma un mes:
| Botón | Qué tiene |
|---|
| 🗓️ Armar | 1 · Equipos y cupos → 2 · Generar / Probar otra distribución → 3 · Revisar reglas. Al final, Borrar mes. |
| 📌 Fechas | Lo que el generador tiene en cuenta: ausencias, cumpleaños, feriados nacionales y feria judicial. |
| 📊 Estadísticas | Abre directo, en grande: tabla equipo × mes (días, findes, viernes o feriados), equidad, este mes, rango e histórico. |
| 📤 Compartir | Imagen/PDF para WhatsApp, link de solo lectura y "Fijar como maestro en la nube". |
| ⚙️ Ajustes | Sincronización, backup JSON, colores, rol del dispositivo y forzar actualización. |
📏 Reglas del generador
El mes se arma en bloques semanales, cada uno para un solo equipo: Lun+Mar, Mié+Jue, Vie y Sáb+Dom. Por semana se asigna primero el finde y después Lun-Mar, Mié-Jue y Viernes.
Antes de generar
- Hacen falta al menos 4 equipos configurados.
- Enero y julio (feria judicial) no se generan: se cargan a mano.
- El mes anterior tiene que tener datos (salvo febrero y agosto, que vienen de feria).
- Si el mes anterior terminó a mitad de un bloque (lunes, miércoles o sábado), el día 1 lo continúa con la misma gente (y el mismo G. MAT. si es domingo).
Fines de semana
- Un equipo no vuelve a hacer finde hasta que pasen 6 findes (con 7 equipos, un ciclo parejo de 7 semanas). Si no hay candidato, se afloja a 3 findes y, en último caso, se elige por puntaje.
- Gestión de materiales: ALVARO y MARTIN se alternan cada finde (los dos días la misma persona). En feria no se asigna.
- Post-feria (febrero y agosto): el equipo que hizo un finde completo en la feria no hace finde en todo el mes; quien trabajó la última semana de feria no hace el primer finde.
Días de semana
- Un equipo no trabaja dos bloques en la misma semana (incluido el finde). Nunca se afloja.
- Descanso post-viernes (por persona): quien trabaja un viernes no vuelve de lunes a viernes de la semana siguiente. El finde sí. Nunca se afloja.
- Descanso post-finde: el equipo del finde no hace el Lun-Mar siguiente.
- Rotación de bloque: un equipo no repite el mismo bloque dos semanas seguidas, y se prefiere darle un bloque distinto al último que hizo.
- Post-feria: quien trabajó la última semana de feria no hace Lun-Vie en la primera semana.
- Entre los candidatos se elige al equipo con menos días en el mes (y, a igualdad, con menos días en el historial).
- Feriados: se trabajan. Si un bloque de días de semana cae en feriado, se prefiere al equipo que menos feriados hizo (en todo el historial cargado). Los feriados en finde siguen la rotación de findes.
Cupos, fechas bloqueadas y desempates
- Cupos automáticos (activados por defecto): los días del mes se reparten en partes iguales (con 7 equipos, 4 o 5 cada uno). Los días que sobran rotan: quien tuvo 5 vuelve a tenerlos recién cuando les tocó a los demás. Se pueden apagar y poner cupos a mano.
- Feria judicial: el día queda sin equipo.
- Cumpleaños y ausencias: el equipo de esa persona no trabaja ese día. Nunca se afloja.
- Si las reglas chocan, se aflojan de la más débil a la más fuerte: rotación de bloque → post-finde → post-feria → partir el bloque entre dos equipos → pasarse del cupo. Lo que se aflojó aparece en el 🔍 Informe de reglas, que también revisa los meses cargados a mano.
📦 Estructura del proyecto
turnos-app/
├── index.html # Punto de entrada
├── styles.css # Estilos
├── data.js # Roster, colores, datos iniciales
├── app.js # Lógica principal
├── manifest.json # Manifest PWA (instalación)
├── service-worker.js # Cache offline
├── icons/
│ ├── icon-192.png
│ ├── icon-512.png
│ ├── icon-maskable-512.png
│ └── apple-touch-icon.png
├── .nojekyll # Para que GitHub Pages no procese como Jekyll
└── README.md
🚀 Cómo subirla a GitHub y desplegarla
Paso 1 — Crear el repositorio
- Andá a https://github.com/new
- Nombre del repo:
turnos-intervenciones (o el que quieras)
- Visibilidad: Public (es necesario para GitHub Pages gratis)
- No marques "Add a README" — lo vamos a subir nosotros
- Hacé click en Create repository
Paso 2 — Subir los archivos
Opción A — Por la web (más fácil):
- En la página del repo recién creado, hacé click en uploading an existing file
- Arrastrá todos los archivos y la carpeta
icons/ de esta app
- Escribí un mensaje de commit como "Primera versión" y hacé click en Commit changes
Opción B — Por la terminal (si tenés Git):
cd turnos-app
git init
git add .
git commit -m "Primera versión"
git branch -M main
git remote add origin https://github.com/TU_USUARIO/turnos-intervenciones.git
git push -u origin main
Paso 3 — Activar GitHub Pages
- En el repo, andá a Settings (arriba a la derecha)
- En el menú izquierdo, hacé click en Pages
- En Source, elegí Deploy from a branch
- En Branch, seleccioná main y / (root), después hacé click en Save
- Esperá unos 30 segundos. Aparecerá una URL como:
https://TU_USUARIO.github.io/turnos-intervenciones/
Paso 4 — Instalar la app en el celular
Abrí esa URL en el navegador del teléfono y:
En Android (Chrome):
- Aparecerá un banner "Agregar a pantalla de inicio". Hacé click.
- O: menú ⋮ → "Instalar app" / "Agregar a pantalla de inicio"
En iPhone (Safari):
- Tocá el botón Compartir (cuadrado con flecha hacia arriba)
- Tocá "Agregar a pantalla de inicio"
Listo, la app queda como un ícono nativo y se abre en pantalla completa.
🔧 Personalización
Cambiar los colores de los equipos
Abrí data.js y editá el objeto COLORS:
const COLORS = {
'Hidalgo': '#FFC000', // amarillo
'Frias': '#8EAADB', // azul claro
// ... etc
};
Agregar o sacar gente del roster
En data.js:
const ROSTER = [
'Cabeza', 'Campi', /* ... */
'NuevaPersona' // ← agregar acá
];
Y asignarle un color en COLORS.
Subir cambios y refrescar la app
Después de cambiar los archivos, subilos al repo y la app se actualiza sola la próxima vez que se abre con internet (el service worker la refresca). Si querés forzar la actualización, abrí la app, ve al menú → "Borrar mes actual" y volvé a abrir.
🔗 Link de solo lectura para el equipo
Una URL corta y fija que le podés mandar al equipo por WhatsApp (o pegar en la descripción del grupo). Entran y ven sólo el calendario: no pueden generar, editar ni borrar. Se actualiza sola cuando guardás cambios, así que se manda una vez y no hay que volver a mandarla.
Configuración (una sola vez)
1. Tener la sincronización en la nube andando. El link lee el calendario desde Firebase. Si todavía no la configuraste: ⚙️ Ajustes → Sincronización en la nube.
2. Habilitar la lectura pública en Firebase. Entrá a tu proyecto → Realtime Database → pestaña Reglas, y pegá esto:
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
},
"public": {
"$sid": {
".read": true,
".write": "auth != null && (!data.exists() || data.child('_owner').val() === auth.uid)"
}
}
}
}
Lo importante de estas reglas: users sigue siendo privado (cada usuario sólo lee y escribe lo suyo), y public es de lectura para cualquiera pero sólo escribible por alguien con sesión iniciada. El visor lee sin loguearse; nadie puede modificar nada desde el link.
3. Generar el link. 📤 Compartir → 🔗 Link de solo lectura → Copiar. Ya lo podés mandar.
Qué se comparte y qué no
| Se comparte | NO se comparte |
|---|
| Turnos de todos los meses | Contraseña del generador |
| Feriados y feria judicial | Configuración de equipos y cupos |
| Reemplazos | Ausencias del personal |
| Colores de las personas | Credenciales de Firebase |
| Cumpleaños | Historial de rotación |
La lista de lo que se publica es una lista blanca en isPublicShareKey() (app.js): si se agrega un dato nuevo a la app, no se publica solo — hay que habilitarlo a propósito.
Tener en cuenta
- Cualquiera con el link ve el calendario, sin contraseña. La URL lleva un token al azar de 32 caracteres para que no se pueda adivinar, pero si alguien la reenvía, quien la reciba entra igual. Es el mismo nivel de exposición que tenía el link de Drive.
- Para revocar un link: borrá la clave
turnos:share_id (⚙️ Ajustes → Exportar/Importar backup, o desde la consola del navegador) y generá uno nuevo. El anterior deja de actualizarse; para que deje de verse, borrá el nodo public/{shareId} viejo desde la consola de Firebase.
💾 Backup y restauración
- Para hacer backup: botón ⚙️ Ajustes abajo → Exportar backup (JSON). Te descarga un archivo
turnos-backup-AAAA-MM-DD.json.
- Para restaurar: ⚙️ Ajustes → Importar backup (JSON) → seleccioná el archivo.
Recomendación: hacer backup periódicamente y guardarlo en Drive o email.
❓ Preguntas frecuentes
¿Necesito un dominio propio?
No. GitHub Pages te da una URL gratis: https://TU_USUARIO.github.io/turnos-intervenciones/
¿Los datos están en la nube?
No, viven en el teléfono (localStorage). Para sincronizar entre dispositivos, usá exportar/importar.
¿Funciona sin internet?
Sí, una vez que la cargaste la primera vez. El service worker la cachea.
¿Cuánto cuesta?
Cero. GitHub Pages es gratis para repos públicos.
¿Y si quiero que solo yo la vea?
Para repos privados, GitHub Pages cuesta plata. Alternativa gratis: Cloudflare Pages o Netlify (ambos permiten hostear desde un repo privado gratis).
📄 Licencia
Uso personal. Modificar a gusto.
📜 Changelog
v85
- 🐛 Estadísticas por equipo con parejas mezcladas: antes, un día con una pareja de dos equipos distintos (ej: Montilla + Milisenda, de antes de un cambio de equipos) se le contaba entero al primer equipo de la lista y el otro quedaba en 0 (Milisenda + Diaz figuraba con 0 en febrero 2026). Ahora cada persona suma medio día a su equipo actual, y las celdas con días repartidos quedan marcadas con un punto violeta. Se aplica a la tabla por mes, Equidad, Este mes y Rango.
- 👤 Estadísticas por persona: en Por mes hay un selector Por equipo / Por persona. La vista por persona muestra los días de cada uno mes a mes (con cualquier pareja) y debajo con quién estuvo cada persona en el período, resaltando a su equipo actual.
v84
- 📊 Estadísticas como botón propio (ya no está dentro de Armar) y en pantalla grande. Nueva pestaña 🗂️ Por mes: una tabla con una fila por equipo y una columna por mes, eligiendo la métrica (días, findes, viernes o feriados), con total, promedio, días sin equipo y los meses con cupo alto marcados. Los meses de feria se ven en gris y no suman.
- 🔍 Revisar reglas como checklist: muestra todas las reglas del turnero con ✅ / ⚠️ / ⛔ y cuántos casos tiene cada una; tocando la regla se ve el detalle y desde ahí se va al día. Se agregaron controles nuevos: un bloque por semana, bloques completos (Lun-Mar y Mié-Jue con el mismo equipo), rotación de bloque, rotación de findes, gestión de materiales en todos los findes (y alternada) y post-feria.
- 📥 Traer el equipo de otro día: en Gestionar equipos de cualquier día, copia el equipo completo de otra fecha (con su 3er integrante) o uno de la lista de equipos. Mantiene la gestión de materiales del día y se puede deshacer.
- 📤 Replicar este día en un rango ahora está disponible en cualquier día (antes sólo en feria). Sólo marca feria judicial si el día de origen es de feria.
v83
- ⚖️ Cupos automáticos, activados por defecto: ya no hace falta balancear antes de generar (se fue la pregunta "¿YA BALANCEASTE?"). Cada mes los días se reparten parejo y el día de más rota entre equipos, así no le tocan 5 siempre a los mismos. Antes la rotación venía apagada y "Auto-balancear" le daba el 5 siempre a los primeros de la lista.
- 🇦🇷 Los feriados se trabajan: el generador ahora asigna equipo en los feriados (antes los dejaba vacíos) y, entre semana, se lo da al equipo que menos feriados hizo.
- ⚖️ Informe de equidad (🗓️ Armar → Informe de equidad, o pestaña Equidad en Estadísticas): para un rango de meses muestra por equipo días, findes, viernes, feriados y meses con cupo de 5, marca quién está por encima y por debajo, el orden de prioridad para los próximos feriados y el detalle de cada feriado con quién lo hizo.
v82
- 🧭 Menú reorganizado por etapas: los cuatro botones pasan a ser 🗓️ Armar, 📌 Fechas, 📤 Compartir y ⚙️ Ajustes (ver la sección Menú). Todo lo que condiciona al generador (ausencias, cumpleaños, feriados y feria) quedó junto en Fechas; se sacaron el "Exportar a imagen" duplicado y la "Variante al azar", que hacía lo mismo que "Probar otra distribución".
- 🐛 El domingo 1 quedaba sin gestión de materiales: cuando el mes arranca en domingo y continúa el finde del mes anterior, no se copiaba el G. MAT. del sábado. Pasaba en noviembre 2026.
- 🐛 Regenerar un mes con meses posteriores ya cargados cambiaba el resultado: el historial tomaba los findes de los meses siguientes como si fueran los más recientes, y eso movía la rotación de findes, la alternancia de G. MAT. y los cupos altos. Ahora sólo cuentan los meses anteriores.
- 🐛 Días vacíos al partir un bloque: si Mié-Jue se partía entre dos equipos y para el segundo día no había candidato, ese día quedaba sin turno aunque se podía cubrir pasando un cupo (pasaba el jueves 27/5/2027). Además, el primer equipo del bloque partido no quedaba marcado como usado en la semana.
- 🐛 El descanso post-finde se aplicaba a toda la semana: la regla es sólo Lun-Mar (así figura en el informe), pero el generador también bloqueaba Mié-Jue y Viernes. Eso trababa el final de mes y forzaba bloques partidos y cupos excedidos.
- Resultado de estos arreglos generando 10 meses seguidos (ago 2026 – jun 2027): de 1 día sin turno y 6 advertencias a 0 días sin turno y 2 advertencias (dos meses con un equipo 1 día por encima del cupo).
- 🐛 La vista previa de "cupo alto este mes" podía no coincidir con lo generado: leía un historial guardado que no registraba el último mes con cupo alto. Ahora usa el mismo cálculo que el generador, y las estadísticas "Histórico total" se calculan en el momento.
- 🐛 Informe de reglas con rotación automática: marcaba "cupo excedido" contra el cupo de la configuración y no contra el cupo rotado que usó el generador.
- 🧹 Se sacó la librería html2canvas, que se descargaba en cada apertura y ya no se usaba.
v81
- ✂️ Link de solo lectura mucho más corto: de ~307 a ~72 caracteres, para que entre en la descripción de un grupo de WhatsApp.
https://alvarogrignola27.github.io/turnointervenciones/#v=uvAXLlTsRwn0qg
- El link era largo porque llevaba la config de Firebase adentro. Ahora, si se completa
PUBLIC_FIREBASE_CONFIG en data.js, sólo viaja el identificador. El modal de compartir arma el bloque listo para pegar y avisa cuántos caracteres quedaron.
- Si
PUBLIC_FIREBASE_CONFIG queda vacío, el link sigue funcionando igual, sólo que largo. Los links ya repartidos siguen andando: se soportan los dos formatos.
- El identificador nuevo pasó de 32 caracteres hexadecimales a 14 en base62 (~83 bits), que sigue siendo imposible de adivinar. Los identificadores ya generados no se tocan.
- Se saca
index.html del final de la URL, que GitHub Pages resuelve igual.
- 🔒 El nodo público ahora sólo lo puede pisar su dueño. La regla anterior era
".write": "auth != null": cualquiera con una cuenta del proyecto (y crear una es gratis) podía sobrescribir el calendario publicado. Ahora el snapshot guarda _owner con el uid de quien lo creó y la regla exige que coincida. Si ya venías usando el link, actualizá las reglas con el bloque nuevo que muestra el modal.
v80
- 🔗 Link de solo lectura (nuevo). Menú ☁️ Datos → "Link de solo lectura". Genera una URL fija para mandarle al equipo: entran y ven sólo el calendario, sin poder generar, editar ni borrar nada. Reemplaza el viejo link de Drive.
- El link no cambia nunca. Se manda una vez y listo: cada vez que guardás cambios, el calendario publicado se actualiza solo. Si alguien lo tiene abierto, se le refresca en vivo.
- Publica sólo lo necesario, con lista blanca. El nodo
users/{uid}/data que usa la sincronización no se puede exponer, porque pushToCloud sube todas las claves turnos:* — incluida turnos:gen_password y la config del generador. Por eso el visor lee de un nodo aparte, public/{shareId}, al que sólo se copian: meses, feriados, feria judicial, reemplazos, colores y cumpleaños. Todo lo demás queda afuera por defecto: si mañana se agrega una clave nueva, no se publica sola.
- El link no lleva credenciales. Sólo el
shareId (token al azar de 32 caracteres, para que la URL no sea adivinable) y los 4 campos públicos de config de Firebase, que están pensados para ir en el cliente. El email y la contraseña de Firebase nunca salen del dispositivo.
- El visor no toca el dispositivo de quien mira. Los datos viven en memoria, no en su
localStorage. Todas las funciones de guardado cortan al entrar. Así, si abrís tu propio link de compartir en tu celular, no te pisa nada.
- Requiere agregar las reglas de
public en Firebase (el modal las muestra listas para copiar). Ver más abajo.
- 🔒 Faltaban acciones en el bloqueo de solo lectura: un dispositivo en modo viewer igual podía usar "Guardar como maestro" (pisando la nube), entrar a la configuración de sincronización o cambiarse el rol solo. Ahora esas acciones también están bloqueadas.
v79
- 🔍 Informe de reglas (nuevo). Menú Generación → "Revisar reglas del mes", y se abre solo al terminar de generar si algo quedó pendiente. Audita el mes sobre los datos guardados, así que también detecta problemas metidos editando días a mano. Chequea:
- Descanso post-viernes (⛔): quien trabaja un viernes no vuelve de lunes a viernes de la semana siguiente.
- Descanso post-finde (⚠️): quien hace sábado/domingo no arranca el lunes o martes siguiente.
- Días sin turno (⛔), ignorando feriados y feria judicial.
- Cupo excedido por equipo (⚠️), cumpleaños trabajando (⚠️) y ausencias trabajando (⛔).
- Reglas que el generador tuvo que aflojar (ℹ️), con el detalle de cuál y en qué días.
- Todas las reglas de "semana siguiente" miran el mes anterior y el siguiente, así que los conflictos en el borde del mes no se escapan. Tocando un ítem se va al día en cuestión.
- 🐛 Los días ya no quedan vacíos en silencio. Los slots de días de semana no tenían ningún fallback: si las reglas se bloqueaban entre sí, el día quedaba sin turno y sólo avisaba un toast de 3 segundos. Pasaba seguido — en 12 meses de prueba quedaban 14 días sin turno, y no por falta de cupo (los equipos llegaban a 4 días teniendo 5 disponibles) sino porque las reglas chocaban sobre el final del mes.
- Ahora se intenta con todas las reglas puestas y, si no hay candidato, se van aflojando por capas de la más débil a la más fuerte: rotación de slot → descanso post-finde → descanso post-feria → partir el slot entre dos equipos → pasarse del cupo máximo.
- El descanso post-viernes nunca se afloja, junto con cumpleaños y ausencias. Es la regla más importante del turnero: se prefiere pasarse del cupo de un equipo antes que romperla.
- Cada relajación queda registrada y se muestra en el informe, así que nunca hay un cambio silencioso.
- Resultado en los mismos 12 meses: 0 días sin turno, 0 violaciones de post-viernes, 0 de post-finde. El costo es que en 4 de 11 meses un equipo queda 1 día por encima de su cupo, y sale avisado en el informe.
v78
- 🐛 La regla del viernes no se respetaba al cambiar de mes. La regla es: si una persona trabaja un viernes, no puede volver de lunes a viernes de la semana siguiente (el fin de semana sí está permitido). Fallaba por tres motivos distintos, todos en el cruce entre meses:
- Días editados a mano quedaban invisibles: el generador identificaba al equipo de un día exigiendo que el par de nombres coincidiera exacto con un equipo de la config. Un día cargado a mano como
Frias + Martinez (que no es ningún equipo) devolvía "no encontrado" y la regla de descanso simplemente no se aplicaba. Ahora, si no hay par exacto, se identifica al equipo por cualquiera de sus integrantes.
- La regla miraba equipos, no personas: ahora se bloquea a todo equipo que tenga alguna de las personas que trabajaron el viernes anterior. Antes se bloqueaba sólo al equipo "titular" de ese viernes.
- Se leía el viernes equivocado cuando el mes anterior terminaba a mitad de semana: si octubre terminaba sábado 31, noviembre leía el viernes 23 en lugar del 30 y arrancaba sin ninguna restricción. El descanso ya no se arrastra como estado entre semanas: cada semana consulta directamente el viernes de la semana calendario anterior, sea del mes que sea.
- La continuidad entre meses sumaba gente de más: al completar un turno que arrancó el último día del mes anterior, se escribía el plantel completo del equipo. Continuar un turno de
Sallas + Ibañez reincorporaba al tercer integrante que no había estado. Ahora se replica la composición exacta del turno original.
- Un viernes feriado ya no hace descansar a nadie: antes se bloqueaba al equipo por un turno que en realidad nunca se trabajó.
- Verificado generando 12 meses corridos: 0 violaciones (antes, entre 1 y 3 en el mismo escenario).
- 🐛 Marcadores del mes viejo al cambiar de mes: al abrir un día de otro mes desde la vista Semana (una semana puede cruzar dos meses) o desde "Editar este día", se cambiaba el mes pero no se recargaban feriados, feria judicial ni reemplazos. Quedaban los del mes anterior, pintados sobre los días del mes nuevo. Ahora se recarga todo el estado del mes.
v77
- 📸 Rediseño del export de imagen (WhatsApp / PDF): el póster que se descargaba quedaba muy distinto del calendario de Excel que se venía compartiendo y de la vista de la app.
- Los dos integrantes del equipo ahora van uno al lado del otro, dentro de una misma cápsula partida al medio. Si el equipo comparte color se lee como un bloque único (igual que el Excel); si cada uno tiene su color, cada mitad lleva el suyo (igual que la vista de mes). Antes los nombres salían apilados uno sobre el otro, que era la diferencia más visible contra el Excel.
- 🐛 La gestión de materiales ya no se pierde: el toggle "Mostrar todos los turnos" arrancaba apagado en los meses regulares, así que el export se descargaba sin las franjas de G. MAT. (ALVARO / MARTIN) ni los terceros integrantes — información que en el Excel siempre estaba. Ahora todos los slots no vacíos se dibujan siempre.
- El toggle pasó a ser "Modo compacto" (apagado por defecto): deja sólo el equipo principal más la gestión de materiales, útil en meses de feria con muchos extras.
- Header con banda de color y subtítulo, nombres de día completos (LUNES, MARTES…), grilla más marcada, celdas de relleno en gris tenue, y feriados / feria / cumpleaños marcados con chips.
- El alto de las celdas se estira cuando el mes tiene poco contenido, así la imagen no sale apachurrada y panorámica.
- Footer con la fecha de actualización, para que en WhatsApp se sepa de cuándo es la versión compartida.
v76
- 🐛 Bug post-feria — finalmente resuelto: en las versiones anteriores
feriaWeekendTeams marcaba a demasiados equipos porque en feria los slots del finde tienen personas mezcladas de teams distintos (ej: slot[0] = "Sallas + Hidalgo" son miembros de teams diferentes). Con TODOS los equipos "marcados", el fallback aflojaba y elegía cualquiera, incluyendo a Milisenda o Campi que fueron protagonistas absolutos.
- Fix — detección precisa de protagonistas:
feriaWeekendTeams ahora requiere que los DOS miembros de slot[0] del finde sean del MISMO equipo (ej: Milisenda+Diaz o Campi+Montilla). Los slots mixtos ya no marcan protagonista.
- Fallback en 3 pases cuando todos los elegibles están agotados:
- Pass A: NO en feriaWeekendTeams NI en postFeriaRestTeams
- Pass B: NO en feriaWeekendTeams (permite postFeriaRest, útil cuando toda la última semana estuvo ocupada)
- Pass C: relajar todo, elegir por score
feriaWeekendCount como score de desempate: cuenta apariciones parciales de cada equipo en slot[0] de findes de feria. El que apareció menos veces gana.
- Distance from end capeada a
teams.length para que equipos nunca vistos en recentWeekends no dominen artificialmente.
- Verificado con el escenario real de las capturas: Milisenda y Campi NO aparecen en ningún finde de agosto; vuelven primero en septiembre (Milisenda sáb 5, Campi sáb 19).
v75
- 🐛 Bug post-feria — última semana también bloqueada del primer finde: el escenario que reportaste — Sallas trabajó martes 28 y miércoles 29 de julio (última semana de feria) y volvía a aparecer en sáb 1 y dom 2 de agosto. La regla de v74 solo bloqueaba equipos que hicieron FINDE en feria, no los que trabajaron la última semana en Lun-Vie.
- Fix: en el primer finde del mes post-feria (weekIdx === 0) ahora también se hard-excluyen los equipos que aparecen en
postFeriaRestTeams (últimos 7 días de feria).
- Fallback de 2 pases: cuando todos los equipos hicieron algo en feria (caso extremo), primero busca candidatos que NO trabajaron la última semana; solo si no hay ninguno, relaja. Verificado: en el escenario donde todos hicieron finde en feria pero solo Milisenda no trabajó la última semana → Milisenda encabeza el primer finde, Sallas al siguiente.
- 🎨 Tile del 3er integrante ya no sale más grande: cuando un equipo tiene 3 miembros (ej: Sallas + Ibañez + Martinez), el 3er nombre iba en un slot separado como nombre solo y usaba fuente 20px, mientras que "Sallas + Ibañez" arriba usaba 17px. Ahora todos los tiles usan la misma 17px para consistencia visual.
v74
- 🐛 Regla post-feria refactorizada — bloqueo TOTAL para findes: reemplaza los enfoques score-based de v72/v73 que fallaban con datos reales. Nueva regla estricta (como pediste):
- Cualquier equipo que haya hecho AL MENOS UN sábado o domingo durante la feria (mes completo enero/julio, no solo última semana) queda HARD-BLOQUEADO de findes en TODO el mes post-feria.
- Esos equipos vuelven a estar disponibles en el segundo mes post-feria, donde aparecen PRIMEROS en la cola porque son los que hace más tiempo no hacen finde regular.
- Fallback inteligente: si TODOS los equipos hicieron finde en feria (caso raro cuando hay muchos participantes por día), se relaja preservando la prioridad — los que hicieron MENOS días de finde en feria salen primero, y en empate el que hizo finde más antiguo.
- Verificado end-to-end: escenario "solo Milisenda + Campi hicieron findes en feria" → agosto sale con Sallas, Cabeza, Frias, Hidalgo, Capdevila (nunca Milisenda ni Campi); septiembre sale con Milisenda primero, Campi segundo, luego el resto.
v73
- 🐛 Bug post-feria — extendido a 2 findes: el fix de v72 cubría solo el primer finde post-feria (weekIdx 0). En meses que empiezan en sábado (como agosto 2026), weekIdx 0 es solo Sáb 1 + Dom 2; el segundo finde (Sáb 8) volvía al round-robin clásico y ahí salían los equipos del primer finde de feria (Milisenda/Diaz) o del segundo (Campi/Montilla). Ahora el algoritmo score-based se aplica a los PRIMEROS 2 FINDES del mes post-feria (weekIdx ≤ 1). Verificado con el escenario real: ni Milisenda ni Campi aparecen en las primeras 2 semanas; salen recién en sáb 22.
- 📸 Botón "Exportar mes a imagen / PDF" en el menú Generación: además de seguir en "Datos y nube", ahora aparece directo en el menú Generación (justo después de "Variante al azar") para que esté más a mano cuando estás trabajando con el mes.
- 🎨 Botones del modal Generar — estilo cat-btn (como los de abajo): "⚖️ Auto-balancear", "Guardar y generar", "+ Agregar equipo" y "Restaurar default" rediseñados con fondo negro + sombra grande + hover lift, para que combinen visualmente con los botones de la barra inferior (Generar/Marcar/Personalizar/Datos). Look mucho más consistente y "tactil".
v72
- 🐛 Bug crítico arreglado — el primer finde post-feria repetía equipos de feria: el escenario que reportaste — Milisenda/Diaz hizo el sáb 4-5 jul (primer finde de feria) y volvía a hacer el sáb 1 ago (primer finde post-feria), o Capdevila aparecía cuando había trabajado el lunes de la última semana de feria.
- Causa: el set
postFeriaRestTeams se aplicaba como HARD exclude solo en el primer pass. En feria casi todos los equipos trabajan algo, así que casi todos quedaban excluidos. El algoritmo caía al SOFT fallback que NO respetaba post-feria, y elegía libremente entre los equipos que SÍ habían trabajado en feria.
- Solución: el primer finde post-feria ahora usa un algoritmo score-based dedicado en vez del round-robin tradicional. Cada equipo recibe un score: +100 si está en los últimos 6 findes, +10 si está en el historial reciente de findes, + (días que trabajó en la última semana de feria × 5). El equipo con menor score gana. Esto naturalmente prefiere equipos que: no hicieron finde reciente, no aparecen en el historial de findes, y/o no trabajaron mucho en feria.
- Verificado con tu escenario (julio 2026 feria + junio 2026): las 3 generaciones (normal, shuffle, random) eligen al equipo Sallas/Ibañez para el sáb 1 ago — no había hecho findes recientes ni había sido protagonista en feria. Milisenda recién aparece en el sáb 22 ago.
v71
- 🎰 Tercera opción de generación — "Variante al azar": nuevo botón en Datos → Generación. A diferencia de "🔀 Probar otra distribución" (que incrementa el shuffle offset secuencialmente), este botón usa un offset aleatorio que se asegura de ser distinto al actual. Sirve cuando ninguna de las dos primeras distribuciones convence y se necesita una variante más distinta.
- 🎨 Botones del modal Generar — mejoras visuales mucho más marcadas: cada card de equipo ahora tiene fondo blanco con borde gris azulado visible y sombra suave (antes eran fondos grises planos sin contorno). Hover effect que levanta la card. Selects y inputs con borde definido + focus ring azul. Botón × rediseñado en card blanco con borde rojo claro. Botón + para 3ra persona con dashed azul. Diferencias claras al pasar el mouse.
v70
- 📐 Exportar imagen para oficio horizontal: las dimensiones del canvas se redujeron para que el calendario entre cómodo en una hoja oficio (Legal) en formato horizontal al imprimir. Reducidos paddings, headers y altura de tiles vs v69. El stylesheet del print modal ahora declara
@page { size: legal landscape } para que el navegador use directamente esa configuración al guardar el PDF.
- 🛠️ G.MAT con tile compacto + prefijo: cuando un slot contiene a ALVARO o MARTIN solos (gestión de materiales), el tile ahora se renderiza más bajo (~32px vs ~50px del normal) y con el prefijo
G.MAT · ALVARO (o G.MAT · MARTIN). Esto refleja visualmente que la gestión no es intervención principal y libera espacio para mostrar más tiles cuando hace falta.
v69
- 🎨 Exportar imagen: soporte multi-tile para feria: en feria (Enero/Julio) los días tienen 2-3 personas extras además del equipo principal, cada una con su color. v68 solo mostraba el slot principal — quedaba incompleto. Ahora:
- Nuevo toggle "🎨 Mostrar todos los turnos del día" en el modal de exportar.
- Default ON en feria (Enero/Julio), OFF en meses regulares (donde típicamente alcanza con la intervención principal).
- Cuando está ON, cada día renderiza un tile vertical por cada slot no-vacío, con el color del nombre principal.
- Tiles dividos en 2 colores cuando un slot tiene 2 personas de equipos distintos (ej:
[Frias, Sallas] se ve mitad azul / mitad naranja).
- Altura de celda adaptativa: se ajusta al máximo de slots en uso en el mes para que ningún tile quede chico.
v68
- 🐛 Rotación de findes post-feria arreglado: el bug que reportaste — Milisenda/Diaz hizo findes 4-5 jul (feria) y Campi/Montilla 11-12 jul, y al generar agosto esos mismos equipos quedaban primeros en la cola. Causa: el algoritmo excluía enero y julio (feria) del rebuild de historial COMPLETAMENTE, así que los findes de feria no contaban como "findes recientes" y los equipos volvían a aparecer al principio.
- Fix: ahora enero/julio se procesan parcialmente — sus findes SÍ se registran en
recentWeekends (con detección flexible de equipo por miembros), pero NO se cuentan días totales ni lastHighMonth (que solo aplican a meses regulares). Esto incluso usa la regla "6 findes hard exclude" del weekend gap: los equipos que hicieron finde en feria pasan a estar bloqueados los primeros 6 findes del mes post-feria.
- 📸 Exportar mes a imagen / PDF (para WhatsApp): nueva acción en Datos. Renderiza el calendario del mes en un canvas grande tipo póster con:
- Título grande con mes y año (
AGOSTO 2026)
- Cabecera Lun-Dom (sábado y domingo con fondo rojo suave)
- Cada día: número grande + equipo de intervención GRANDE con su color (visible desde lejos en una foto)
- Botón "📥 Descargar imagen (PNG)" — perfecto para mandar por WhatsApp como foto
- Botón "📄 Imprimir / PDF" — abre el diálogo de impresión del navegador para guardarlo como PDF
- Sin librerías externas (canvas API puro)
- 🎨 Modal del Generador más prolijo:
- Botón "⚖️ Auto-balancear" con gradient azul + sombra + hover lift
- Card "🔄 Rotación automática" con fondo gradient suave y borde
- "+ Agregar equipo" con borde dashed más estético y hover effect
- "Guardar y generar" / "Restaurar default" rediseñados con efectos visuales
v67
- 🐛 Stats POR EQUIPO en meses pasados arreglado: los meses con reemplazos, config de equipos distinta o feria judicial daban 0 en la sección POR EQUIPO porque el algoritmo exigía un match EXACTO del par (a, b) en slot[0]. Ahora detecta el equipo por mejor coincidencia: cuenta cuántos miembros del equipo (a, b o c) están presentes en el slot principal, y elige el equipo con más matches. Un día con Frias reemplazado por Cabeza (
[Cabeza, Echague]) ahora cuenta correctamente como día del equipo Frias+Echague (ancla = Echague). Meses de feria también muestran datos (cuando alguien del equipo trabaja solo).
- 🛡️ Regla post-feria por INTEGRANTE individual: cuando se genera Febrero o Agosto (después de Enero/Julio de feria), el algoritmo ahora detecta correctamente qué equipos descansan la primera semana. Antes solo detectaba pares EXACTOS de equipo en los slots, pero en feria los integrantes aparecen sueltos o con reemplazos y casi nunca formaban el par exacto. Ahora: si CUALQUIER miembro del equipo (a, b, c) trabajó en CUALQUIER slot de los últimos 7 días de feria, ese equipo descansa toda la primera semana del nuevo mes (Lun-Mar / Mié-Jue / Vie / Sáb-Dom).
v66
- 🔄 Rotación FIFO crítica de cupos altos: implementa la regla pedida por el uso real — un equipo que hace 5 días en un mes NO puede volver a hacer 5 hasta que los OTROS 6 equipos hayan hecho su turno. Ejemplo: si Sallas hace 5 en Agosto, en Septiembre y Octubre quedan otros equipos al frente de la cola, y recién en Noviembre/Diciembre Sallas vuelve a ser candidato a cupo alto.
- Cómo funciona: el historial reconstruido desde los meses persistidos ahora trackea
lastHighMonth por equipo (el último mes-año en que hizo ≥5 días). En computeRotatedMaxes, los equipos se ordenan por (lastHighMonth ASC, totalDays ASC, idx ASC) antes de repartir el template descendente. Los que hace más tiempo no hacen cupo alto van primero.
- Verificación matemática: con 7 equipos cycling a través de 2-3 cincos/mes, cada equipo aparece cada ~2.7 meses en promedio, y la regla "≥6 equipos distintos entre dos cincos del mismo equipo" se cumple para todas las parejas en un test sobre 5 meses (Ago→Dic).
- Confirmación del weekend gap: la regla "un equipo que hace finde espera mínimo 6 findes antes de volver" (
WEEKEND_RECENT_MIN_GAP=6) ya estaba en v60 y sigue activa. Con 7 equipos esto fuerza un ciclo perfecto de 7 semanas. Si los 6 últimos están bloqueados por cumpleaños o ausencias, hay fallback a 3 findes; en último recurso ignora la restricción (caso muy raro).
v65
- ❓ Pregunta de salvaguarda antes de generar el mes: ahora al darle a "Generar mes" aparece un confirm grande "YA BALANCEASTE LOS EQUIPOS??" que recuerda el rango recomendado (máx 5, mín 3) y muestra los cupos totales actuales vs los días del mes. Si los cupos no cuadran con los días, agrega una advertencia con el delta exacto y un tip para usar "⚖️ Auto-balancear para este mes". Si el usuario cancela, abre directamente el modal del generador.
- El prompt NO aparece en regeneraciones (botón "🔀 Probar otra distribución") ni en meses de feria judicial (enero/julio), donde no aplica.
v64
- 🎯 Cupos por equipo más realistas (máx 5, mín 3, target 4): hasta v63 los defaults venían con
maxDays: 9 (sin tope práctico) y los equipos quedaban con cupos desbalanceados. Ahora:
- Nuevos defaults: 3 equipos con cupo 5 y 4 equipos con cupo 4 = 31 (cubre exactamente un mes largo). En el largo plazo, con rotación automática activada, todos los equipos van turnándose entre cupo 5 y cupo 4.
- Botón "⚖️ Auto-balancear cupos para este mes": arriba del listado de equipos en el modal del generador. Ajusta los maxDays para que sumen exactamente los días del mes y todos los equipos tengan 4 o 5 días (diferencia máxima de 1). Funciona para cualquier cantidad de equipos: ej. con 7 equipos hace 4×7=28 en febrero no-bisiesto, 5×2+4×5=30 en abril, 5×3+4×4=31 en marzo, etc.
- Validación visual: si tipeás un valor fuera del rango recomendado 3-5, el input se pinta en ámbar para que lo veas.
- Default de "+ Agregar equipo" bajado de 9 a 4.
v63
- 🐛 Bug del color del nombre en tiles con override de color: cuando le cambiabas el color a Capdevila, Gomez, Milisenda o Diaz (por ejemplo Gomez tomando el color claro de Sallas), el nombre seguía saliendo blanco e ilegible. La causa era un shortcut hardcodeado
WHITE_TEXT que SIEMPRE devolvía blanco para esos 4 nombres sin mirar el color real del fondo. Ahora el color del texto se calcula siempre por luminosidad del fondo aplicado, así un Gomez con fondo claro tiene texto oscuro y un Gomez con su color violeta default sigue teniendo texto blanco.
- ⬅️ Replicar colores a meses pasados: en el modal de Personalizar colores, además del bloque "📋 Replicar a los próximos meses", ahora hay un segundo bloque "📋 Replicar a los meses pasados" con botones ← 1 / ← 2 / ← 3. Misma lógica que el forward pero hacia atrás. Útil cuando armás los colores del mes actual y querés que meses anteriores ya cargados los hereden.
v62
- 🐛 Sección "Otros" duplicada en vista Día — eliminada: en la vista Día (mobile y PC), abajo del card del día aparecían dos secciones legacy ("Gestión de materiales" y "Otros") que volvían a renderizar los mismos slots ya mostrados arriba en 📦 Gestión. Eliminadas ambas. Ahora la vista Día es idéntica a la sección detalle del Mes.
- ✏️ Sección 📦 Gestión ahora es editable: antes era solo lectura (pills coloreadas). Ahora, al entrar a "Gestionar equipos":
- Cada nombre se convierte en un dropdown editable (con Equipos + Otros agrupados).
- Aparece un × al lado de cada pill para quitar a esa persona.
- Aparece un botón "+ Agregar a Gestión" abajo que abre el selector con todo el roster + OTROS.
- La sección "✨ Extras" separada (que solo aparecía en feria) se removió porque ahora 📦 Gestión hace lo mismo y para feria + no-feria (G.MAT en sáb/dom).
- 🚀 Botón "Guardar calendario como maestro en la nube": nueva acción explícita en el menú Datos y dentro del modal de Sincronización. Cuando termines de armar el calendario, tocando este botón:
- Sube TODO el estado local a Firebase con un timestamp especial
_masterTimestamp.
- Los dispositivos nuevos que se conecten van a descargar esta versión y NO van a poder pisarla con sus datos viejos en el escenario de race.
- Mostrá un confirm con 3 puntos antes de ejecutar, para que sea imposible apretarlo sin querer.
- 🛡️ Sync más robusto contra "dispositivo nuevo pisa la nube": nueva flag
_initialPullSucceeded (más estricta que _initialSyncDone de v60). Solo es true si el pull inicial terminó SIN errores. Si la conexión a Firebase tiene cualquier hiccup (timeout, sin internet momentáneo, etc.), los pushes automáticos quedan BLOQUEADOS hasta que el listener confirme que la lectura funciona o el usuario fuerce el push manualmente. Antes con v60 si el pull tiraba excepción, el catch silencioso seguía adelante y habilitaba pushes igual — ese era el agujero.
v61
- 📊 Footer compacto en modo viewer: como en v60 se ocultaban los 4 botones de abajo en modo viewer, no quedaba forma de ver la versión actual ni de forzar una actualización. Agregué un footer fijo abajo del calendario que aparece SOLO en modo viewer, con:
- Versión X a la izquierda (sincronizada con
APP_VERSION actual).
- 🔄 Buscar actualización a la derecha — dispara
checkForUpdate(): borra el caché, desregistra el SW y recarga con la versión nueva del servidor.
- 🐛 Bug del duplicado en feria arreglado: en feria + "Gestionar equipos" activo, JUAN DIAZ LOZA / JUAN PABLO GODOY / MARTIN / ALVARO aparecían DOS veces — una en la sección 📦 GESTIÓN (lectura) y otra en ✨ EXTRAS (editable). Confundía. Fix: la sección Gestión se oculta cuando estás en modo edición (porque ya tenés la misma info en Extras, además editable). En modo lectura, Gestión sigue apareciendo como antes (es la única forma de ver esa info ahí).
v60
- 🔒 Modo viewer ahora oculta los 4 botones de abajo (Generar/Marcar/Personalizar/Datos): cuando el dispositivo está en modo "solo lectura", la barra inferior con los 4 botones de acciones desaparece completamente. Solo queda visible el calendario, los filtros, el toggle de vista (Mes/Semana/Día) y el botón HOY. Más espacio útil y cero posibilidad de tocar acciones de edición sin querer.
- 🔓 Candado discreto en el header: como ya no hay botón "Datos" en modo viewer, agregué un candado 🔒 chiquito amarillo al lado de las flechas del header. Al tocarlo se dispara el prompt de contraseña para volver a modo editor. Solo aparece en modo viewer; en modo admin queda oculto.
v59
- Contraseña
Ecif2026# configurada en data.js para desbloquear modo editor desde viewer.
v58
- 🔑 Contraseña para desbloquear el modo editor: en
data.js ahora hay 2 constantes nuevas:
DEFAULT_ROLE → 'admin' (default) o 'viewer'. Define el rol que arrancan los dispositivos NUEVOS al instalar la app por primera vez. Si vas a desplegar en los celulares del equipo, ponelo en 'viewer'.
ADMIN_UNLOCK_PASSWORD → vacía por default. Si la completás (ej: 'turnos2026'), pasar de viewer → admin va a pedir esa contraseña en cada dispositivo donde alguien intente desbloquear. Bajar de admin → viewer NUNCA pide contraseña (cualquiera puede "auto-restringirse").
- 🔓 Botón cambia dinámicamente: cuando estás en viewer y hay password configurada, el botón del menú dice "🔓 Desbloquear modo editor (pide contraseña)". Si no hay password, dice simplemente "🔓 Cambiar a modo editor".
- Si meten password incorrecta: aparece alerta
❌ Contraseña incorrecta. El dispositivo sigue en modo solo lectura. y el rol no cambia.
- ⚠️ Sigue siendo soft security — alguien con DevTools puede leer la contraseña en
data.js. Es una traba para uso normal, no para usuarios mañosos. Para seguridad real necesitarías usuarios separados en Firebase con reglas de permisos.
v57
- 🐛 Bug del cambio de rol arreglado: en v56 la sección "Rol del dispositivo" no se veía porque tenía un
data-section="role" que no coincidía con ningún tab del menú. Ahora está adentro de la sección Datos del menú (Datos → ☁️ DATOS Y NUBE + 👤 ROL DEL DISPOSITIVO), bien visible al final con su botón "🔒 Cambiar a modo solo lectura" y la explicación de qué hace cada modo.
- 🎨 Selector "↩ copiar color de…" en el modal de Colores: en cada fila del modal de colores, al lado del input de color, ahora hay un dropdown con todas las otras personas. Al elegir una, esa persona toma el mismo color exacto que la elegida. Ejemplo: Celina selecciona "Cabeza" → Celina queda del mismo verde que Cabeza para que sea claro quién la está cubriendo durante una ausencia / reemplazo prolongado. Funciona tanto en modo global como en modo mes.
- 📋 Botón "Replicar colores a próximos meses": en el modal de Colores, cuando estás en modo mes y tenés colores especiales configurados, aparece abajo un bloque azul con 3 botones: → 1 mes, → 2 meses, → 3 meses. Tocás cualquiera y los overrides de color de ese mes se copian a los meses siguientes consecutivos. Confirma antes con la lista de meses afectados y avisa que sobrescribe los colores especiales que esos meses ya tengan.
v56
- 🖼️ Export sin leyenda de equipos: la sección "🤝 EQUIPOS" se removió del export como imagen. Ahora la grilla del calendario y los reemplazos/ausencias ocupan más espacio, queda más grande y legible.
- 🔌 Auto-conexión a Firebase con credenciales embebidas: nueva constante
AUTO_CONNECT_FIREBASE en data.js (vacía por default). Si la completás con tu email y password antes de subir el repo, todos los dispositivos que abran el link se conectan SOLOS a la base de datos compartida — sin tener que configurar manualmente. La descarga inicial de la nube sigue siendo bloqueante (no pisa datos). Si dejás las credenciales vacías, sigue funcionando como antes (config manual). ⚠️ Tener en cuenta que cualquiera con acceso al código fuente verá las credenciales — solo usar para herramientas internas.
- 👤 Roles "soft" admin / viewer: nueva sección en el menú Datos para cambiar el rol del DISPOSITIVO actual. Default ✏️ admin (puede editar todo, como hasta ahora). Cambiando a 👀 viewer:
- Se ocultan los botones "Gestionar equipos", "+", "×", "☆", "⚖" en el card del día.
- El menú sigue mostrando botones de edición pero al apretarlos sale toast
🔒 Modo solo lectura activado — no se puede modificar.
- Aparece un badge amarillo "👀 solo lectura" en la esquina del header.
- La sincronización con la nube sigue activa (recibe cambios de otros dispositivos en tiempo real).
- Es un control de UX, no de seguridad: alguien con DevTools puede saltarlo. Útil para que el equipo solo consulte sin riesgo de tocar algo sin querer.
v55
- 🧱 Tiles del mes con extras apilados full-width en feria: cuando un día de feria tiene 1, 2 o 3 personas extras (más allá de Intervención + Apoyo), cada extra ocupa una fila completa con su nombre centrado, una abajo de la otra. Mucho más legible que las pills pequeñas lado a lado. Si hay 4+ extras, cae al formato compacto anterior para no romper la grilla.
- 📦 Sección "Gestión" en el detalle del día: en el card del día (modo lectura, sin tener que abrir "Gestionar equipos"), después del Equipo de Intervención y Apoyo aparece una sección 📦 GESTIÓN con la persona o personas asignadas. Útil para sábados/domingos donde queda visible al instante quién hace Gestión de Materiales. En feria, lista los extras ahí también. Si no hay nadie en esa categoría, la sección no aparece.
v54
- 🐛 Bug del 3er miembro (Martinez) arreglado: cuando borrabas a Martinez (o cualquier 3er miembro de un equipo de 3) con la × del pill, se borraba bien de los datos pero el pill vacío seguía apareciendo en el panel. Causa: el código mostraba el 3er miembro si estaba en los slots del día O si la config del equipo lo definía como de 3 personas. Como la config siempre dice "Sallas+Ibañez+Martinez", aunque borrabas Martinez del día específico, igual aparecía como pill vacía. Fix: ahora el 3er miembro solo se muestra si está realmente en los slots del día. Si lo borrás, desaparece. Para re-agregarlo usás el "+" del equipo de intervención.
- ✨ Sección Extras visible en feria judicial dentro de "Gestionar equipos": cuando un día está marcado como feria y activás "Gestionar equipos", ahora aparece una sección ✨ EXTRAS (N) entre los equipos y los Reemplazos. Cada extra se ve como un dropdown editable (con el color de la persona) + un × para borrarlo. Abajo hay un botón "+ Agregar extra" que abre un picker con grupos "Equipos" (ROSTER completo) y "Otros" (Juan Diaz Loza, Juan Pablo Godoy, MARTIN, ALVARO). Los extras se agregan en los slots 2+ (no tocan Intervención=slot 0 ni Apoyo=slot 1). Permite los casos típicos de feria con 5-6 personas trabajando el mismo día. Fuera de feria, la sección no aparece (no aplica).
v53
- 🚀 Anti-cache agresivo para que las actualizaciones lleguen YA: arregla el caso donde el dispositivo no detecta las versiones nuevas y queda atascado en una vieja. Tres capas:
- Meta-tags
Cache-Control: no-cache, no-store, must-revalidate en el HTML — el navegador siempre revalida el index con el servidor.
updateViaCache: 'none' en el registro del Service Worker — el navegador NO usa su caché HTTP para chequear si el SW cambió (antes podía servir el SW viejo hasta 24 horas).
fetch(..., { cache: 'no-cache' }) en el SW para HTML/JS/CSS — el SW también saltea la caché HTTP al ir a buscar archivos nuevos.
- Cache-busting con
?v=53 en los imports de app.js, data.js y styles.css desde el HTML — cada release cambia el sufijo y fuerza descarga fresca.
- 🟠 Botón "Forzar actualización" más visible y explicado: renombrado de "Buscar actualización" a "🔄 Forzar actualización (limpiar caché)", con estilo destacado en amarillo y texto explicativo abajo: "¿No ves los últimos cambios? Tocá esto para descargar la versión más nueva." Internamente desregistra TODOS los SW, borra TODAS las caches y recarga con cache-bust. Garantizado.
v52
- 🔴 Banner de actualización movido arriba de toda la app: el aviso de "nueva versión disponible" ya no vive sólo dentro del menú Datos. Ahora aparece como un banner rojo full-width en el tope absoluto de la pantalla, sticky (se queda visible aunque scrollees), imposible de pasar por alto. Cuando hay update aparece automáticamente, con texto "● Hay una versión nueva disponible. Tocá para actualizar." y un botón blanco grande "↻ Actualizar ahora". El badge verde/rojo en el menú Datos sigue funcionando como antes (confirmación adicional del estado).
- Verificación de feria con OTROS en dropdowns: en v51 los dropdowns en feria ya muestran "Equipos: 15 + Otros: 4" — si no se veían era porque el dispositivo tenía cacheada una versión anterior. Una vez actualizado a v52 (con el banner imposible de ignorar), el problema queda resuelto definitivamente.
v51
- 🟢🔴 Indicador de versión con detección automática de actualizaciones: nuevo badge en el menú Datos que muestra el estado de la app:
- 🟢 Verde "● Versión 51 · actualizada" cuando estás en la última versión disponible.
- 🔴 Rojo "● Versión 51 · hay una nueva" + botón grande rojo "🔴 Hay una versión nueva — Tocar para actualizar" cuando el Service Worker detecta una versión nueva descargada.
- Cómo funciona: el SW chequea actualizaciones cada 5 minutos mientras la app está abierta. Cuando hay una versión nueva en el servidor, el SW la descarga en background pero NO la activa automáticamente — espera a que el usuario aprete el botón. Esto evita pisar el trabajo en curso. Al tocar el botón, el SW recibe
SKIP_WAITING y toma el control; el listener controllerchange recarga la página automáticamente con la versión nueva ya activa.
- Detección al abrir la app: si al abrir hay un SW esperando (caso típico: actualización detectada en otra pestaña/sesión), el badge ya aparece en rojo de entrada.
- Animación sutil: el punto rojo del badge parpadea suavemente para que se note sin ser molesto.
v50
- 🏛️ En feria: OTROS disponibles en los dropdowns de Intervención y Apoyo: en días marcados feria judicial, los dropdowns de equipos ahora muestran tanto los miembros del ROSTER (Frias, Echague, Hidalgo, etc.) como los OTROS (Juan Diaz Loza, Juan Pablo Godoy, MARTIN, ALVARO), separados en grupos visuales ("Equipos" y "Otros"). Esto resuelve el caso típico donde 3 de los 4 OTROS trabajan el mismo día en feria. Fuera de feria, los dropdowns mantienen sólo el ROSTER (los OTROS se asignan automáticamente como G.MAT en sáb/dom).
- 🔥 BUG CRÍTICO de sincronización ARREGLADO — versión vieja pisando la nube: un dispositivo nuevo que se conectaba a Firebase por primera vez podía pisar la nube con su estado local vacío (o con defaults pre-cargados de la versión cacheada) antes de que llegara el snapshot remoto. Causa raíz: durante la inicialización del app, varias funciones llaman
scheduleCloudPush() (cargar DEFAULT_BIRTHDAYS, etc.), dejando un timer pendiente. Cuando finalmente Firebase autenticaba, ese push pendiente disparaba y sobrescribía la nube ANTES de que llegara el listener con los datos buenos. Fix de raíz: nueva flag _initialSyncDone que bloquea TODO push hasta que initFirebaseSync haya completado un pull bloqueante (once('value')) y aplicado los datos remotos. Recién después se habilita el push y se setea el listener para cambios incrementales. La flag se resetea al desconectar para forzar otro pull al volver a conectar.
- 🔀 Probar otra distribución (regenerar): nueva opción en el menú Generar al lado de "Generar mes". Cuando regenerás el mes con esta opción, el algoritmo aplica un
shuffleOffset al índice inicial del rotador de findes, produciendo una distribución DIFERENTE manteniendo TODAS las reglas (gap 6 findes, descansos, cumpleaños, ausencias, etc.). Cada llamada sucesiva incrementa el offset (1, 2, 3, ..., vuelve a 1 después de 7), así podés probar varias variantes hasta que te guste. Verificado: 1ra generación → Sallas/Cabeza/Milisenda/Campi/Capdevila; 2da con shuffle → Campi/Sallas/Cabeza/Milisenda/Capdevila. Distinto pero válido.
v49
- 🎨 Exportación PDF/imagen profesional, sin torta de cumpleaños: la imagen del mes ahora se renderiza desde cero (no clona la vista). Layout corporativo: header con franja azul, título "Turnos de Intervenciones" + mes en grande a la izquierda, fecha de emisión a la derecha; grilla limpia Lun-Dom con headers grises (Sáb/Dom en rojo); cada día con pills coloreadas de los equipos + 📦 G.MAT; tags FERIA / FERIADO cuando aplica; bloques inferiores con Reemplazos del mes, Ausencias del mes y leyenda de Equipos con todos los miembros; footer con marca y versión. NO incluye iconos de cumpleaños (🎂) — la imagen es para uso institucional.
- 🗑️ Botón "Borrar este día": nuevo botón rojo al final de la sección "Gestionar equipos" del card del día. Al apretarlo confirma con detalle qué se va a borrar (equipos, reemplazos, marcadores de feriado/feria, G.MAT, extras) y limpia todo lo del día específico. Equivale a la opción "Borrar mes" pero acotada a un solo día.
v48
- 🧹 Extras removido de "Gestionar equipos": la sección ✨ Extras se sacó del modo Gestionar equipos. Los días feria con 4+ personas igual funcionan: usás "+" del Intervención (slot 0) y "+" del Apoyo (slot 1) para cargarlos. Si necesitás una 5ta persona, otro "+" del Apoyo la pone en un slot adicional. Estructura final del modo Gestionar equipos: Equipos + Reemplazos + G.MAT (Sáb/Dom) + Replicar (Feria).
- 👤 Ausencias planificadas: nueva opción en el menú Generar. Permite cargar ausencias por rango de fechas para cualquier persona (roster + otros). Cada ausencia bloquea al equipo de esa persona para que el generador no le asigne turnos en esos días. Funciona igual que el bloqueo por cumpleaños (hard exclude). Modal con lista de ausencias activas (con × para borrar) y formulario para agregar (persona + Desde + Hasta). Las ausencias se persisten cross-month y se sincronizan a la nube. Verificado: Frias ausente del 10-15 ago → el generador asignó Hidalgo, Sallas, Campi, Milisenda en esos días, sin Frias.
v47
- 🧹 "Gestionar día" eliminado: el panel colapsable "⚙️ Gestionar día" se removió por completo. Todas sus opciones quedaron integradas arriba a simple vista:
- Feriado → botón rápido ☆ en la barra superior
- Feria judicial → botón rápido ⚖ en la barra superior
- Reemplazos → dentro de "Gestionar equipos"
- Extras → dentro de "Gestionar equipos"
- Replicar día (feria) → dentro de "Gestionar equipos" (solo cuando el día está marcado como feria)
- Estructura final del card del día:
- Barra:
[☆] [⚖] ··· [✎ Gestionar equipos]
- Equipo de Intervención (con
+ en edit)
- Equipo de Apoyo (con
+ en edit)
- Al activar Gestionar equipos: Reemplazos → Extras → G.MAT (Sáb/Dom) → Replicar (Feria)
v46
- 🔧 "Editar" renombrado a "Gestionar equipos": el botón en la barra superior del card del día ahora dice "✎ Gestionar equipos" (en lugar de "Editar"). Hace lo mismo: activa los dropdowns para cambiar gente y los botones "+" para agregar.
- ↪ Reemplazos movido al modo "Gestionar equipos": cuando activás el botón, además de los dropdowns aparece la sección Reemplazos justo debajo de los equipos, con su botón "+ Agregar reemplazo". Antes estaba dentro de "Gestionar día"; ahora queda más cerca de los equipos.
- 📦 Gestión de Materiales editable inline (sólo sábado/domingo no-feria): cuando estás en sábado o domingo (y no es feria judicial), al activar "Gestionar equipos" aparece también la sección 📦 GESTIÓN DE MATERIALES con un dropdown para elegir entre ALVARO, MARTIN o "— sin asignar —". Permite cambiar manualmente quién hace G.MAT ese día sin tocar el resto del equipo. Hint visible: "Alterna Alvaro/Martín cada finde (asignado automáticamente al generar)". En días de semana o feria, la sección no aparece (no aplica).
- Estructura final del card del día:
- Barra superior:
[★] [⚖] ··· ✎ Gestionar equipos
- Equipo de Intervención
- Equipo de Apoyo
- (Si Gestionar equipos activo) Reemplazos + G.MAT (Sáb/Dom)
- Gestionar día → Extras + Marcadores
v45
- ⭐ Botones rápidos Feriado / Feria judicial arriba del card: ahora al tocar un día, arriba a la izquierda aparecen 2 botones cuadrados al lado del "✎ Editar": ☆ para feriado y ⚖ para feria judicial. Tocás una vez y queda marcado (el botón se pone en color: feriado amarillo, feria rojo). Volvés a tocar y lo quitás. Un paso menos: ya no hace falta abrir Gestionar día → Marcadores. Las opciones siguen estando en Gestionar día también, no se rompió nada.
- 📆 Estadísticas con rango personalizado (Desde / Hasta): nueva pestaña "📆 Rango" en el modal de Estadísticas, entre "Este mes" e "Histórico total". Cuando la elegís, aparecen 4 selectores arriba (mes y año Desde, mes y año Hasta). Cambia automáticamente al ajustar los selectores. Calcula días por equipo y por persona en TODO el rango seleccionado, sumando los meses persistidos. Default: Enero-mes actual del año en curso. Ejemplo: Agosto-Octubre 2026 muestra "Sallas+Ibañez 15 días, Capdevila+Gomez 14, ...". Si elegís Desde > Hasta, las invierte automáticamente.
v44
- 🐛 BUG CRÍTICO ARREGLADO — feria judicial bloqueaba el día: cuando marcabas un día sin datos como feria judicial (típico en enero o julio), un error JS rompía toda la renderización del panel. Síntomas: el botón seguía diciendo "Marcar como feria judicial" en lugar de cambiar a "Quitar", no aparecía "Replicar este día", no se podían cargar personas — el día quedaba "bloqueado" hasta hacer "Borrar mes actual". Causa raíz: en
buildDayInfoBlock, cuando el día no tenía datos, slots era null en lugar de [] (incoherente con el resto del código). Después en la lógica de feria hacía slots[1] → crash con Cannot read properties of null (reading '1'). Fix: slots ahora siempre es array (|| [] en lugar de || null), coherente con el resto del código. Verificado: cero errores JS, panel re-renderiza completo, "Quitar feria judicial" y "Replicar" aparecen, dropdowns vacíos funcionan, se puede cargar gente.
v43
- 🛠️ Bug enero 2027 — panel del día "en blanco" al editar: cuando un día no tenía equipo asignado y entrabas en modo Editar, sólo aparecía un placeholder "Sin equipo asignado" sin dropdowns para elegir. Ahora si entrás en modo Editar y no hay equipo, aparecen 2 dropdowns vacíos en Equipo de Intervención para que elijas directamente sin tener que pasar por el "+".
- 🛌 Descanso post-feria en febrero/agosto: cuando generás el mes siguiente a un mes de feria (febrero después de enero, agosto después de julio), el algoritmo recolecta todos los equipos que aparecieron en la última semana del mes de feria y los pone en el
restExclude de la PRIMERA semana del mes nuevo. Así, los que vienen trabajando del 16 al 31 de enero no arrancan febrero — el algoritmo prefiere a los que estaban descansando (los que hicieron 1-15 de feria o los que no entraron a feria).
- 📦 Gestión de Materiales auto-asignada alternando Alvaro/Martín cada finde: el generador ahora asigna automáticamente ALVARO o MARTIN como Gestión de Materiales en cada finde (sábado + domingo), alternando entre ellos. Si el último G.MAT fue ALVARO, este finde es MARTIN, y viceversa. La alternancia es persistente cross-month (se guarda y se recupera con
rebuildHistoryFromMonths). NO se asigna en findes de feria. Verificado en Agosto 2026: MARTIN → ALVARO → MARTIN → ALVARO → MARTIN, alterna perfecto.
v42
- ✨ Sección "Extras" en Gestionar día: nueva sección debajo de "Reemplazos" para asignar personas de OTROS (Juan Díaz Loza, Juan Pablo Godoy, Alvaro, Martín) como extras del día. Útil principalmente para feria judicial donde tres o cuatro de esos pueden trabajar el mismo día. Cada extra se ve como pill de color con × para quitarlo. Botón "+ Agregar extra" abre un picker con los OTROS.
- 🏛️ En feria los extras NO se muestran como "Gestión de materiales": en días marcados feria judicial, los tiles del calendario (Mes y Semana) muestran a ALVARO y MARTIN como pills normales con su nombre, no como "📦 G. MAT.". La etiqueta de gestión de materiales queda reservada para sábados y domingos fuera de feria.
- Estructura final del panel Gestionar día: Reemplazos → Extras → Marcadores (feriado / feria judicial / replicar día).
v41
- 🐛 Apoyo en feria escribía sobre intervención: bug crítico. En días feria, al cambiar una persona del Equipo de Apoyo, el cambio iba al slot[0] (intervención) y reemplazaba a alguien del equipo de intervención. Causa: el cálculo de
apSlotIdx usaba findTeamSlot que devuelve el primer slot con equipo (= slot 0). Ahora cuando es feria, se fuerza apSlotIdx = 1 (slot del apoyo). Verificado: en día feria con sólo intervención cargada, al elegir Capdevila en el primer dropdown del Apoyo, se crea correctamente [["Frias","Echague"],["Capdevila",null]] con la intervención intacta.
- Sobre los dropdowns grises: cuando el día feria todavía no tiene apoyo cargado, los dropdowns del Apoyo aparecen vacíos con "—" (grises) — es el estado vacío esperando que elijas. No es bug, es la indicación visual de que falta seleccionar.
v40
- 🏛️ Feria judicial: 4 personas en el mismo día como 2 equipos: cuando un día está marcado como feria judicial, el panel muestra las primeras 2 personas como Equipo de Intervención (slot 0 del mismo día) y las otras 2 como Equipo de Apoyo (slot 1 del MISMO día, no del día siguiente). Antes el apoyo se buscaba siempre en el día siguiente. También se oculta la nota "Entra el ..." porque no aplica en feria. El "+" en cada equipo agrega al slot correspondiente (intervención → slot 0; apoyo → slot 1) manteniendo el 2x2 prolijo.
v39
- 🪟 2x2 para 4 personas en feria: cuando agregás personas con el "+", el sistema ahora rellena los huecos existentes en las filas antes de crear filas nuevas. Así, en días de feria judicial con 4 personas, queda 2 arriba y 2 abajo (en lugar de 2 arriba + 1 + 1 sueltas). Aplica también a días normales.
- ♻️ Regeneración no se contamina con la generación anterior: bug encontrado. Cuando regenerabas un mes una segunda vez, el algoritmo seguía viendo los findes y el uso de la 1ra generación → la rotación quedaba desbalanceada. Ahora el historial (recentWeekends, weekendIdx, teamHistory) se RECONSTRUYE desde cero cada vez, escaneando todos los meses persistidos pero EXCLUYENDO el mes que se está regenerando. Resultado: la regeneración es determinística y respeta exactamente las mismas reglas siempre. También se excluyen enero/julio (feria) del rebuild para que no contaminen la rotación normal. Verificado: regenerar Ago 2026 dos veces da resultado idéntico.
v38
- 📋 Replicar día en un rango (feria judicial): cuando un día está marcado como feria judicial, en "Gestionar día" aparece la opción "📋 Replicar este día en un rango". Abre un modal con dos campos (desde / hasta) y copia las personas asignadas a todos los días del rango, marcando también feria judicial en cada uno. Por defecto sugiere desde el día siguiente hasta el 15 o el fin de mes (según convenga). Pensado para feria de enero/julio donde típicamente las mismas personas hacen del 1 al 15 y otras del 16 al 31 — cargás el día 1, replicás hasta el 15, y después modificás puntualmente lo que necesites.
v37
- 🛌 Descanso post-finde (Sáb-Dom → no Lun-Mar inmediato): bug en la lógica de generación detectado. Cuando un mes arrancaba en Sáb-Dom (como agosto 2026), el equipo asignado al finde inicial podía aparecer también en Lun-Mar de la semana siguiente — porque el
used se resetea por semana y no había tracking cruzado. Ahora se mantiene un prevWeekendTeamIdx que se agrega al restExclude de la siguiente semana, así el equipo del finde descansa al menos hasta Mié-Jue. Verificado con 5 regeneraciones consecutivas (Ago-Nov 2026): ningún equipo de finde aparece en el Lun-Mar siguiente.
v36
- 🔄 Sync Firebase bidireccional real-time (incluye borrados): el listener de Firebase ya existía pero tenía un bug — cuando borrabas un mes en PC, mobile recibía el snapshot pero solo APLICABA las claves recibidas (no detectaba las que faltaban). Ahora
applyRemoteData también elimina del localStorage local cualquier clave turnos:* que ya no esté en el snapshot remoto. Así, borrar un mes en PC se refleja al instante en mobile y viceversa. Toast informativo cuando se aplican borrados ("🔄 N cambios sincronizados (incluye borrados)").
- 🗑️ Borrar mes con limpieza completa: ahora también elimina marcadores de feriado/feria judicial, reemplazos y overrides de colores del mes. Push inmediato a la nube.
- ⚖️ Enero y julio (feria judicial) excluidos del generador: si intentás generar enero o julio, aparece un cartel explicando que son meses de feria judicial y los equipos rotan distinto. No se genera nada automático. Los meses siguientes (febrero y agosto) saltan el check de continuidad para que puedas generar normalmente.
- 🔁 Rotación de slot semanal por equipo: agregado tracking del último slot semanal que hizo cada equipo (Lun-Mar / Mié-Jue / Vie). Al volver a tocar, el algoritmo PREFIERE darle un slot distinto al que tuvo antes. Ej: si Frias hizo Mié-Jue, la próxima vez le toca Lun-Mar o Vie. Es preferencia soft (no hard) — si no hay alternativa, igual se respeta la rotación principal. Verificado con generación de Ago-Oct 2026: ningún equipo repite el mismo slot semanal dos veces consecutivas.
v35
- 🔄 Rotación de findes mejorada (no repetir antes de 6 sábados): antes la lógica solo bloqueaba al equipo del finde anterior y se reseteaba mes a mes — eso provocaba que, por ejemplo, Capdevila+Gomez hiciera el 15/Ago y volviera el 12/Sep (solo 3 findes después). Ahora hay un historial cross-month de los últimos findes y al menos deben pasar 6 sábados antes que un equipo vuelva a hacer finde. Con 7 equipos, eso significa rotación pareja perfecta. Verificado con generación de 5 meses seguidos (Ago–Dic 2026): todos los equipos respetan el gap, salvo un caso forzado por cumpleaños (4-oct = Gómez) que entra al fallback. Si tenés meses ya generados antes de v35 conviene regenerarlos para que arranque la nueva rotación.
v34
- 🧹 Modo edición simplificado: cuando entrás en modo Editar ya no aparece la sección "FILAS DEL DÍA" abajo (era redundante con el "+" al lado de cada equipo). Solo queda lo necesario: los selects de cada equipo, el "+" para sumar persona, y un botón "Deshacer" si hubo cambios.
- ❌ Botón × para quitar persona extra: cuando agregás un 3ro al equipo (o ya viene uno predefinido como Martinez), en modo Editar aparece una × roja al lado de la pill para quitarlo directamente. Funciona igual en intervención y en apoyo.
- 🎲 "Borrar mes" movido a Generar: la opción "🗑️ Borrar mes actual" ya no está en Datos. Ahora vive en 🎲 Generar junto a "🎲 Generar mes", que es donde tiene más sentido.
- ⌃ Flechita para cerrar el panel del día: arriba a la derecha del título del día ("Viernes 5") hay un botón ⌃ que cierra el panel completo. Más rápido que tocar el día de nuevo en el calendario.
v33
- 🐛 Bug HOY arreglado: antes el botón HOY tenía la clase
.vt y disparaba el cambio de vista a undefined, dejando la pantalla en blanco. Ahora HOY es un botón independiente con su propio handler.
- 📐 HOY ancho completo abajo del view-toggle: el layout ahora es Mes / Semana / Día arriba y 📅 HOY ancho completo abajo cubriendo los 3 tabs. Más fácil de tocar.
- ✎ Botón Editar arriba a la derecha del tile: la edición sale del panel "Gestionar día" y va arriba a la derecha del bloque de equipos como un botón rápido. Al tocarlo cambia a "✓ Listo".
- ➕ Botón "+" al lado de cada equipo en modo edición: cuando entrás en modo edición, aparecen botones "+" punteados a la derecha de Equipo de Intervención y Equipo de Apoyo. Permiten agregar otra persona al equipo (modal con todo el roster + otros). Útil para agregar un 3er o 4to miembro al toque.
v32
- 📐 Layout del header refinado:
- Desktop: el botón HOY va al final, después de Día → orden Mes / Semana / Día / 📅 HOY.
- Mobile: HOY también va integrado al final del view-toggle (📅 con número del día actual). El bloque entero se alinea a la derecha y no ocupa el ancho completo.
- 📏 Contenido no se tapa con los botones de abajo: aumenté el padding bottom de la app y le puse fondo sólido + sombrita a la barra de los 4 botones (Generar/Marcar/Personalizar/Datos). El contenido del calendario queda visible arriba de la barra sin tapársele.
v31
- 📅 Botón HOY visible en el header: nuevo botón "📅 HOY" arriba a la derecha del título (en mobile solo el ícono con el número del día actual). Al tocarlo te lleva al día de hoy en cualquier vista, abre el panel del día y hace scroll al detalle. Toast informativo ("📅 Hoy: Sábado 20" o "Ya estás en hoy" si no cambiaste de día). Antes había un botón "Hoy" escondido adentro del picker — ahora está siempre a mano.
v30
- 🛠️ 3er miembro del equipo detectado SIEMPRE (sin depender de la config del generador): agregué un fallback en
findTeamMembers que si la config no aclara el 3ro, lo encuentra por sí solo buscando en los slots cualquier persona del ROSTER sola (que no sea ALVARO ni MARTIN — esos son gestión). Así si alguien edita la config del generador y se "olvida" del 3ro, la vista Día/Mes igual lo muestra como parte del equipo y no como OTROS. Verificado con config corrupta: Martes 30 con Sallas+Ibañez+Martinez muestra los 3 juntos aunque la config solo diga {Sallas, Ibañez}.
v29
- 🎯 Vista Día simplificada con "Gestionar día" unificado: la vista Día ahora tiene la misma estructura que el panel del Mes — Equipo de Intervención + Apoyo arriba y ⚙️ Gestionar día abajo. El panel desplegable es el mismo de ambos lados: cambios de feriado, feria judicial, reemplazos y filas funcionan idénticamente desde cualquier vista. Si tocás "Editar filas" desde la vista Día, te lleva a la vista Mes con el editor abierto.
v28
- 🖥️ Vista mes en PC: nombres enteros (no abreviados) en los tiles del calendario. En mobile siguen abreviados para no ocupar tanto.
- 📦 Gestión de materiales en los tiles del calendario: cuando un slot tiene a ALVARO o MARTIN solos, ahora se ve como "📦 G. MAT. ALVARO" (o MARTIN) en vez de mostrar solo el nombre. Se ve igual en Mes y en Semana.
- ↪ + Agregar reemplazo dentro de Gestionar día: para no sobrecargar el panel del día, moví el botón "+ Agregar reemplazo" dentro de "Gestionar día" → sección "Reemplazos". En el botón de Gestionar día aparece el badge "↪N" si hay reemplazos.
- 🔃 Gestionar día se cierra al cambiar de día: si tenés el panel desplegado y tocás otro día del calendario, se cierra automáticamente.
- 📅 Semana muestra equipo de 3: la vista Semana ya mostraba el 3er miembro como pill aparte (Martinez abajo de Sallas+Ibañez). Verificado.
v27
- 🎂 Cumpleaños precargados: la app ya viene con los 19 cumpleaños del equipo cargados de fábrica. Cuando la abrís por primera vez (sin datos guardados), aparecen automáticamente. Si los modificás o sincronizás con Firebase, los cambios persisten. Si los borrás y querés volver a tenerlos, hay un botón nuevo "🎂 Cargar precargados" en el modal de Cumpleaños.
v26
- ⚙️ Panel "Gestionar día": en el detalle del día reemplacé los 3 botones grandes ("Marcar feriado", "Marcar feria judicial", "Editar filas") por un único botón "⚙️ Gestionar día" que despliega un panel con todas las acciones agrupadas por categoría (Marcadores / Edición avanzada). Cuando el día tiene algún marcador activo, se ve como badge al lado del título.
v25
- 🩹 Equipos de 3 personas EN TODAS LAS VISTAS, intervención Y apoyo: hice un helper único
findTeamMembers que detecta los 3 miembros de cualquier equipo de 3. Ahora se muestra el tercero correctamente tanto en el Equipo de Intervención como en el Equipo de Apoyo (cuando es de 3), en panel del mes y en vista Día. También los reemplazos saben quién pertenece a cada equipo (los 3, incluido el tercero del apoyo).
v24
- 🩹 Fix del 3er miembro más robusto: la detección ahora encuentra al tercero del equipo de 3 sin importar exactamente cómo esté formateado el slot en los datos. Antes había casos en que se escapaba como "OTROS".
- 📦 Sección "Gestión de materiales": en la vista Día, los slots con ALVARO o MARTIN se muestran en un bloque dorado distintivo llamado "Gestión de materiales" (en vez de "Otros"). El dropdown está restringido a ALVARO y MARTIN solamente, así no podés asignar a otro por error.
v23
- 🩹 Vista Día: el 3er miembro del equipo ya no aparece como "Otros": en la vista Día, cuando el equipo es de 3 personas (ej: Sallas+Ibañez+Martinez), el tercero (Martinez) se reconoce como parte del Equipo de Intervención y aparece adentro, ancho completo, debajo de los otros 2. Antes salía como "OTROS" abajo, separado, lo que daba confuso.
v22
- 🩹 Equipos de 3 personas en el panel del día: cuando el equipo de intervención es de 3 (como Sallas+Ibañez+Martinez), el tercero ahora aparece abajo en una pill ancho completo, no se pierde. Se ve tanto en el panel del Mes como en la vista Día. En modo edición también se puede cambiar como select.
v21
- 🔄 Buscar actualización de la app: nuevo botón en Datos y nube. Al tocar limpia el cache del service worker, fuerza al SW a aplicar la versión nueva y recarga la página. Ya no hace falta cerrar y reabrir la PWA manualmente cada vez que subo una versión nueva. Los datos locales (turnos, colores, cumpleaños, reemplazos) se mantienen intactos.
v20
- 🔁 Reemplazos sin redundancia y separados por equipo: cuando un reemplazo apunta a alguien del Equipo de Intervención aparece como "REEMPLAZOS DEL DÍA" entre Intervención y Apoyo. Cuando apunta a alguien del Apoyo, aparece como "REEMPLAZOS DEL APOYO" debajo del Apoyo. El × para borrar va al lado de cada item. Ya no se duplica abajo del card.
v19
- 🔁 Leyenda de reemplazo entre Intervención y Apoyo: en el panel del Mes y en la vista Día, los reemplazos del día se ven como un bloque violeta "REEMPLAZOS DEL DÍA (N)" arriba del Equipo de Apoyo, así está visible siempre la leyenda "X reemplaza a Y" sin tener que mirar abajo.
- 🤝 Equipo de Apoyo también se puede reemplazar: al elegir "a quién reemplaza" en el form, ahora aparecen tanto los del Equipo de Intervención como los del Equipo de Apoyo.
- 📤 Reemplazos en la imagen exportada: el mes compartido por WhatsApp ahora trae al final una lista con todos los reemplazos del mes ("Día 5 — Gomez reemplaza a Capdevila").
- 📊 Estadísticas: nuevo botón en Generación que abre un modal con:
- "Este mes" → días por equipo y por persona (barras de colores)
- "Histórico total" → días acumulados por equipo desde que se empezó a generar, ordenados, con indicador de balance.
v18
- 🎨 Colores específicos por mes (override): en el modal de Colores ahora hay un toggle "🌐 Todos los meses / 📅 Solo [Mes Año]". Si cambiás un color en modo "Solo este mes", queda aplicado únicamente para ese mes — el resto sigue con el color general. Útil cuando cambia la composición de un equipo de un mes a otro. Los personajes con override muestran un 📅 al lado y la fila queda con fondo lila claro.
- Botón "🗑️ Borrar todos los colores especiales de [Mes Año]" en el modal para limpiar overrides de golpe.
v17
- 🔁 Reemplazos visibles siempre (no solo en modo edición). Bloque violeta con la lista de reemplazos + botón "+ Agregar reemplazo" arriba del "Editar filas del día". Se ve igual en el panel del Mes y en la vista Día.
- 🔥 Firebase precargado: los 4 campos (API Key, Auth Domain, Database URL, Project ID) vienen llenos por defecto. En una PC nueva solo tenés que poner email + password y conectar.
v16
- 🎲 ⚖️ 🎨 ☁️ 4 botones de categoría en lugar del "…Más": ahora abajo a la pantalla hay 4 botones chicos (Generar, Marcar, Personalizar, Datos). Cada uno abre solo su mini-lista corta — no más lista enorme.
v15
- 🎂 Cumpleaños: nuevo modal en el menú para definir la fecha de cumpleaños de cada persona. El día que alguien cumple años, su equipo NO recibe turno del generador (se busca otro). Visual: ícono 🎂 en la esquina del día en el calendario.
- 🔁 Reemplazos: en el modo edición del día hay un botón "+ Reemplazo" violeta. Te pide a quién reemplaza (alguien del día) y quién lo reemplaza (cualquier persona del roster). El reemplazo aparece debajo de las filas del día en color violeta distintivo ("ALVARO ↪ reemplaza a Cabeza"). En el calendario, los días con reemplazos muestran un ↪ violeta en la esquina.
- 🗂️ Menú organizado por categorías: ahora "…Más" tiene 4 secciones (Generación, Marcadores, Personalización, Datos y nube). Antes era una lista plana.
- ☁️ Sincronización mejorada: nuevos botones "⬇️ Forzar descarga de la nube" y "⬆️ Forzar subida a la nube" en el modal de sync. Solución para el caso "dice sincronizado pero no aparece nada" (forzás la descarga manualmente).
- 🔑 Contraseña del generador quitada: ya no pide contraseña para generar el mes. Si querés volver a tener una traba, decímelo y la pongo de otra forma.
v14
- ⚖️ Feria judicial (color rojo, distinto al amarillo del feriado):
- Botón "Marcar como feria judicial" en el panel de cada día (igual que feriado)
- Botón "Marcar mes completo como feria judicial" en el menú (para enero)
- Botón "Marcar rango de días como feria judicial" en el menú (para julio 13-26)
- El generador la respeta igual que los feriados (no asigna equipos esos días)
- Visual distinto: rojo en el calendario, badge "FJ" en la esquina, badge rojo en el panel
- 📤 Compartir mes (imagen):
- Nuevo botón en el menú que exporta el calendario del mes actual como imagen PNG
- En mobile: abre el menú de compartir nativo (incluye WhatsApp) gracias al Web Share API
- En PC: descarga la imagen para que la compartas manualmente
- Incluye título "Turnos de Intervenciones — [Mes] [Año]" y footer con fecha de generación
v13
- 🔄 Rotación automática de cupos altos entre meses (toggle en el modal del generador). Cuando está activa:
- Mantiene el template de cupos que vos definiste (ej: 3 equipos con 5 y 4 con 4)
- Cada mes, los equipos con menos días totales en el historial reciben los cupos más altos
- Los equipos van rotando solos entre cupos altos y bajos → balance casi perfecto en el largo plazo
- El contador del modal muestra qué equipos van a tener cupo alto este mes (preview)
- Test verificado: en 3 meses, todos los equipos quedan entre 12 y 13 días (diferencia máx-mín = 1).
v12
- Continuidad entre meses: si el mes anterior termina en medio de un slot (Lun, Mié o Sáb), el día 1 del mes nuevo arranca con el mismo equipo para completar ese slot. La rotación de fines de semana y el descanso post-viernes también heredan del mes anterior.
- No se puede generar un mes si el anterior no tiene datos: alert claro que dice qué mes hay que generar primero (ej: "Primero generá Octubre 2026").
- 🔑 Contraseña para generar turnos: primera vez se define (con confirmación), después se pide cada vez que se genera. Botón en el menú para borrarla/cambiarla.
- Equipo de apoyo editable: en el modo edición del panel del día, los pills del equipo de apoyo también son selects (igual que los de intervención).
v11
- Diagnóstico de sincronización mejorado: cuadro de status arriba del modal de Sync con feedback en vivo. Botón "🔍 Probar si Firebase cargó". Mensajes de error con sugerencia de solución.
- Service Worker network-first para HTML/JS/CSS: las nuevas versiones llegan rápido. Firebase nunca se cachea.
v10
- ☁️ Sincronización en la nube (Firebase): los datos se sincronizan automáticamente entre PC y celular. Setup de una sola vez con Firebase (gratis):
- Crear proyecto en console.firebase.google.com
- Habilitar Realtime Database + Authentication (Email/Password)
- Copiar config en el modal "☁️ Sincronización en la nube" del menú
- Listo — todos los cambios se sincronizan en segundos
- Indicador de estado en el menú: ⚪ Sin conectar / 🟡 Conectando / 🟢 Sincronizado / 🔵 Sincronizando / 🔴 Error
v9
- Generador con reglas HARD (no son sugerencias, son constraints estrictos):
- Mismo equipo NO puede hacer el mismo slot 2 semanas seguidas (fin del bug de "3 viernes con Campi+Montilla")
- Si un equipo hace viernes, la semana siguiente solo puede hacer fin de semana (no Lun-Mar/Mié-Jue/Vie). Así descansan entre activo y apoyo.
- Smart 2-day splitting: si un slot de 2 días no tiene equipo con cupo, se parte en 2 equipos distintos (1 día cada uno). Antes los días quedaban vacíos.
- Contador de cupos en el modal del generador: suma de máx/mes vs días del mes. Se actualiza en vivo:
- 🟢 Verde cuando = días del mes
- 🟡 Amarillo cuando sobran
- 🔴 Rojo cuando faltan
v8
- Generador mucho más equitativo:
- Ya no repite el mismo equipo en el mismo slot 2 semanas seguidas (fin de bug de "3 viernes seguidos con Campi+Montilla")
- Balance cross-month: los equipos que hicieron más días el mes pasado tienen menos prioridad este mes. Se va auto-balanceando con el tiempo.
- Los feriados nacionales se respetan automáticamente
- 🇦🇷 Precarga de feriados nacionales de Argentina: nuevo botón en el menú. Carga TODOS los feriados del año actual (Año Nuevo, Carnaval, Memoria, Malvinas, Viernes Santo, Trabajador, Revolución de Mayo, Güemes, Belgrano, Independencia, San Martín, Diversidad, Soberanía, Inmaculada, Navidad). El cálculo de Pascua/Carnaval/Viernes Santo es dinámico por año.
- Tiles del mes NO editables: en mobile eran muy chicos y se cambiaba alguien sin querer al elegir el día. Ahora el calendario es solo lectura; para editar se toca el día → panel desplegable → ahí sí los pills son editables (igual que en vista Semana y Día).
v7
- Colores configurables por persona (menú "🎨 Colores de personas"): tocás el cuadradito de color y elegís el que quieras. Útil cuando alguien cambia de equipo de intervención.
- Equipos de 3 personas soportados en el generador (ej. Sallas + Ibañez + Martinez). Botón "+" en la config para agregar 3ra persona a cualquier equipo.
- Colores default actualizados a la distribución real de equipos:
- Equipo durazno: Sallas + Ibañez + Martinez
- Equipo amarillo: Hidalgo + Laporta
- Equipo verde: Cabeza + Celina
- Equipo azul: Frias + Echague
- Equipo violeta: Capdevila + Gomez
- Equipo gris: Campi + Montilla
- Equipo naranja oscuro: Milisenda + Diaz
- Fix del "—" sobrante: cuando una fila tiene un solo nombre, el select vacío del costado ya no aparece. El nombre ocupa todo el ancho y aparece un "+" para agregar compañero si querés.
v6
- Generador con cap ESTRICTO: si ponés "máx/mes: 4", se respeta a rajatabla. Los días que sobran quedan vacíos y aparece un toast indicando cuántos no se asignaron (para que subas el cupo)
- TODOS los tiles editables: en cualquier vista (mes / semana / día) tocás un pill y se abre el dropdown con los 15 del roster + "Otros". Reemplazos rápidos sin abrir el panel.
- Pills de "Otros" ancho completo: cuando una fila de Otros tiene un solo nombre (oficios MARTIN / ALVARO / abogados), el pill ocupa todo el ancho del tile en lugar de dejar un hueco al lado.
v5
- "Equipo a cargo" → renombrado a "Equipo de intervención" en todas las vistas
- Tiles editables: las píldoras del equipo de intervención son tap-ables → dropdown con los 15 del roster para hacer reemplazos rápidos sin abrir el editor
- Generador mejorado:
- Pantalla previa para definir parejas de equipos + máximo de días por mes de cada uno
- Lógica de rotación de fin de semana (cada finde le toca a un equipo distinto en secuencia, ciclando todos)
- Días de semana balanceados al equipo menos usado
- Respeta tope máximo por equipo y feriados
- Equipos por defecto reducidos a 7 (lo típico) y configurables desde la app
v4
- Generador automático de mes: respeta la lógica L+Ma / Mi+J / V / S+D con equipos al azar sin repetir dentro de la misma semana
- Feriados: botón en el panel del día para marcar/quitar feriado. Día pintado de amarillo con marca "F"
- Panel de día limpio: sólo muestra info (cargo + apoyo) por defecto. El editor avanzado queda colapsado tras "✎ Editar filas del día"
- Roster limpio: removidos ALVARO GRIGNOLA y MARTIN VILLANUEVA (duplicados); FERIADO ya no está en el dropdown porque ahora es un flag separado
- Migración automática: entradas viejas de "FERIADO" en los datos se convierten al nuevo sistema de flag
v3
- Tres vistas (Mes / Semana / Día) estilo Google Calendar
- "Equipo a cargo + Equipo de apoyo" en panel de edición (no solo en vista Día)
- Filtros: por persona y por equipo del mes (se combinan)
- Deshacer cambios por día (hasta 10 niveles de undo)
- Roster reorganizado: "Abogados" se mueve a "Otros" (gente que no hace turnos regulares)
- Número de versión visible en el menú
- Desktop responsive estilo Google Calendar
v2
- Vistas Semana y Día
- Lógica de Equipo de Apoyo (anclado al día siguiente)
- Layout desktop ampliado
v1
- Versión inicial PWA con vista mensual, dropdowns y persistencia local