142 lines
3.8 KiB
TypeScript
142 lines
3.8 KiB
TypeScript
/**
|
|
* React Hook for fetching Wikidata images on-demand
|
|
*
|
|
* This hook fetches the main image (P18 property) from Wikidata for an institution
|
|
* when we have a wikidata_id but no wikidata_image_url.
|
|
*
|
|
* Usage:
|
|
* ```tsx
|
|
* const wikidataImageUrl = useWikidataImage(institution.wikidata_id, institution.wikidata_image_url);
|
|
* // wikidataImageUrl will be:
|
|
* // - institution.wikidata_image_url if it exists
|
|
* // - fetched URL from Wikidata if wikidata_id exists
|
|
* // - undefined otherwise
|
|
* ```
|
|
*/
|
|
|
|
import { useState, useEffect, useRef } from 'react';
|
|
import { fetchWikidataImageUrl } from '../utils/wikidata';
|
|
|
|
/**
|
|
* Hook to get Wikidata image URL for an institution
|
|
*
|
|
* @param wikidataId - Wikidata entity ID (e.g., "Q190804")
|
|
* @param existingUrl - Already-known image URL (if available)
|
|
* @param enabled - Whether to fetch (default true)
|
|
* @returns The image URL (existing or fetched) or undefined
|
|
*/
|
|
export function useWikidataImage(
|
|
wikidataId: string | undefined,
|
|
existingUrl: string | undefined,
|
|
enabled: boolean = true
|
|
): string | undefined {
|
|
const [imageUrl, setImageUrl] = useState<string | undefined>(existingUrl);
|
|
const [_isLoading, setIsLoading] = useState(false);
|
|
const prevWikidataIdRef = useRef<string | undefined>(undefined);
|
|
|
|
useEffect(() => {
|
|
// If we already have a URL, use it
|
|
if (existingUrl) {
|
|
setImageUrl(existingUrl);
|
|
return;
|
|
}
|
|
|
|
// If disabled or no wikidata_id, clear and return
|
|
if (!enabled || !wikidataId) {
|
|
setImageUrl(undefined);
|
|
return;
|
|
}
|
|
|
|
// Skip if we already fetched for this ID
|
|
if (prevWikidataIdRef.current === wikidataId) {
|
|
return;
|
|
}
|
|
prevWikidataIdRef.current = wikidataId;
|
|
|
|
// Fetch from Wikidata
|
|
let cancelled = false;
|
|
setIsLoading(true);
|
|
|
|
fetchWikidataImageUrl(wikidataId)
|
|
.then((url) => {
|
|
if (!cancelled) {
|
|
setImageUrl(url || undefined);
|
|
setIsLoading(false);
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
if (!cancelled) {
|
|
console.error('[useWikidataImage] Error fetching:', error);
|
|
setIsLoading(false);
|
|
}
|
|
});
|
|
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, [wikidataId, existingUrl, enabled]);
|
|
|
|
return imageUrl;
|
|
}
|
|
|
|
/**
|
|
* Hook that returns both the image URL and loading state
|
|
*/
|
|
export function useWikidataImageWithStatus(
|
|
wikidataId: string | undefined,
|
|
existingUrl: string | undefined,
|
|
enabled: boolean = true
|
|
): { imageUrl: string | undefined; isLoading: boolean } {
|
|
const [imageUrl, setImageUrl] = useState<string | undefined>(existingUrl);
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const prevWikidataIdRef = useRef<string | undefined>(undefined);
|
|
|
|
useEffect(() => {
|
|
// If we already have a URL, use it
|
|
if (existingUrl) {
|
|
setImageUrl(existingUrl);
|
|
setIsLoading(false);
|
|
return;
|
|
}
|
|
|
|
// If disabled or no wikidata_id, clear and return
|
|
if (!enabled || !wikidataId) {
|
|
setImageUrl(undefined);
|
|
setIsLoading(false);
|
|
return;
|
|
}
|
|
|
|
// Skip if we already fetched for this ID (but allow refetch on ID change)
|
|
if (prevWikidataIdRef.current === wikidataId && imageUrl !== undefined) {
|
|
return;
|
|
}
|
|
prevWikidataIdRef.current = wikidataId;
|
|
|
|
// Fetch from Wikidata
|
|
let cancelled = false;
|
|
setIsLoading(true);
|
|
|
|
fetchWikidataImageUrl(wikidataId)
|
|
.then((url) => {
|
|
if (!cancelled) {
|
|
setImageUrl(url || undefined);
|
|
setIsLoading(false);
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
if (!cancelled) {
|
|
console.error('[useWikidataImage] Error fetching:', error);
|
|
setImageUrl(undefined);
|
|
setIsLoading(false);
|
|
}
|
|
});
|
|
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, [wikidataId, existingUrl, enabled, imageUrl]);
|
|
|
|
return { imageUrl, isLoading };
|
|
}
|
|
|
|
export default useWikidataImage;
|