From 2a8cbf42993eea076b46cb7b6001815f90417c03 Mon Sep 17 00:00:00 2001 From: gabdevele Date: Thu, 18 Jun 2026 13:51:54 +0200 Subject: [PATCH] feat: add unread notifications feature and enhance notification display --- app/components/Header.vue | 24 ++- app/components/dashboard/AdminDashboard.vue | 128 +++++---------- app/composables/useAuth.ts | 26 +++ app/pages/admin/reports.vue | 117 ++++---------- app/pages/notifications.vue | 166 ++++++++++---------- 5 files changed, 196 insertions(+), 265 deletions(-) diff --git a/app/components/Header.vue b/app/components/Header.vue index 3b07a04..7440050 100644 --- a/app/components/Header.vue +++ b/app/components/Header.vue @@ -26,7 +26,7 @@ onUnmounted(() => { } }) -const { isAuthenticated, user, logout } = useAuth() +const { isAuthenticated, user, logout, hasUnreadNotifications } = useAuth() const panelLabel = computed(() => isAdmin(user.value?.role) ? 'Pannello' : 'Dashboard') const navLinks = [ @@ -70,8 +70,9 @@ const navLinks = [ - @@ -215,7 +216,7 @@ const navLinks = [ visibility: visible; } - .navbar-collapsable { +.navbar-collapsable { position: fixed !important; top: 0; left: 0; @@ -294,4 +295,19 @@ const navLinks = [ height: 48px; margin-inline: 16px; } - \ No newline at end of file + +.profile-icon-wrap { + position: relative; +} + +.notification-dot { + position: absolute; + top: -2px; + right: -2px; + width: 10px; + height: 10px; + border-radius: 50%; + background: #d9364f; + border: 2px solid #ffffff; +} + diff --git a/app/components/dashboard/AdminDashboard.vue b/app/components/dashboard/AdminDashboard.vue index f7bd20c..6f15461 100644 --- a/app/components/dashboard/AdminDashboard.vue +++ b/app/components/dashboard/AdminDashboard.vue @@ -4,36 +4,11 @@ const { getOverviewStats } = useAdmin() const { data: statsRes, pending } = useAsyncData('admin-stats', () => getOverviewStats()) const adminActions = [ - { - to: '/admin/reports', - icon: 'it-files', - label: 'Report', - tone: 'primary' - }, - { - to: '/admin/catalog', - icon: 'it-list', - label: 'Categorie e Team', - tone: 'primary' - }, - { - to: '/admin/areas', - icon: 'it-map-marker', - label: 'Aree', - tone: 'primary' - }, - { - to: '/admin/users', - icon: 'it-user', - label: 'Gestione Utenti', - tone: 'primary' - }, - { - to: '/admin/moderation', - icon: 'it-warning', - label: 'Moderazione Abusi', - tone: 'danger' - } + { to: '/admin/reports', icon: 'it-files', label: 'Report', tone: 'primary' }, + { to: '/admin/catalog', icon: 'it-list', label: 'Categorie e Team', tone: 'primary' }, + { to: '/admin/areas', icon: 'it-map-marker', label: 'Aree', tone: 'primary' }, + { to: '/admin/users', icon: 'it-user', label: 'Gestione Utenti', tone: 'primary' }, + { to: '/admin/moderation', icon: 'it-warning', label: 'Moderazione Abusi', tone: 'danger' } ] @@ -46,78 +21,59 @@ const adminActions = [

-
-
-
-
-
-

{{ statsRes.total_users || 0 }}

-

Utenti Registrati

-
+
+
+
+
+
{{ statsRes.total_users || 0 }}
+
Utenti registrati
-
-
-
-
-

- {{ statsRes.open_reports ?? statsRes.reports_by_status?.find(s => s.status === 'OPEN')?.total ?? 0 }} -

-

Segn. Aperte

+
+
+
+
+ {{ statsRes.open_reports ?? statsRes.reports_by_status?.find(s => s.status === 'OPEN')?.total ?? 0 }}
+
Segnalazioni aperte
-

Gestione Sistema

+
+
+
+

Gestione sistema

+ {{ adminActions.length }} sezioni +
-
-
- - - - {{ action.label }} - - +
+
+ + + {{ action.label }} + +
+
diff --git a/app/composables/useAuth.ts b/app/composables/useAuth.ts index 9b38c9d..076f1d9 100644 --- a/app/composables/useAuth.ts +++ b/app/composables/useAuth.ts @@ -29,7 +29,10 @@ export const useAuth = () => { type UserContext = CurrentUserResponse['user'] const user = useState('auth_user', () => null) const isSyncingUser = useState('auth_syncing', () => false) + const unreadNotifications = useState('auth_unread_notifications', () => 0) + const isRefreshingNotifications = useState('auth_refreshing_notifications', () => false) const isAuthenticated = computed(() => !!(tokenState.value || token.value)) + const hasUnreadNotifications = computed(() => unreadNotifications.value > 0) const isAuthStatusError = (error: any) => { const status = error?.statusCode || error?.status || error?.response?.status return status === 401 || status === 403 @@ -39,6 +42,24 @@ export const useAuth = () => { tokenState.value = newVal || null }) + const refreshUnreadNotifications = async () => { + if (!(tokenState.value || token.value) || !user.value || isRefreshingNotifications.value) { + unreadNotifications.value = user.value ? unreadNotifications.value : 0 + return + } + + isRefreshingNotifications.value = true + + try { + const res = await fetchNotifications({ page: 1, per_page: 20 }) + unreadNotifications.value = (res.notifications || []).filter(notification => !notification.read_at).length + } catch (error) { + console.error('[Auth] Failed to refresh notifications:', error) + } finally { + isRefreshingNotifications.value = false + } + } + const syncUser = async (options: { redirectOnSuccess?: boolean; currentPath?: string } = {}) => { const { redirectOnSuccess = false, currentPath } = options const tokenVal = tokenState.value || token.value @@ -49,6 +70,7 @@ export const useAuth = () => { const res = await fetchCurrentUser() if (res.ok) { user.value = res.user + await refreshUnreadNotifications() const path = currentPath ?? useNuxtApp().$router.currentRoute.value.path if (redirectOnSuccess && path.startsWith('/auth')) { @@ -79,6 +101,7 @@ export const useAuth = () => { token.value = null tokenState.value = null user.value = null + unreadNotifications.value = 0 nuxtApp.runWithContext(() => navigateTo('/auth/login')) } @@ -121,6 +144,9 @@ export const useAuth = () => { tokenState, isSyncingUser, isAuthenticated, + unreadNotifications, + hasUnreadNotifications, + refreshUnreadNotifications, handleLoginSuccess, syncUser, logout, diff --git a/app/pages/admin/reports.vue b/app/pages/admin/reports.vue index 47c1e31..f4e63bb 100644 --- a/app/pages/admin/reports.vue +++ b/app/pages/admin/reports.vue @@ -94,7 +94,7 @@ const truncate = (value?: string, max = 120) => { - - diff --git a/app/pages/notifications.vue b/app/pages/notifications.vue index 19d3e41..ad3f997 100644 --- a/app/pages/notifications.vue +++ b/app/pages/notifications.vue @@ -1,11 +1,13 @@