All files / layers / L2R / slots AgeCheckIndicator.tsx

84.48% Statements 49/58
64.28% Branches 18/28
86.66% Functions 13/15
89.13% Lines 41/46

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82              37x   37x 37x 3x 922x 922x 922x 922x 2404x 922x 922x         742x     9x   580x 9x   9x 27x     580x 9x   9x   8x 2900x 7x 2x 1x   1x       7x             35x                                                
import { useSyncExternalStore } from 'react'
import type { ReactNode } from 'react'
import { useQueryClient } from '@tanstack/react-query'
import { RefreshCw } from 'lucide-react'
import type { EntityPath } from '../../L1/contracts'
import type { QueryParams } from '../../interfaces'
import { refCountKey, getRefCount, subscribeRefCount } from '../../L1/refCountStore'
import { normalizeFilters } from '../../L1/mutationQueue'
import { useDataAge } from '../../L1/useDataAge'
import { Button } from '@/components/ui/button'
 
const SKELETON_ROWS = 5
 
export interface AgeCheckIndicatorProps {
  entityPath: EntityPath
  normalizedParams?: QueryParams
  onRefresh?: () => void
  children: ReactNode
}
 
export function AgeCheckIndicator({
  entityPath,
  normalizedParams,
  onRefresh,
  children,
}: AgeCheckIndicatorProps) {
  const queryClient = useQueryClient()
 
  const normalized = normalizedParams ? normalizeFilters(normalizedParams) : {}
  const rk = refCountKey(entityPath, normalized)

  const refCount = useSyncExternalStore(
    (onStoreChange: () => void) => subscribeRefCount(rk, onStoreChange),
    () => getRefCount(rk),
  )
 
  const { isStale } = useDataAge(entityPath, normalizedParams)
 
  if (refCount > 0) return <>{children}</>
 
  if (!isStale) return <>{children}</>
 
  const handleRefresh = () => {
    if (onRefresh) {
      onRefresh()
    } else {
      queryClient.invalidateQueries({ queryKey: [entityPath] })
    }
  }
 
  return (
    <div data-testid="age-check-stale" className="space-y-4">
      <div
        data-testid="age-check-skeleton"
        className="animate-pulse space-y-2"
      >
        {Array.from({ length: SKELETON_ROWS }, (_, i) => (
          <div
            key={i}
            className="h-6 rounded bg-muted"
            style={{ width: `${80 - i * 10}%` }}
          />
        ))}
      </div>
      <div className="flex flex-col items-center gap-2 py-4">
        <p className="text-sm text-muted-foreground" data-testid="age-check-message">
          Data may be outdated
        </p>
        <Button
          variant="outline"
          size="sm"
          onClick={handleRefresh}
          data-testid="age-check-refresh"
        >
          <RefreshCw className="mr-1 size-3" />
          Refresh
        </Button>
      </div>
    </div>
  )
}