mirror of
https://github.com/complexcaresolutions/dak.c2s.git
synced 2026-03-17 18:23:42 +00:00
refactor: migrate useNotifications to TanStack Query
Replace manual useState/useEffect/setInterval polling with useQuery (refetchInterval: 60s) and useMutation for markAsRead/markAllAsRead. Public API remains identical so consumers need no changes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
5920986c02
commit
29b54e58a2
1 changed files with 47 additions and 49 deletions
|
|
@ -1,65 +1,63 @@
|
|||
import { useState, useEffect, useCallback, useRef } from 'react'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { useCallback } from 'react'
|
||||
import api from '@/services/api'
|
||||
import type { Notification, NotificationList } from '@/types'
|
||||
|
||||
const POLL_INTERVAL = 60_000 // 60 seconds
|
||||
const NOTIFICATIONS_KEY = ['notifications'] as const
|
||||
|
||||
async function fetchNotifications(): Promise<NotificationList> {
|
||||
const res = await api.get<NotificationList>('/notifications')
|
||||
return res.data
|
||||
}
|
||||
|
||||
export function useNotifications() {
|
||||
const [notifications, setNotifications] = useState<Notification[]>([])
|
||||
const [unreadCount, setUnreadCount] = useState(0)
|
||||
const [loading, setLoading] = useState(true)
|
||||
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const fetchNotifications = useCallback(async () => {
|
||||
try {
|
||||
const res = await api.get<NotificationList>('/notifications')
|
||||
setNotifications(res.data.items)
|
||||
setUnreadCount(res.data.unread_count)
|
||||
} catch {
|
||||
// Silently fail for polling
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}, [])
|
||||
const { data, isLoading } = useQuery({
|
||||
queryKey: NOTIFICATIONS_KEY,
|
||||
queryFn: fetchNotifications,
|
||||
refetchInterval: 60_000,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
fetchNotifications()
|
||||
intervalRef.current = setInterval(fetchNotifications, POLL_INTERVAL)
|
||||
return () => {
|
||||
if (intervalRef.current) {
|
||||
clearInterval(intervalRef.current)
|
||||
}
|
||||
}
|
||||
}, [fetchNotifications])
|
||||
|
||||
const markAsRead = useCallback(async (id: number) => {
|
||||
try {
|
||||
const markAsReadMutation = useMutation({
|
||||
mutationFn: async (id: number) => {
|
||||
await api.put<Notification>(`/notifications/${id}/read`)
|
||||
setNotifications((prev) =>
|
||||
prev.map((n) => (n.id === id ? { ...n, is_read: true } : n))
|
||||
)
|
||||
setUnreadCount((prev) => Math.max(0, prev - 1))
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}, [])
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: NOTIFICATIONS_KEY })
|
||||
},
|
||||
})
|
||||
|
||||
const markAllAsRead = useCallback(async () => {
|
||||
try {
|
||||
const markAllAsReadMutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
await api.put<{ marked_read: number }>('/notifications/read-all')
|
||||
setNotifications((prev) => prev.map((n) => ({ ...n, is_read: true })))
|
||||
setUnreadCount(0)
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}, [])
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: NOTIFICATIONS_KEY })
|
||||
},
|
||||
})
|
||||
|
||||
const markAsRead = useCallback(
|
||||
(id: number) => {
|
||||
markAsReadMutation.mutate(id)
|
||||
},
|
||||
[markAsReadMutation],
|
||||
)
|
||||
|
||||
const markAllAsRead = useCallback(() => {
|
||||
markAllAsReadMutation.mutate()
|
||||
}, [markAllAsReadMutation])
|
||||
|
||||
const refresh = useCallback(() => {
|
||||
queryClient.invalidateQueries({ queryKey: NOTIFICATIONS_KEY })
|
||||
}, [queryClient])
|
||||
|
||||
return {
|
||||
notifications,
|
||||
unreadCount,
|
||||
loading,
|
||||
notifications: data?.items ?? [],
|
||||
unreadCount: data?.unread_count ?? 0,
|
||||
loading: isLoading,
|
||||
markAsRead,
|
||||
markAllAsRead,
|
||||
refresh: fetchNotifications,
|
||||
refresh,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue