🏡 index : ironmagma/quintodrome.git

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 <List resource="album">...</List>
 * }
 *
 * @example
 * // Example 2: Album show page - refresh when album or its songs change
 * const AlbumShow = () => {
 *   useResourceRefresh('album', 'song')
 *   return <Show resource="album">...</Show>
 * }
 *
 * @example
 * // Example 3: Dashboard - refresh when any resource changes
 * const Dashboard = () => {
 *   useResourceRefresh() // No parameters = watch all resources
 *   return <div>...</div>
 * }
 *
 * @example
 * // Example 4: Library management page - watch library resources
 * const LibraryList = () => {
 *   useResourceRefresh('library')
 *   return <List resource="library">...</List>
 * }
 *
 * **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] })
        }
      }
    })
  }
}