// @flow import React from 'react'; import useFetched from 'effects/use-fetched'; type Props = { pins?: { urls?: Array, claimIds?: Array, onlyPinForOrder?: string }, claimsById: { [string]: Claim }, doResolveClaimIds: (Array) => Promise, doResolveUris: (Array, boolean) => Promise, }; export default function useResolvePins(props: Props) { const { pins, claimsById, doResolveClaimIds, doResolveUris } = props; const [resolvedPinUris, setResolvedPinUris] = React.useState(pins ? undefined : null); const [resolvingPinUris, setResolvingPinUris] = React.useState(false); const hasResolvedPinUris = useFetched(resolvingPinUris); React.useEffect(() => { if (resolvedPinUris === undefined && pins && !resolvingPinUris) { if (pins.claimIds) { // setResolvingPinUris is only needed for claim_search. // doResolveUris uses selectResolvingUris internally to prevent double call. setResolvingPinUris(true); // We can't use .then() here to grab the `claim_search` uris directly, // because we skip those that are already resolved. Instead, we mark a // flag here, then populate the array in the other effect below in the // next render cycle (redux would be updated by then). Pretty dumb. // $FlowFixMe: already checked for null `pins`, but flow can't see it when there's code above it? Wow. doResolveClaimIds(pins.claimIds).finally(() => setResolvingPinUris(false)); } else if (pins.urls) { doResolveUris(pins.urls, true).finally(() => setResolvedPinUris(pins.urls)); } else { setResolvedPinUris(null); } } }, [resolvedPinUris, pins, doResolveUris, doResolveClaimIds, resolvingPinUris]); React.useEffect(() => { if (hasResolvedPinUris) { if (pins && pins.claimIds) { setResolvedPinUris(pins.claimIds.map((id) => claimsById[id]?.canonical_url)); } } // Only do this over a false->true->false transition for hasResolvedPinUris. // eslint-disable-next-line react-hooks/exhaustive-deps }, [hasResolvedPinUris]); return resolvedPinUris; }