import type { ReactNode } from 'react' import { isTimeoutError, userFacingError } from '../lib/fetch' /** Weekend Context terminology for coverage / availability indicators. */ export type DataAvailability = 'local' | 'partial' | 'stale' | 'archive' | 'limited' | 'missing' export function availabilityLabel(kind: DataAvailability): string { switch (kind) { case 'local': return 'Local' case 'partial': return 'Partial' case 'stale': return 'Stale' case 'archive': return 'Archive' case 'limited': return 'Limited' case 'missing': return 'Missing' } } export function AvailabilityBadge({ kind, label }: { kind: DataAvailability; label?: string }) { return ( {label ?? availabilityLabel(kind)} ) } export type RouteStateKind = 'loading' | 'empty' | 'error' | 'timeout' interface RouteStateProps { kind: RouteStateKind title?: string message?: ReactNode error?: unknown onRetry?: () => void retrying?: boolean testId?: string /** Optional override for the Retry button's data-testid (defaults to none). */ retryTestId?: string className?: string /** Optional availability strip (stale/limited/partial) above the state body. */ availability?: DataAvailability children?: ReactNode } const DEFAULT_TITLES: Record = { loading: 'Loading…', empty: 'Nothing here yet', error: 'Could not load this view', timeout: 'Request timed out', } const DEFAULT_MESSAGES: Record = { loading: 'Fetching the latest local data.', empty: 'No data is available for this view yet.', error: 'Something went wrong. Retry to try again.', timeout: 'This request took too long. Check your connection, then retry.', } /** * Shared primary-route state surface: loading, empty, timeout/error + retry. * Retry is a real )} )} ) } interface StaleNoticeProps { availability?: DataAvailability message?: string onRetry?: () => void testId?: string } /** Inline notice when a successful payload is limited/stale/partial. */ export function DataNotice({ availability = 'stale', message, onRetry, testId = 'data-notice', }: StaleNoticeProps) { const defaultMessage = availability === 'stale' ? 'Showing stale cached data. Retry to refresh.' : availability === 'limited' ? 'Some optional details are unavailable. Core local data is shown.' : availability === 'partial' ? 'Coverage is partial for this weekend.' : availability === 'archive' ? 'Showing an archived snapshot.' : 'Data availability is limited.' return (
{message ?? defaultMessage} {onRetry && ( )}
) }