mirror of
https://github.com/complexcaresolutions/dak.c2s.git
synced 2026-03-17 20:43:41 +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 api from '@/services/api'
|
||||||
import type { Notification, NotificationList } from '@/types'
|
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() {
|
export function useNotifications() {
|
||||||
const [notifications, setNotifications] = useState<Notification[]>([])
|
const queryClient = useQueryClient()
|
||||||
const [unreadCount, setUnreadCount] = useState(0)
|
|
||||||
const [loading, setLoading] = useState(true)
|
|
||||||
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)
|
|
||||||
|
|
||||||
const fetchNotifications = useCallback(async () => {
|
const { data, isLoading } = useQuery({
|
||||||
try {
|
queryKey: NOTIFICATIONS_KEY,
|
||||||
const res = await api.get<NotificationList>('/notifications')
|
queryFn: fetchNotifications,
|
||||||
setNotifications(res.data.items)
|
refetchInterval: 60_000,
|
||||||
setUnreadCount(res.data.unread_count)
|
})
|
||||||
} catch {
|
|
||||||
// Silently fail for polling
|
|
||||||
} finally {
|
|
||||||
setLoading(false)
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
useEffect(() => {
|
const markAsReadMutation = useMutation({
|
||||||
fetchNotifications()
|
mutationFn: async (id: number) => {
|
||||||
intervalRef.current = setInterval(fetchNotifications, POLL_INTERVAL)
|
|
||||||
return () => {
|
|
||||||
if (intervalRef.current) {
|
|
||||||
clearInterval(intervalRef.current)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [fetchNotifications])
|
|
||||||
|
|
||||||
const markAsRead = useCallback(async (id: number) => {
|
|
||||||
try {
|
|
||||||
await api.put<Notification>(`/notifications/${id}/read`)
|
await api.put<Notification>(`/notifications/${id}/read`)
|
||||||
setNotifications((prev) =>
|
},
|
||||||
prev.map((n) => (n.id === id ? { ...n, is_read: true } : n))
|
onSuccess: () => {
|
||||||
)
|
queryClient.invalidateQueries({ queryKey: NOTIFICATIONS_KEY })
|
||||||
setUnreadCount((prev) => Math.max(0, prev - 1))
|
},
|
||||||
} catch {
|
})
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const markAllAsRead = useCallback(async () => {
|
const markAllAsReadMutation = useMutation({
|
||||||
try {
|
mutationFn: async () => {
|
||||||
await api.put<{ marked_read: number }>('/notifications/read-all')
|
await api.put<{ marked_read: number }>('/notifications/read-all')
|
||||||
setNotifications((prev) => prev.map((n) => ({ ...n, is_read: true })))
|
},
|
||||||
setUnreadCount(0)
|
onSuccess: () => {
|
||||||
} catch {
|
queryClient.invalidateQueries({ queryKey: NOTIFICATIONS_KEY })
|
||||||
// ignore
|
},
|
||||||
}
|
})
|
||||||
}, [])
|
|
||||||
|
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 {
|
return {
|
||||||
notifications,
|
notifications: data?.items ?? [],
|
||||||
unreadCount,
|
unreadCount: data?.unread_count ?? 0,
|
||||||
loading,
|
loading: isLoading,
|
||||||
markAsRead,
|
markAsRead,
|
||||||
markAllAsRead,
|
markAllAsRead,
|
||||||
refresh: fetchNotifications,
|
refresh,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue