diff --git a/app/components/Header.vue b/app/components/Header.vue
index 7db4408..89fb08d 100644
--- a/app/components/Header.vue
+++ b/app/components/Header.vue
@@ -34,7 +34,7 @@ const navLinks = [
]
const { isAuthenticated, user, logout } = useAuth()
-const panelLabel = computed(() => user.value?.role?.toUpperCase() === 'ADMIN' ? 'Pannello' : 'Dashboard')
+const panelLabel = computed(() => isAdmin(user.value?.role) ? 'Pannello' : 'Dashboard')
diff --git a/app/middleware/auth.ts b/app/middleware/auth.ts
index 9cd2cd5..9292130 100644
--- a/app/middleware/auth.ts
+++ b/app/middleware/auth.ts
@@ -20,19 +20,10 @@ export default defineNuxtRouteMiddleware(async (to) => {
const requiredRole = to.meta.auth?.role
if (requiredRole && auth.user.value) {
- const userRole = auth.user.value.role.toUpperCase()
+ const userRole = auth.user.value.role
- const roleLevels: Record = {
- 'CITIZEN': 1,
- 'OPERATOR': 2,
- 'ADMIN': 3
- }
-
- const userLevel = roleLevels[userRole] || 0
- const requiredLevel = roleLevels[requiredRole] || 0
-
- if (userLevel < requiredLevel) {
- console.warn(`[Auth] User role ${userRole} (level ${userLevel}) insufficient for required ${requiredRole} (level ${requiredLevel})`)
+ if (!hasMinimumRole(userRole, requiredRole)) {
+ console.warn(`[Auth] User role ${userRole} insufficient for required ${requiredRole}`)
return navigateTo('/')
}
}
diff --git a/app/pages/admin/users.vue b/app/pages/admin/users.vue
index 774a608..67ccd02 100644
--- a/app/pages/admin/users.vue
+++ b/app/pages/admin/users.vue
@@ -17,7 +17,7 @@ const banError = ref('')
const roleError = ref('')
const pendingBanUser = ref(null)
const isUpdatingBan = ref(false)
-const parseRoles = (roles?: string) => roles ? roles.split(',').map((r) => r.trim().toUpperCase()).filter(Boolean) : []
+const parseRoles = (roles?: string) => roles ? roles.split(',').map(normalizeRole).filter(Boolean) : []
const banConfirmMessage = computed(() =>
pendingBanUser.value
? `Vuoi ${pendingBanUser.value.banned ? 'sbloccare' : 'bannare'} utente ${pendingBanUser.value.first_name} ${pendingBanUser.value.last_name}?`
diff --git a/app/pages/dashboard/index.vue b/app/pages/dashboard/index.vue
index f16106c..d6802a8 100644
--- a/app/pages/dashboard/index.vue
+++ b/app/pages/dashboard/index.vue
@@ -10,24 +10,21 @@ import OperatorDashboard from '~/components/dashboard/OperatorDashboard.vue'
import AdminDashboard from '~/components/dashboard/AdminDashboard.vue'
const currentDashboard = computed(() => {
- const role = user.value?.role?.toUpperCase()
- if (role === 'CITIZEN') return CitizenDashboard
- if (role === 'OPERATOR') return OperatorDashboard
- if (role === 'ADMIN') return AdminDashboard
+ if (isCitizen(user.value?.role)) return CitizenDashboard
+ if (isOperator(user.value?.role)) return OperatorDashboard
+ if (isAdmin(user.value?.role)) return AdminDashboard
return null
})
const heroTitle = computed(() => {
- const role = user.value?.role?.toUpperCase()
- if (role === 'ADMIN') return 'Pannello Admin'
- if (role === 'OPERATOR') return 'Gestione Operativa'
+ if (isAdmin(user.value?.role)) return 'Pannello Admin'
+ if (isOperator(user.value?.role)) return 'Gestione Operativa'
return 'Dashboard'
})
const heroSubtitle = computed(() => {
- const role = user.value?.role?.toUpperCase()
- if (role === 'ADMIN') return 'Accesso amministrativo per configurazioni, utenti e moderazione'
- if (role === 'OPERATOR') return 'Prendi in carico e gestisci le segnalazioni in corso'
+ if (isAdmin(user.value?.role)) return 'Accesso amministrativo per configurazioni, utenti e moderazione'
+ if (isOperator(user.value?.role)) return 'Prendi in carico e gestisci le segnalazioni in corso'
return 'Riepilogo rapido delle tue segnalazioni e dei punti cittadino'
})
diff --git a/app/pages/operator/reports/[id].vue b/app/pages/operator/reports/[id].vue
index f45d676..9c958dc 100644
--- a/app/pages/operator/reports/[id].vue
+++ b/app/pages/operator/reports/[id].vue
@@ -129,7 +129,9 @@ const handleStatusUpdate = async () => {
}
const handleAssignTeam = async () => {
+ if (isAdmin(user.value?.role)) return
if (!selectedTeamId.value) return
+
isAssigning.value = true
try {
const res = await assignTeam(reportId, {
@@ -229,6 +231,8 @@ const handleSendMessage = async (msgText: string, files: File[]) => {
const canFlagMessage = (message: Message) => {
if (!user.value) return false
+ if (isAdmin(user.value?.role)) return false
+
const isCitizenMessage = message.user_id !== user.value.id && message.user_id === report.value?.user_id
const isAlreadyFlagged = flaggedMessageIds.value.includes(message.id)
return isCitizenMessage && !isAlreadyFlagged
@@ -408,7 +412,7 @@ const formattedInterventionLinkExpiry = computed(() =>
-
+
diff --git a/app/pages/profile.vue b/app/pages/profile.vue
index f65d6c8..246a7cb 100644
--- a/app/pages/profile.vue
+++ b/app/pages/profile.vue
@@ -71,7 +71,7 @@ const formatDate = (dateString: string) =>
Ruolo
- {{ user?.role }}
+ {{ normalizeRole(user?.role) }}
diff --git a/app/utils/roles.ts b/app/utils/roles.ts
new file mode 100644
index 0000000..ef77b5c
--- /dev/null
+++ b/app/utils/roles.ts
@@ -0,0 +1,43 @@
+export const ROLES = {
+ CITIZEN: 'CITIZEN',
+ OPERATOR: 'OPERATOR',
+ ADMIN: 'ADMIN'
+} as const
+
+export type Role = keyof typeof ROLES
+
+export const ROLE_LEVELS: Record = {
+ [ROLES.CITIZEN]: 1,
+ [ROLES.OPERATOR]: 2,
+ [ROLES.ADMIN]: 3
+}
+
+export function normalizeRole(role?: string | null): string {
+ return role?.trim().toUpperCase() ?? ''
+}
+
+export function isRole(userRole: string | undefined | null, targetRole: string): boolean {
+ return normalizeRole(userRole) === targetRole.toUpperCase()
+}
+
+export function hasMinimumRole(userRole: string | undefined | null, requiredRole: string): boolean {
+ const userLvl = ROLE_LEVELS[normalizeRole(userRole)] || 0
+ const reqLvl = ROLE_LEVELS[requiredRole.toUpperCase()] || 0
+ return userLvl >= reqLvl
+}
+
+export function isAdmin(userRole?: string | null): boolean {
+ return isRole(userRole, ROLES.ADMIN)
+}
+
+export function isOperator(userRole?: string | null): boolean {
+ return isRole(userRole, ROLES.OPERATOR)
+}
+
+export function isCitizen(userRole?: string | null): boolean {
+ return isRole(userRole, ROLES.CITIZEN)
+}
+
+export function canAccess(userRole: string | undefined | null, requiredRole: string): boolean {
+ return hasMinimumRole(userRole, requiredRole)
+}