211 lines
6.9 KiB
Vue
211 lines
6.9 KiB
Vue
<script setup lang="ts">
|
|
import type { Notification } from '~/types/api'
|
|
|
|
definePageMeta({
|
|
middleware: 'auth',
|
|
})
|
|
|
|
useHead({ title: 'Notifiche - Visione' })
|
|
|
|
const { fetchNotifications, markNotificationRead, refreshUnreadNotifications } = useAuth()
|
|
const router = useRouter()
|
|
|
|
const page = ref(1)
|
|
const perPage = ref(15)
|
|
|
|
const { data: notificationsData, refresh: refreshNotifications } = await useAsyncData(
|
|
'notifications',
|
|
() => fetchNotifications({ page: page.value, per_page: perPage.value }),
|
|
{ watch: [page] }
|
|
)
|
|
|
|
const notifications = computed<Notification[]>(() => notificationsData.value?.notifications || [])
|
|
const totalNotifications = computed(() => notificationsData.value?.notifications?.length || 0)
|
|
const unreadCount = computed(() => notifications.value.filter((notification) => !notification.read_at).length)
|
|
|
|
const handleMarkAsRead = async (notificationId: number) => {
|
|
try {
|
|
await markNotificationRead(notificationId)
|
|
await refreshNotifications()
|
|
await refreshUnreadNotifications()
|
|
} catch (error) {
|
|
console.error('Error marking notification as read:', error)
|
|
}
|
|
}
|
|
|
|
const handleNotificationClick = async (notification: Notification) => {
|
|
if (!notification.read_at) {
|
|
await handleMarkAsRead(notification.id)
|
|
}
|
|
|
|
if (notification.report_id) {
|
|
router.push(`/reports/${notification.report_id}`)
|
|
}
|
|
}
|
|
|
|
const formatDate = (dateString: string): string => {
|
|
const date = new Date(dateString)
|
|
const now = new Date()
|
|
const diffMs = now.getTime() - date.getTime()
|
|
const diffMins = Math.floor(diffMs / 60000)
|
|
const diffHours = Math.floor(diffMins / 60)
|
|
const diffDays = Math.floor(diffHours / 24)
|
|
|
|
if (diffMins < 1) return 'Proprio ora'
|
|
if (diffMins < 60) return `${diffMins}m fa`
|
|
if (diffHours < 24) return `${diffHours}h fa`
|
|
if (diffDays < 7) return `${diffDays}d fa`
|
|
|
|
return date.toLocaleDateString('it-IT', {
|
|
day: '2-digit',
|
|
month: '2-digit',
|
|
year: '2-digit'
|
|
})
|
|
}
|
|
|
|
const getNotificationIcon = (type: string): string => {
|
|
const icons: Record<string, string> = {
|
|
'report_created': 'it-pencil',
|
|
'report_assigned': 'it-check-circle',
|
|
'report_updated': 'it-refresh',
|
|
'report_resolved': 'it-check-circle',
|
|
'message_received': 'it-comment',
|
|
'feedback_requested': 'it-star',
|
|
'reward_earned': 'it-star',
|
|
}
|
|
return icons[type] || 'it-bell'
|
|
}
|
|
|
|
const getNotificationColor = (type: string): string => {
|
|
const colors: Record<string, string> = {
|
|
'report_created': 'primary',
|
|
'report_assigned': 'info',
|
|
'report_updated': 'info',
|
|
'report_resolved': 'success',
|
|
'message_received': 'primary',
|
|
'feedback_requested': 'warning',
|
|
'reward_earned': 'warning',
|
|
}
|
|
return colors[type] || 'secondary'
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<div class="bg-light border-bottom py-4 mb-4">
|
|
<div class="container">
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<h1 class="h3 font-weight-bold mb-2">
|
|
<BIIcon name="it-bell" size="sm" color="primary" class="me-2" />
|
|
Centro Notifiche
|
|
</h1>
|
|
<p class="text-muted mb-0">
|
|
{{ unreadCount > 0 ? `Hai ${unreadCount} notifiche non lette` : 'Tutte le notifiche lette' }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="container mb-5">
|
|
<div class="row">
|
|
<div class="col-12 col-lg-10 offset-lg-1">
|
|
<div v-if="notifications.length === 0" class="card card-bg border-0 shadow-sm">
|
|
<div class="card-body py-5 text-center">
|
|
<BIIcon name="it-bell" size="lg" color="secondary" class="mb-3 d-block mx-auto" />
|
|
<h2 class="h5 mb-2">Nessuna notifica</h2>
|
|
<p class="text-muted mb-3">Quando arriveranno aggiornamenti sulle tue segnalazioni, li troverai qui.</p>
|
|
<NuxtLink to="/reports" class="btn btn-outline-primary btn-sm">
|
|
Vai alle segnalazioni
|
|
</NuxtLink>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-else class="card card-bg border-0 shadow-sm">
|
|
<div class="card-body p-0">
|
|
<div
|
|
v-for="notification in notifications"
|
|
:key="notification.id"
|
|
class="notification-row p-3"
|
|
:class="{ 'notification-row-unread': !notification.read_at }"
|
|
>
|
|
<div class="d-flex align-items-start gap-3">
|
|
<div class="flex-shrink-0 mt-1">
|
|
<div
|
|
class="rounded-circle d-flex align-items-center justify-content-center notification-icon"
|
|
:class="`bg-${getNotificationColor(notification.type)}`"
|
|
>
|
|
<BIIcon :name="getNotificationIcon(notification.type)" size="sm" color="white" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex-grow-1">
|
|
<div class="d-flex flex-wrap justify-content-between gap-2">
|
|
<div>
|
|
<h2 class="h6 mb-1">{{ notification.title }}</h2>
|
|
<p class="mb-1 text-muted">{{ notification.body }}</p>
|
|
<small class="text-muted">{{ formatDate(notification.created_at) }}</small>
|
|
</div>
|
|
<div v-if="!notification.read_at" class="flex-shrink-0">
|
|
<span class="badge bg-primary">Nuovo</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-3 d-flex flex-wrap gap-2">
|
|
<button
|
|
type="button"
|
|
class="btn btn-outline-primary btn-sm"
|
|
@click="handleNotificationClick(notification)"
|
|
>
|
|
Apri notifica
|
|
</button>
|
|
<NuxtLink v-if="notification.report_id" :to="`/reports/${notification.report_id}`" class="btn btn-outline-primary btn-sm">
|
|
Vedi segnalazione
|
|
</NuxtLink>
|
|
<button
|
|
v-if="!notification.read_at"
|
|
type="button"
|
|
class="btn btn-outline-secondary btn-sm"
|
|
@click.stop="handleMarkAsRead(notification.id)"
|
|
>
|
|
Segna come letta
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<Pagination
|
|
v-if="notifications.length > 0"
|
|
:current-page="page"
|
|
:per-page="perPage"
|
|
:total-items="totalNotifications"
|
|
@page-change="page = $event"
|
|
/>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.notification-row + .notification-row {
|
|
border-top: 1px solid #e9ecef;
|
|
}
|
|
|
|
.notification-row-unread {
|
|
border-left: 4px solid #0066cc;
|
|
background: #f8fbff;
|
|
}
|
|
|
|
.notification-icon {
|
|
width: 40px;
|
|
height: 40px;
|
|
}
|
|
</style>
|