From 94ff4ea726b66eb06ea711646951c2967f7e6b98 Mon Sep 17 00:00:00 2001 From: josedario87 <71241187+josedario87@users.noreply.github.com> Date: Wed, 11 Jun 2025 03:57:57 -0600 Subject: [PATCH 1/6] feat(ui): animate navbar tab on new events --- ui/src/components/ui/NavBar.vue | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/ui/src/components/ui/NavBar.vue b/ui/src/components/ui/NavBar.vue index 464b314..1c501fb 100644 --- a/ui/src/components/ui/NavBar.vue +++ b/ui/src/components/ui/NavBar.vue @@ -54,15 +54,26 @@ const hasBadge = (path, op) => { return table && realtime.badges[table]?.[op] } +const hasAnyBadge = (path) => { + const table = tableForPath(path) + if (!table) return false + const b = realtime.badges[table] + return b.INSERT || b.UPDATE || b.DELETE +} + // clases dinΓ‘micas p/ mostrar / ocultar barra const sidebarClasses = computed(() => ui.sidebarOpen ? 'translate-x-0' : '-translate-x-full') -const handleLinkClick = () => { +const handleLinkClick = (path) => { // Close sidebar if desktopNavbarPersistent is false or if it's mobile view (width < 768px) // Assuming 768px is the 'md' breakpoint. if (!ui.desktopNavbarPersistent || window.innerWidth < 768) { ui.closeSidebar() } + // Clear badges for this module when the link is clicked + const table = tableForPath(path) + if (table) realtime.clearBadgesForTable(table) + // Otherwise, (desktopNavbarPersistent is true AND width >= 768px), do nothing to keep sidebar open. } @@ -89,9 +100,9 @@ const handleLinkClick = () => { {{ l.label }} @@ -117,7 +128,7 @@ ul { list-style: none; padding-left: 0; } border: 1px solid var(--accent-color); overflow: hidden; border-radius: 0.375rem; - transition: background-color 0.3s ease, color 0.3s ease; + transition: background-color 0.3s ease, color 0.3s ease, transform 0.3s ease; z-index: 0; } @@ -159,6 +170,10 @@ ul { list-style: none; padding-left: 0; } box-shadow: 0 1px 3px 0 rgba(0,0,0,0.1), 0 1px 2px 0 rgba(0,0,0,0.06); } +.nav-link.notified { + transform: translateX(4px); +} + /* Scrollbar styling using primary color */ .custom-scroll::-webkit-scrollbar { width: 8px; } .custom-scroll::-webkit-scrollbar-track { background: transparent; } From 43dc15e13504d753b652a15ebd6f9d4325537472 Mon Sep 17 00:00:00 2001 From: josedario87 Date: Wed, 11 Jun 2025 04:08:43 -0600 Subject: [PATCH 2/6] navbar animada con eventos sse --- ui/src/components/ui/NavBar.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/components/ui/NavBar.vue b/ui/src/components/ui/NavBar.vue index 1c501fb..2582ec7 100644 --- a/ui/src/components/ui/NavBar.vue +++ b/ui/src/components/ui/NavBar.vue @@ -171,7 +171,7 @@ ul { list-style: none; padding-left: 0; } } .nav-link.notified { - transform: translateX(4px); + transform: translateX(10px); } /* Scrollbar styling using primary color */ From 74b9c0ad7ec02f87073021cae2b703d0a00a036d Mon Sep 17 00:00:00 2001 From: josedario87 <71241187+josedario87@users.noreply.github.com> Date: Wed, 11 Jun 2025 04:12:02 -0600 Subject: [PATCH 3/6] feat(ui): add snackbar for realtime notifications --- ui/src/App.vue | 2 + ui/src/components/ui/SnackbarContainer.vue | 67 ++++++++++++++++++++++ ui/src/stores/useRealtime.js | 6 ++ ui/src/stores/useSnackbar.js | 22 +++++++ 4 files changed, 97 insertions(+) create mode 100644 ui/src/components/ui/SnackbarContainer.vue create mode 100644 ui/src/stores/useSnackbar.js diff --git a/ui/src/App.vue b/ui/src/App.vue index dd4e2d8..56c4abf 100644 --- a/ui/src/App.vue +++ b/ui/src/App.vue @@ -2,6 +2,7 @@ import { watchEffect, computed } from 'vue' // Added computed import TopBar from '@/components/ui/TopBar.vue' import NavBar from '@/components/ui/NavBar.vue' +import SnackbarContainer from '@/components/ui/SnackbarContainer.vue' import { useUi } from '@/stores/useUi' const ui = useUi() @@ -80,6 +81,7 @@ const transitionDurationStyle = computed(() => { + diff --git a/ui/src/components/ui/SnackbarContainer.vue b/ui/src/components/ui/SnackbarContainer.vue new file mode 100644 index 0000000..8d6e676 --- /dev/null +++ b/ui/src/components/ui/SnackbarContainer.vue @@ -0,0 +1,67 @@ + + + + + diff --git a/ui/src/stores/useRealtime.js b/ui/src/stores/useRealtime.js index cf34662..09c444e 100644 --- a/ui/src/stores/useRealtime.js +++ b/ui/src/stores/useRealtime.js @@ -3,6 +3,7 @@ import { usePlanillasStore } from './usePlanillas' import { useEmpleadosStore } from './useEmpleados' import { useTareasStore } from './useTareas' import { useAsistenciasStore } from './useAsistencias' +import { useSnackbarStore } from './useSnackbar' export const useRealtimeStore = defineStore('realtime', { state: () => ({ @@ -55,6 +56,11 @@ export const useRealtimeStore = defineStore('realtime', { addEvent(); } + const snackbar = useSnackbarStore(); + const idPart = payload.new?.id || payload.old?.id; + const message = `${payload.operation} ${payload.table}${idPart ? ' #' + idPart : ''}`; + snackbar.push({ text: message }); + // mark badge for module and operation if (this.badges[payload.table]) { this.badges[payload.table][payload.operation] = true; diff --git a/ui/src/stores/useSnackbar.js b/ui/src/stores/useSnackbar.js new file mode 100644 index 0000000..7b01c32 --- /dev/null +++ b/ui/src/stores/useSnackbar.js @@ -0,0 +1,22 @@ +import { defineStore } from 'pinia' + +export const useSnackbarStore = defineStore('snackbar', { + state: () => ({ + snacks: [] + }), + actions: { + push({ text, type = 'info', duration = 4000 }) { + const id = crypto.randomUUID ? crypto.randomUUID() : Date.now().toString(36) + Math.random().toString(36).slice(2) + const snack = { id, text, type } + this.snacks.push(snack) + if (duration > 0) { + setTimeout(() => this.remove(id), duration) + } + return id + }, + remove(id) { + const index = this.snacks.findIndex(s => s.id === id) + if (index !== -1) this.snacks.splice(index, 1) + } + } +}) From aa480e8faabb3fa88787015fcb8acce0f508a12d Mon Sep 17 00:00:00 2001 From: josedario87 <71241187+josedario87@users.noreply.github.com> Date: Wed, 11 Jun 2025 04:25:40 -0600 Subject: [PATCH 4/6] Improve snackbar style and duration --- ui/src/components/ui/SnackbarContainer.vue | 53 ++++++++-------------- ui/src/stores/useRealtime.js | 4 +- ui/src/stores/useSnackbar.js | 8 +++- 3 files changed, 29 insertions(+), 36 deletions(-) diff --git a/ui/src/components/ui/SnackbarContainer.vue b/ui/src/components/ui/SnackbarContainer.vue index 8d6e676..0ba7fac 100644 --- a/ui/src/components/ui/SnackbarContainer.vue +++ b/ui/src/components/ui/SnackbarContainer.vue @@ -1,12 +1,13 @@