import { useEffect } from 'react'; import { z } from 'zod'; import { useAppDispatch, useAppSelector, useLoading } from 'soapbox/hooks'; import { type RootState } from 'soapbox/store'; import { importEntities } from '../actions'; import { Entity } from '../types'; import { EntityFn } from './types'; import { type UseEntityOpts } from './useEntity'; /** Entities will be filtered through this function until it returns true. */ type LookupFn = (entity: TEntity) => boolean function useEntityLookup( entityType: string, lookupFn: LookupFn, entityFn: EntityFn, opts: UseEntityOpts = {}, ) { const { schema = z.custom() } = opts; const dispatch = useAppDispatch(); const [isFetching, setPromise] = useLoading(true); const entity = useAppSelector(state => findEntity(state, entityType, lookupFn)); const isLoading = isFetching && !entity; const fetchEntity = async () => { try { const response = await setPromise(entityFn()); const entity = schema.parse(response.data); dispatch(importEntities([entity], entityType)); } catch (e) { // do nothing } }; useEffect(() => { if (!entity || opts.refetch) { fetchEntity(); } }, []); return { entity, fetchEntity, isFetching, isLoading, }; } function findEntity( state: RootState, entityType: string, lookupFn: LookupFn, ) { const cache = state.entities[entityType]; if (cache) { return (Object.values(cache.store) as TEntity[]).find(lookupFn); } } export { useEntityLookup };