From 5dae4a20d340cd251205220015d81842e2dca3cf Mon Sep 17 00:00:00 2001 From: josedario87 <71241187+josedario87@users.noreply.github.com> Date: Mon, 9 Jun 2025 19:40:29 -0600 Subject: [PATCH 1/4] feat(ui): add realtime feed view --- README.md | 2 + ui/README.md | 4 ++ .../components/realtime/RealtimeEventCard.vue | 60 +++++++++++++++++++ ui/src/components/ui/NavBar.vue | 2 + ui/src/router/index.js | 3 + ui/src/stores/useRealtime.js | 16 +++-- ui/src/views/RealtimeFeedView.vue | 53 ++++++++++++++++ 7 files changed, 134 insertions(+), 6 deletions(-) create mode 100644 ui/src/components/realtime/RealtimeEventCard.vue create mode 100644 ui/src/views/RealtimeFeedView.vue diff --git a/README.md b/README.md index 9ed4356..07d1427 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,8 @@ source.onmessage = (e) => { }; ``` +La interfaz incluye una vista **Feed** accesible desde la barra lateral. Allí se muestran en tiempo real las tarjetas de cada módulo conforme llegan estos eventos. + #### Card Animation The data cards implemented in `ui/src/components/ui/NucleoDataCard.vue` now feature a subtle growing animation when hovered over. This animation is implemented purely with CSS using keyframes and transitions defined within the component's ` diff --git a/ui/src/components/ui/NavBar.vue b/ui/src/components/ui/NavBar.vue index 34f862b..06db6a1 100644 --- a/ui/src/components/ui/NavBar.vue +++ b/ui/src/components/ui/NavBar.vue @@ -12,6 +12,7 @@ const links = [ { to: '/tareas', label: 'Tareas', icon: '📋' }, { to: '/planillas', label: 'Planillas', icon: '📂' }, { to: '/asistencias', label: 'Asistencias', icon: '⏰' }, + { to: '/feed', label: 'Feed', icon: '📰' }, { to: '/config', label: 'Config', icon: '⚙️' }, ] @@ -24,6 +25,7 @@ const accentColorForPath = (path) => { if (path.startsWith('/tareas')) return ui.accentColorTareas if (path.startsWith('/planillas')) return ui.accentColorPlanillas if (path.startsWith('/asistencias')) return ui.accentColorAsistencias + if (path.startsWith('/feed')) return ui.primaryColor if (path.startsWith('/config')) return ui.accentColorConfiguracion return ui.accentColorChat } diff --git a/ui/src/router/index.js b/ui/src/router/index.js index ea9a22c..d4a9628 100644 --- a/ui/src/router/index.js +++ b/ui/src/router/index.js @@ -25,6 +25,9 @@ const routes = [ { path: '/asistencias/nuevo', name: 'asistencias-new', component: () => import('@/views/asistencias/AsistenciaForm.vue') }, { path: '/asistencias/:id', name: 'asistencias-edit', component: () => import('@/views/asistencias/AsistenciaForm.vue'), props: true }, + // ────── Feed en tiempo real ────── + { path: '/feed', name: 'feed', component: () => import('@/views/RealtimeFeedView.vue') }, + // 404 { path: '/:pathMatch(.*)*', name: 'not-found', component: () => import('@/views/NotFound.vue') } ] diff --git a/ui/src/stores/useRealtime.js b/ui/src/stores/useRealtime.js index a567cdf..a46edd1 100644 --- a/ui/src/stores/useRealtime.js +++ b/ui/src/stores/useRealtime.js @@ -7,6 +7,7 @@ import { useAsistenciasStore } from './useAsistencias' export const useRealtimeStore = defineStore('realtime', { state: () => ({ _sse: null, + events: [], }), actions: { init() { @@ -19,13 +20,16 @@ export const useRealtimeStore = defineStore('realtime', { console.log('🟢 Conexión SSE establecida correctamente'); }; - this._sse.onmessage = (e) => { - console.log('📩 SSE message raw:', e.data); + this._sse.onmessage = (e) => { + console.log('📩 SSE message raw:', e.data); - try { - const payload = JSON.parse(e.data); - console.log('📦 Payload parseado:', payload); - console.log('🧪 Tabla recibida:', payload.table); + try { + const payload = JSON.parse(e.data); + console.log('📦 Payload parseado:', payload); + console.log('🧪 Tabla recibida:', payload.table); + + // store event for feed + this.events.unshift({ ...payload, receivedAt: new Date().toISOString() }); switch (payload.table) { case 'Planilla': diff --git a/ui/src/views/RealtimeFeedView.vue b/ui/src/views/RealtimeFeedView.vue new file mode 100644 index 0000000..16e4fd0 --- /dev/null +++ b/ui/src/views/RealtimeFeedView.vue @@ -0,0 +1,53 @@ + + + + + From 9030469fe7ff11c81ccb664200f5e83802a8520d Mon Sep 17 00:00:00 2001 From: josedario87 <71241187+josedario87@users.noreply.github.com> Date: Mon, 9 Jun 2025 19:49:24 -0600 Subject: [PATCH 2/4] Improve realtime feed --- README.md | 2 +- ui/README.md | 2 +- .../components/realtime/RealtimeEventCard.vue | 46 ++++++++++++++++--- ui/src/views/RealtimeFeedView.vue | 19 ++++++-- 4 files changed, 57 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 07d1427..54d6be2 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ source.onmessage = (e) => { }; ``` -La interfaz incluye una vista **Feed** accesible desde la barra lateral. Allí se muestran en tiempo real las tarjetas de cada módulo conforme llegan estos eventos. +La interfaz incluye una vista **Feed** accesible desde la barra lateral. Allí se muestran en tiempo real las tarjetas de cada módulo conforme llegan estos eventos. Las actualizaciones exhiben la tarjeta anterior y la nueva con una flecha que indica el cambio. #### Card Animation The data cards implemented in `ui/src/components/ui/NucleoDataCard.vue` now feature a subtle growing animation when hovered over. This animation is implemented purely with CSS using keyframes and transitions defined within the component's ` diff --git a/ui/src/views/RealtimeFeedView.vue b/ui/src/views/RealtimeFeedView.vue index 16e4fd0..82c66a0 100644 --- a/ui/src/views/RealtimeFeedView.vue +++ b/ui/src/views/RealtimeFeedView.vue @@ -16,16 +16,16 @@ onMounted(() => {

Feed en Tiempo Real

-
+
No hay eventos aún.
-
+ @@ -50,4 +50,17 @@ onMounted(() => { font-size: 2.2em; font-weight: 600; } + +.feed-enter-active, +.feed-leave-active { + transition: all 0.3s ease-out; +} +.feed-enter-from { + opacity: 0; + transform: translateY(-10px); +} +.feed-enter-to { + opacity: 1; + transform: translateY(0); +} From a311c811d70299a427a079b6acf1f36ec45f0145 Mon Sep 17 00:00:00 2001 From: josedario87 <71241187+josedario87@users.noreply.github.com> Date: Mon, 9 Jun 2025 20:10:52 -0600 Subject: [PATCH 3/4] style(feed): highlight insert/delete events --- .../components/realtime/RealtimeEventCard.vue | 10 +++++++++- ui/src/views/RealtimeFeedView.vue | 18 ++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/ui/src/components/realtime/RealtimeEventCard.vue b/ui/src/components/realtime/RealtimeEventCard.vue index d8ac00f..39d171e 100644 --- a/ui/src/components/realtime/RealtimeEventCard.vue +++ b/ui/src/components/realtime/RealtimeEventCard.vue @@ -1,5 +1,5 @@