'use client'; import type { ReactElement } from 'react'; import { formatAge, type FreshnessLabel } from '@/lib/freshness/model'; /** * Rendering rules for non-current freshness states (RI-5-001). * * - `unavailable` renders an explicit failure panel — never an empty * healthy collection. * - `stale` may render last-known data, but only under a visible label * carrying source identity, snapshot version, and age. * - `partial` renders the verified parts plus an explicit list of what is * missing. */ interface RetryableNoticeProps { readonly onRetry?: () => void; readonly retryLabel?: string; } function RetryButton({ onRetry, retryLabel }: RetryableNoticeProps): ReactElement | null { if (!onRetry) return null; return ( ); } export interface UnavailableDataNoticeProps extends RetryableNoticeProps { /** What is unavailable, e.g. "Tasks". */ readonly title: string; /** Optional underlying failure detail (network message, invalidation reason). */ readonly detail?: string | null; } /** Explicit `unavailable` state. Never renders as an empty healthy collection. */ export function UnavailableDataNotice({ title, detail, onRetry, retryLabel, }: UnavailableDataNoticeProps): ReactElement { return (
{title} are unavailable
This is not an empty result — the data could not be verified from the gateway. {detail ? ` ${detail}` : ''}
Showing last-known data — it may be out of date
Source {label.source} · snapshot v{label.version} · fetched{' '} {formatAge(label.fetchedAt, Date.now())}. Verdicts derived from this data are unknown and changes are disabled until it is revalidated.
Some data could not be loaded
{missing.join(', ')} {missing.length === 1 ? 'is' : 'are'} unavailable — sections below show an explicit unavailable state instead of an empty list. Derived verdicts remain unknown until every collection is revalidated.