Add unread notification badge and poll to dashboard layout
- Import onCleanup, getAuthHeader in DashboardLayout - Poll /api/me/notifications every 60s for unread_count - Show orange badge on bell icon when unread > 0 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
bcb940f3f1
commit
f5d294abbf
1 changed files with 44 additions and 3 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { Component, Show, createEffect, For, createSignal, onMount } from 'solid-js';
|
||||
import { Component, Show, createEffect, For, createSignal, onMount, onCleanup } from 'solid-js';
|
||||
import { useNavigate, A, useSearchParams } from '@solidjs/router';
|
||||
import { authState, logout, switchRole, bootstrapAuth, setMockRuntimeConfig, isModuleLocked } from '~/lib/auth';
|
||||
import { authState, logout, switchRole, bootstrapAuth, setMockRuntimeConfig, isModuleLocked, getAuthHeader } from '~/lib/auth';
|
||||
import { shouldShowRoleSwitcher, getRoleLabel } from '~/lib/auth-flow';
|
||||
import {
|
||||
getRoleTourStorageKey,
|
||||
|
|
@ -340,6 +340,22 @@ export default function DashboardLayout(props: { children: any }) {
|
|||
const [tourKind, setTourKind] = createSignal<GuidedTourKind | null>(null);
|
||||
const [tourStepIndex, setTourStepIndex] = createSignal(0);
|
||||
const [authReady, setAuthReady] = createSignal(false);
|
||||
const [unreadCount, setUnreadCount] = createSignal(0);
|
||||
|
||||
const API = import.meta.env.VITE_API_URL ?? 'http://localhost:8000';
|
||||
|
||||
async function fetchUnreadCount() {
|
||||
const auth = getAuthHeader();
|
||||
if (!auth.Authorization) return;
|
||||
try {
|
||||
const res = await fetch(`${API}/api/me/notifications?page=1&limit=1`, { headers: auth });
|
||||
if (!res.ok) return;
|
||||
const data = await res.json();
|
||||
setUnreadCount(data.unread_count ?? 0);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
// Restore session or inject mock preview config
|
||||
onMount(async () => {
|
||||
|
|
@ -350,6 +366,10 @@ export default function DashboardLayout(props: { children: any }) {
|
|||
await bootstrapAuth();
|
||||
}
|
||||
setAuthReady(true);
|
||||
// Poll for unread notification count every 60 seconds
|
||||
await fetchUnreadCount();
|
||||
const notifTimer = setInterval(fetchUnreadCount, 60_000);
|
||||
onCleanup(() => clearInterval(notifTimer));
|
||||
});
|
||||
|
||||
createEffect(() => {
|
||||
|
|
@ -580,8 +600,29 @@ export default function DashboardLayout(props: { children: any }) {
|
|||
</A>
|
||||
</div>
|
||||
</Show>
|
||||
<A href="/dashboard/notifications" class="topbar-icon-btn" title="Notifications">
|
||||
<A href="/dashboard/notifications" class="topbar-icon-btn" title="Notifications" style={{ position: 'relative' }}>
|
||||
<IconBell />
|
||||
<Show when={unreadCount() > 0}>
|
||||
<span style={{
|
||||
position: 'absolute',
|
||||
top: '2px',
|
||||
right: '2px',
|
||||
'min-width': '16px',
|
||||
height: '16px',
|
||||
'border-radius': '999px',
|
||||
background: '#fd6116',
|
||||
color: '#fff',
|
||||
'font-size': '10px',
|
||||
'font-weight': '800',
|
||||
display: 'flex',
|
||||
'align-items': 'center',
|
||||
'justify-content': 'center',
|
||||
padding: '0 3px',
|
||||
'line-height': '1',
|
||||
}}>
|
||||
{unreadCount() > 99 ? '99+' : unreadCount()}
|
||||
</span>
|
||||
</Show>
|
||||
</A>
|
||||
<div class="topbar-user">
|
||||
<span class="topbar-name">{rc()?.user?.full_name ?? 'User'}</span>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue