diff --git a/ui/page/livestreamSetup/view.jsx b/ui/page/livestreamSetup/view.jsx index eb6da5a23..61ead7329 100644 --- a/ui/page/livestreamSetup/view.jsx +++ b/ui/page/livestreamSetup/view.jsx @@ -15,6 +15,7 @@ import CopyableText from 'component/copyableText'; import Card from 'component/common/card'; import ClaimList from 'component/claimList'; import usePersistedState from 'effects/use-persisted-state'; +import usePrevious from 'effects/use-previous'; type Props = { channels: Array, @@ -50,8 +51,116 @@ export default function LivestreamSetupPage(props: Props) { claim.value_type === 'stream' && !(claim.value && claim.value.source) ) : []; + const [localPending, setLocalPending] = React.useState([]); // + const localPendingStr = JSON.stringify(localPending); + const pendingLivestreamClaimsStr = JSON.stringify(pendingLiveStreamClaims); + const prevPendingLiveStreamClaimStr = usePrevious(pendingLivestreamClaimsStr); + const liveStreamClaimsStr = JSON.stringify(livestreamClaims); + const prevLiveStreamClaimsStr = JSON.stringify(liveStreamClaimsStr); const pendingLength = pendingLiveStreamClaims.length; - const totalLivestreamClaims = pendingLiveStreamClaims.concat(livestreamClaims); + + // maintain a pendingClaims list by channelId that locally that things are removed from only when they show up in claim_search results. + + React.useEffect(() => { + if (activeChannelClaimStr) { + const channelClaim = JSON.parse(activeChannelClaimStr); + + // ensure we have a channel + if (channelClaim.claim_id) { + Lbry.channel_sign({ + channel_id: channelClaim.claim_id, + hexdata: toHex(channelClaim.name), + }) + .then((data) => { + setSigData(data); + }) + .catch((error) => { + setSigData({ signature: null, signing_ts: null }); + }); + } + } + }, [activeChannelClaimStr, setSigData]); + + // The following 2 effects handle the time between pending disappearing and claim_search being able to find it. + // We'll maintain our own pending list: + // add to it when there are new things in pending + // remove items only when our claim_search finds it + React.useEffect(() => { + // add to localPending when pending changes + const localPending = JSON.parse(localPendingStr); + const pendingLivestreamClaims = JSON.parse(pendingLivestreamClaimsStr); + if ( + pendingLiveStreamClaims !== prevPendingLiveStreamClaimStr || + (pendingLivestreamClaims.length && !localPending.length) + ) { + const prevPendingLivestreamClaims = prevPendingLiveStreamClaimStr + ? JSON.parse(prevPendingLiveStreamClaimStr) + : []; + const pendingClaimIds = pendingLivestreamClaims.map((claim) => claim.claim_id); + const prevPendingClaimIds = prevPendingLivestreamClaims.map((claim) => claim.claim_id); + const newLocalPending = []; + if (pendingClaimIds.length > prevPendingClaimIds.length) { + pendingLivestreamClaims.forEach((pendingClaim) => { + if (!localPending.some((lClaim) => lClaim.claim_id === pendingClaim.claim_id)) { + newLocalPending.push(pendingClaim); + } + }); + setLocalPending(localPending.concat(newLocalPending)); + } + } + }, [pendingLivestreamClaimsStr, prevPendingLiveStreamClaimStr, localPendingStr, setLocalPending]); + + React.useEffect(() => { + // remove from localPending when livestreamClaims found + const localPending = JSON.parse(localPendingStr); + if (liveStreamClaimsStr !== prevLiveStreamClaimsStr && localPending.length) { + const livestreamClaims = JSON.parse(liveStreamClaimsStr); + setLocalPending( + localPending.filter((pending) => !livestreamClaims.some((claim) => claim.claim_id === pending.claim_id)) + ); + } + }, [liveStreamClaimsStr, prevLiveStreamClaimsStr, localPendingStr, setLocalPending]); + + React.useEffect(() => { + let checkClaimsInterval; + if (!activeChannelClaimStr) return; + const channelClaim = JSON.parse(activeChannelClaimStr); + + function checkLivestreamClaims() { + Lbry.claim_search({ + channel_ids: [channelClaim.claim_id], + has_no_source: true, + claim_type: ['stream'], + }) + .then((res) => { + if (res && res.items && res.items.length > 0) { + setLivestreamClaims(res.items.reverse()); + } else { + setLivestreamClaims([]); + } + setSpin(false); + }) + .catch(() => { + setLivestreamClaims([]); + setSpin(false); + }); + } + if (!checkClaimsInterval) { + checkLivestreamClaims(); + checkClaimsInterval = setInterval(checkLivestreamClaims, LIVESTREAM_CLAIM_POLL_IN_MS); + } + return () => { + if (checkClaimsInterval) { + clearInterval(checkClaimsInterval); + } + }; + }, [activeChannelClaimStr, pendingLength, setSpin]); + const activeChannelId = activeChannelClaim && activeChannelClaim.claim_id; + const localPendingForChannel = localPending.filter( + (claim) => claim.signing_channel && claim.signing_channel.claim_id === activeChannelId + ); + const totalLivestreamClaims = localPendingForChannel.concat(livestreamClaims); + const helpText = (

@@ -95,61 +204,6 @@ export default function LivestreamSetupPage(props: Props) {

); - React.useEffect(() => { - if (activeChannelClaimStr) { - const channelClaim = JSON.parse(activeChannelClaimStr); - - // ensure we have a channel - if (channelClaim.claim_id) { - Lbry.channel_sign({ - channel_id: channelClaim.claim_id, - hexdata: toHex(channelClaim.name), - }) - .then((data) => { - setSigData(data); - }) - .catch((error) => { - setSigData({ signature: null, signing_ts: null }); - }); - } - } - }, [activeChannelClaimStr, setSigData]); - - React.useEffect(() => { - let checkClaimsInterval; - if (!activeChannelClaimStr) return; - const channelClaim = JSON.parse(activeChannelClaimStr); - - function checkLivestreamClaims() { - Lbry.claim_search({ - channel_ids: [channelClaim.claim_id], - has_no_source: true, - claim_type: ['stream'], - }) - .then((res) => { - if (res && res.items && res.items.length > 0) { - setLivestreamClaims(res.items.reverse()); - } else { - setLivestreamClaims([]); - } - setSpin(false); - }) - .catch(() => { - setLivestreamClaims([]); - setSpin(false); - }); - } - if (!checkClaimsInterval) { - checkLivestreamClaims(); - checkClaimsInterval = setInterval(checkLivestreamClaims, LIVESTREAM_CLAIM_POLL_IN_MS); - } - return () => { - if (checkClaimsInterval) { - clearInterval(checkClaimsInterval); - } - }; - }, [activeChannelClaimStr, pendingLength, setSpin]); - return ( {(fetchingChannels || spin) && ( @@ -219,11 +273,11 @@ export default function LivestreamSetupPage(props: Props) { {totalLivestreamClaims.length > 0 ? ( <> - {Boolean(pendingLiveStreamClaims.length) && ( + {Boolean(localPendingForChannel.length) && (
claim.permanent_url)} + uris={localPendingForChannel.map((claim) => claim.permanent_url)} />
)}