import { useSelector } from 'react-redux' import { useState } from 'react' import { useRefresh, useDataProvider } from 'react-admin' /** * A hook that automatically refreshes react-admin managed resources when refresh events are received via SSE. * * This hook is designed for components that display react-admin managed resources (like lists, shows, edits) * and need to stay in sync when those resources are modified elsewhere in the application. * * **When to use this hook:** * - Your component displays react-admin resources (albums, songs, artists, playlists, etc.) * - You want automatic refresh when those resources are created/updated/deleted * - Your data comes from standard dataProvider.getMany() calls * - You're using react-admin's data management (queries, mutations, caching) * * **When NOT to use this hook:** * - Your component displays derived/custom data not directly managed by react-admin * - You need custom reload logic beyond dataProvider.getMany() * - Your data comes from non-standard endpoints * - Use `useRefreshOnEvents` instead for these scenarios * * @param {...string} visibleResources - Resource names to watch for changes. * If no resources specified, watches all resources. * If '*' is included in resources, triggers full page refresh. * * @example * // Example 1: Album list - refresh when albums change * const AlbumList = () => { * useResourceRefresh('album') * return ... * } * * @example * // Example 2: Album show page - refresh when album or its songs change * const AlbumShow = () => { * useResourceRefresh('album', 'song') * return ... * } * * @example * // Example 3: Dashboard - refresh when any resource changes * const Dashboard = () => { * useResourceRefresh() // No parameters = watch all resources * return
...
* } * * @example * // Example 4: Library management page - watch library resources * const LibraryList = () => { * useResourceRefresh('library') * return ... * } * * **How it works:** * - Listens to refresh events from the SSE connection * - When events arrive, checks if they match the specified visible resources * - For specific resource IDs: calls dataProvider.getMany(resource, {ids: [...]}) * - For global refreshes: calls refresh() to reload the entire page * - Uses react-admin's built-in data management and caching * * **Event format expected:** * - Global refresh: { '*': '*' } or { someResource: ['*'] } * - Specific resources: { album: ['id1', 'id2'], song: ['id3'] } */ export const useResourceRefresh = (...visibleResources) => { const [lastTime, setLastTime] = useState(Date.now()) const refresh = useRefresh() const dataProvider = useDataProvider() const refreshData = useSelector( (state) => state.activity?.refresh || { lastReceived: lastTime }, ) const { resources, lastReceived } = refreshData if (lastReceived <= lastTime) { return } setLastTime(lastReceived) if ( resources && (resources['*'] === '*' || Object.values(resources).find((v) => v.find((v2) => v2 === '*'))) ) { refresh() return } if (resources) { Object.keys(resources).forEach((r) => { if (visibleResources.length === 0 || visibleResources?.includes(r)) { if (resources[r]?.length > 0) { dataProvider.getMany(r, { ids: resources[r] }) } } }) } }