/* Standup diario (27-oct-2026). Servidor: backend/standup.py. Mi standup: GET /api/standup/hoy → instrucciones del bot + preguntas por pendiente; POST /api/standup/respuesta. Si la persona lo deja marcado, mueve sus pendientes con PATCH /api/tarea?id= (queda a su nombre en el historial). Equipo (Leo, Adriana, el bot): GET /api/standup?fecha= . La dirección guarda la vista: ?vista=equipo&fecha=AAAA-MM-DD. */ (function () { const $ = id => document.getElementById(id); const esc = s => { const d = document.createElement('div'); d.textContent = s == null ? '' : String(s); return d.innerHTML; }; const MES = ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dic']; const DIA = ['domingo', 'lunes', 'martes', 'miércoles', 'jueves', 'viernes', 'sábado']; const largo = f => { const d = new Date(f + 'T12:00:00'); return isNaN(d) ? f : DIA[d.getDay()] + ' ' + d.getDate() + ' ' + MES[d.getMonth()]; }; const hora = iso => (iso || '').slice(11, 16); const ESTADO_T = { 'por-hacer': 'Por hacer', 'en-curso': 'En curso', bloqueado: 'Bloqueado', hecho: 'Hecho' }; const OPC = [['hecho', 'Hecho'], ['sigo', 'Sigo con él'], ['bloqueado', 'Bloqueado'], ['no-empece', 'No empecé']]; const A_TABLERO = { hecho: 'hecho', sigo: 'en-curso', bloqueado: 'bloqueado' }; const params = new URLSearchParams(location.search); let vista = params.get('vista') === 'equipo' ? 'equipo' : 'mio', puedeEquipo = false; async function api(url, op) { const r = await fetch(url, Object.assign({ credentials: 'same-origin', cache: 'no-store' }, op || {})); const j = await r.json().catch(() => ({ ok: false, error: 'HTTP ' + r.status })); if (!r.ok || !j.ok) { const e = new Error(j.error || ('HTTP ' + r.status)); e.status = r.status; throw e; } return j; } const json = (method, body) => ({ method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }); function aviso(t, bien) { const a = $('aviso'); a.className = 'msg ' + (bien ? 'ok' : 'err'); a.innerHTML = t; a.scrollIntoView({ block: 'nearest' }); } function botones() { $('vistas').innerHTML = '' + (puedeEquipo ? '' : ''); $('vistas').querySelectorAll('button').forEach(b => b.addEventListener('click', () => { vista = b.dataset.v; const p = new URLSearchParams(location.search); p.set('vista', vista); history.replaceState(null, '', '?' + p); botones(); (vista === 'equipo' ? equipo : mio)(); })); } async function mio() { const C = $('cont'); C.innerHTML = '
Cargando…
'; let j; try { j = await api('/api/standup/hoy'); } catch (e) { C.innerHTML = '' + esc(s.nota_bot) + '
' : '') + 'Las preparó ' + esc(s.preparado_por || 'el bot') + ' el ' + esc(largo((s.preparado_en || '').slice(0, 10))) + ' a las ' + esc(hora(s.preparado_en)) + ', con el tablero de ese momento.
Hoy el bot no dejó instrucciones; contesta sobre tus pendientes abiertos.
'; } const previas = {}; ((s.respuesta || {}).por_tarea || []).forEach(p => { previas[p.tarea_id] = p; }); const preg = s.preguntas || []; h += 'No tienes pendientes abiertos a tu nombre. Si estás trabajando en algo que no está en el tablero, cuéntalo abajo.
'; preg.forEach((p, i) => { const prev = previas[p.tarea_id] || {}; h += 'Cargando…
'; fecha = fecha || params.get('fecha') || ''; let j; try { j = await api('/api/standup' + (fecha ? '?fecha=' + encodeURIComponent(fecha) : '')); } catch (e) { C.innerHTML = 'El bot no preparó standup ese día.
'; else { const bloqueos = j.standups.filter(s => s.respuesta && (s.respuesta.bloqueos || (s.respuesta.por_tarea || []).some(p => p.estado === 'bloqueado'))); if (bloqueos.length) h += '| Persona | Contestó | Terminó | Le falta | Pendientes |
|---|---|---|---|---|
| ' + esc(s.nombre) + ' | ' + (r ? esc(hora(r.enviada_en)) : '—') + ' | ' + esc(r ? r.hecho : '') + ' | ' + esc(r ? r.falta : '') + ' | '
+ (r ? (r.por_tarea || []).map(p => esc(p.tarea_id) + ': ' + esc(p.estado) + (p.nota ? ' — ' + esc(p.nota) : '')).join(' ') : esc((s.preguntas || []).length + ' preguntas')) + ' |