freshyo/apps/admin-web/src/lib/refresh-context.tsx
2026-09-06 23:05:20 +05:30

62 lines
2.2 KiB
TypeScript

import React, { createContext, useContext, useEffect, useRef } from 'react'
import { useLocation } from '@tanstack/react-router'
import { EventBus, REFRESH_EVENT } from './event-bus'
import { getQueryClient } from './query-client'
// Web port of packages/ui refresh-context + useManualRefresh +
// useMarkDataFetchers + useFocusCallback. Navigation focus (expo) is
// approximated with route-pathname changes; manual refresh uses the bus.
const RefreshContext = createContext<{ refreshAll: () => void } | null>(null)
export const RefreshProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const refreshAll = () => {
getQueryClient().invalidateQueries()
EventBus.emit(REFRESH_EVENT)
}
return <RefreshContext.Provider value={{ refreshAll }}>{children}</RefreshContext.Provider>
}
export const useRefresh = () => {
const context = useContext(RefreshContext)
if (!context) throw new Error('useRefresh must be used within RefreshProvider')
return context
}
export function useManualRefresh(callback: () => void) {
const ref = useRef(callback)
ref.current = callback
useEffect(() => {
const sub = EventBus.addListener(REFRESH_EVENT, () => ref.current())
return () => sub.remove()
}, [])
}
// Refetch on 2nd+ visit to the current route (mirrors useMarkDataFetchers:
// skip first focus, refetch on subsequent focuses).
export function useMarkDataFetchers(callback: () => void) {
const location = useLocation()
const ref = useRef(callback)
ref.current = callback
const visitsRef = useRef<Record<string, number>>({})
useEffect(() => {
const key = location.pathname + location.searchStr
const count = visitsRef.current[key] ?? 0
visitsRef.current[key] = count + 1
if (count >= 1) {
ref.current()
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [location.pathname, location.searchStr])
}
// Run callback when the window regains focus (web analogue of screen focus).
export default function useFocusCallback(callback: () => void) {
const ref = useRef(callback)
ref.current = callback
useEffect(() => {
const onFocus = () => ref.current()
window.addEventListener('focus', onFocus)
return () => window.removeEventListener('focus', onFocus)
}, [])
}