Files
shiftcraft/app/components/App/Notifications.vue
2026-04-17 23:26:01 +00:00

86 lines
2.1 KiB
Vue

<template>
<UTooltip
:text="$t('notifications')"
:shortcuts="['N']"
>
<UButton
color="neutral"
variant="ghost"
square
@click="drawerOpen = true"
>
<UChip
color="error"
:show="hasUnreadNotifications"
inset
>
<UIcon
name="i-lucide-bell"
class="size-5 shrink-0"
/>
</UChip>
</UButton>
</UTooltip>
<USlideover
v-model:open="drawerOpen"
:title="$t('notifications')"
>
<template #body>
<div
v-for="notification in notifications"
:key="notification.id"
v-on-visible="() => markAsRead(notification.id)"
class="px-3 py-2.5 rounded-md hover:bg-elevated/50 flex items-center gap-3 relative -mx-3 first:-mt-3 last:-mb-3"
>
<UChip
color="error"
:show="!notification.isRead"
inset
>
<UAvatar
alt="Nuxt"
size="md"
/>
</UChip>
<div class="text-sm flex-1">
<p class="flex items-center justify-between">
<span class="text-highlighted font-medium">{{ notification.title }}</span>
<time
:datetime="notification.created"
class="text-muted text-xs"
v-text="$d(new Date(notification.created), { year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric' })"
/>
</p>
<p class="text-dimmed">
{{ notification.body }}
</p>
</div>
</div>
</template>
</USlideover>
</template>
<script setup lang="ts">
const { fetchNotifications, subscribeToChanges, unsubscribe, markAsRead } = useNotifications()
const { notifications } = storeToRefs(useNotifications())
const drawerOpen = ref(false)
const hasUnreadNotifications = computed(() => notifications.value.some(n => !n.isRead))
// Fetch the notifications once on page load
fetchNotifications()
onMounted(() => {
// Subscribe to realtime changes of notifications
subscribeToChanges()
})
// Unsubscribe for cleanup
onUnmounted(() => {
unsubscribe()
})
</script>