import { useCallback, useEffect, useRef, useState } from 'react'; import { useHttpService } from '../../services/HttpService'; import { isRefusedRead } from '../../utils/fetchFailureMessage'; import { readUrlFor, summariseShownItem, type ShownItemSummary, type ShownResource } from './shareableRecordItem'; export type ShownRead = | { state: 'loading' } | { state: 'ready'; summary: ShownItemSummary } | { state: 'refused' } | { state: 'failed' }; const LOADING: ShownRead = { state: 'loading' }; /** * A refusal is its own state, not a failed load. Answers are keyed to the reference, so a late one * never appears under the next item. */ export const useShownRecordItem = (reference: string | null) => { const { get } = useHttpService(); const getRef = useRef(get); getRef.current = get; const [read, setRead] = useState<{ reference: string; result: ShownRead } | null>(null); const [attempt, setAttempt] = useState(0); useEffect(() => { if (!reference) return; const url = readUrlFor(reference); if (!url) { setRead({ reference, result: { state: 'failed' } }); return; } let cancelled = false; setRead({ reference, result: LOADING }); getRef.current(url) .then((item) => { if (cancelled) return; setRead({ reference, result: item?.resourceType ? { state: 'ready', summary: summariseShownItem(item) } : { state: 'failed' }, }); }) .catch((error: unknown) => { if (cancelled) return; setRead({ reference, result: { state: isRefusedRead(error) ? 'refused' : 'failed' } }); }); return () => { cancelled = true; }; }, [reference, attempt]); const retry = useCallback(() => setAttempt((n) => n + 1), []); return { read: reference && read?.reference === reference ? read.result : LOADING, retry, }; };