Jitsi: modal flotante dragable con aviso automático al chat
Resumen
Rediseño completo del modal de reunión Jitsi en el workspace interno de CreaRack (PR #59, commit 25e2515). El modal deja de ser una ventana full-screen con backdrop opaco y se convierte en una ventana flotante que coexiste con el resto del workspace, soporta arrastre, redimensionado y minimización.
Adicionalmente, al abrir una reunión se envía un aviso automático al chat del equipo para que los otros miembros (Dani, Txell) sean notificados sin necesidad de invitar manualmente.
Comportamiento del modal flotante
Dimensiones y posición inicial
| Parámetro | Valor |
|---|---|
| Tamaño por defecto | 640 × 480 px |
| Tamaño mínimo | 360 × 280 px |
| Altura minimizado | 56 px (solo header) |
| Posición inicial | Centrada horizontalmente, 1/3 desde arriba |
z-index | 1000 (flota sobre workspace, no bloquea nada que quede al lado) |
Funcionalidades de interacción
- Drag del header:
PointerEventsconsetPointerCapture/releasePointerCapture. Soporta tanto mouse como touch. La posición se restringe medianteclampPospara que la ventana nunca salga del viewport. No hay drag si está minimizado. - Resize desde esquina inferior derecha: handle visual estilo diagonal striped. Mismo mecanismo de pointer capture. Respeta
MIN_WIDTH/MIN_HEIGHTy el margen de 16 px al borde de la ventana. - Minimizar / Restaurar: oculta el cuerpo del modal (
display: none) pero no desmonta el iframe, manteniendo la sesión Jitsi activa. La transición de altura (0.18s ease) solo se aplica al colapsar, evitando lag durante el drag. - Botón “Aparte”: abre la sala Jitsi en una pestaña nueva.
- Cerrar (Esc o botón): desmonta el componente. La prop
onCloseviene deTeamChat.
Cambios de UX respecto al modal anterior
| Aspecto | Antes | Ahora |
|---|---|---|
| Tipo | Full-screen con backdrop rgba(0,0,0,0.7) + backdropFilter: blur(4px) | Ventana flotante, sin oscurecer |
document.body.style.overflow | Se bloqueaba ('hidden') | Ya no se toca |
| Interacción con el resto del workspace | Imposible (modal bloquea todo) | Posible — ventana es movible y no opaca |
| Minimización | No existía | Header visible de 56 px, iframe vivo |
| Resize | No existía | Handle esquina inferior derecha |
Aviso automático al chat del equipo
Flujo
- Al montar
JitsiMeetingModal, siauthorestá definido y no se está enlocalhost, se ejecuta unPOST /api/chat/messages. - El body del mensaje:
📞 {author} ha iniciado una reunión. Únete: {origin}/?meeting=open o directamente {MEETING_URL}. announcedRef(unuseRef<boolean>) evita reenviar el aviso si el modal se cierra y se reabre en la misma sesión de página.- Errores de red se silencian (
.catch(() => {})); la reunión puede continuar aunque falle el anuncio.
Condición de guarda: localhost
if (typeof window === 'undefined' || window.location.hostname === 'localhost') return;
En desarrollo local no se envía el aviso para evitar ruido en el chat real del equipo.
Integración con el polling del chat
Los receptores (Dani, Txell) ven el mensaje en el polling de 15 s del chat de equipo (implementado en TeamChat.tsx). Si tienen el tab oculto, el sistema de notificaciones existente (beep + favicon rojo, ítem 1 s77) actúa sobre este mensaje igual que sobre cualquier otro.
Prop author
TeamChat pasa me (la variable que identifica al usuario actual) como author:
{meetingOpen && <JitsiMeetingModal author={me} onClose={() => setMeetingOpen(false)} />}
Detalles de implementación relevantes
useMemo en winStyle
Los estilos inline del contenedor (position: fixed, left, top, width, height, etc.) se calculan con useMemo dependiendo de pos.x, pos.y, size.w, size.h y collapsed. Esto evita recalcular el objeto en cada render intermedio y es especialmente relevante durante el drag (muchos eventos de pointermove por segundo).
Transición condicional
transition: collapsed ? 'height 0.18s ease' : 'none',
La transición CSS solo está activa cuando se colapsa/expande. Durante el drag no hay transición para que el movimiento sea inmediato y no produzca lag visual.
Sala fija
La sala Jitsi es siempre la misma:
https://meet.jit.si/CrearackSL-Workspace-EduDaniTxell-Sala#config.prejoinPageEnabled=true
Quien entra primero la crea; los demás se unen sin signup. El flag prejoinPageEnabled=true mantiene la pantalla de vista previa antes de entrar.
Archivos afectados
| Archivo | Tipo de cambio |
|---|---|
src/components/widgets/JitsiMeetingModal.tsx | Reescritura completa (~174 LOC netas añadidas) |
src/components/widgets/TeamChat.tsx | +1 línea: añade prop author={me} al mount del modal |
Véase también
- [[workspace—que-es-workspace]]