29 lines
1.3 KiB
TypeScript
29 lines
1.3 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import type { PageEnrichment } from '../shared/enrichment.ts';
|
|
|
|
// One request per article shared by hero, collection and detail views. No wallet data is sent.
|
|
const cache = new Map<number, { expires: number; job: Promise<PageEnrichment> }>();
|
|
function load(pageId: number): Promise<PageEnrichment> {
|
|
const existing=cache.get(pageId);
|
|
if(existing && existing.expires>Date.now())return existing.job;
|
|
const job=(async()=>{
|
|
const response=await fetch(`/api/wikipedia/${pageId}`,{signal:AbortSignal.timeout(15000),cache:'no-store'});
|
|
if(!response.ok)throw new Error('Live Wikipedia data unavailable');
|
|
return await response.json() as PageEnrichment;
|
|
})();
|
|
cache.set(pageId,{expires:Date.now()+5*60*1000,job});
|
|
if(cache.size>128)cache.delete(cache.keys().next().value!);
|
|
return job;
|
|
}
|
|
export function useEnrichment(pageId: number) {
|
|
const [data,setData]=useState<PageEnrichment>();
|
|
const [error,setError]=useState(false);
|
|
const [attempt,setAttempt]=useState(0);
|
|
useEffect(()=>{
|
|
let active=true;setData(undefined);setError(false);
|
|
load(pageId).then(value=>{if(active)setData(value);},()=>{if(active)setError(true);});
|
|
return()=>{active=false;};
|
|
},[pageId,attempt]);
|
|
return {data,error,retry:()=>{cache.delete(pageId);setAttempt(n=>n+1);}};
|
|
}
|