Manage Subs: change from claim_search to batch-resolve
The idea of using claim_search to indirectly batch-resolve didn't work out well. There's something wrong with the claim_search pagination where some results are duplicated in multiple pages, while some are missing. It's also returning less results that than the given number of claim ids, so sometimes the infinite scroll breaks.
This commit is contained in:
parent
0090e9b1ae
commit
3edb00b99d
2 changed files with 56 additions and 27 deletions
|
@ -1,4 +1,5 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doResolveUris } from 'redux/actions/claims';
|
||||
import { selectSubscriptionUris } from 'redux/selectors/subscriptions';
|
||||
import ChannelsFollowingManage from './view';
|
||||
|
||||
|
@ -6,4 +7,8 @@ const select = (state) => ({
|
|||
subscribedChannelUris: selectSubscriptionUris(state),
|
||||
});
|
||||
|
||||
export default connect(select)(ChannelsFollowingManage);
|
||||
const perform = {
|
||||
doResolveUris,
|
||||
};
|
||||
|
||||
export default connect(select, perform)(ChannelsFollowingManage);
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import ClaimList from 'component/claimList';
|
||||
import ClaimListDiscover from 'component/claimListDiscover';
|
||||
import DebouncedInput from 'component/common/debounced-input';
|
||||
import Empty from 'component/common/empty';
|
||||
import Page from 'component/page';
|
||||
import Spinner from 'component/spinner';
|
||||
import * as CS from 'constants/claim_search';
|
||||
import * as ICONS from 'constants/icons';
|
||||
import { parseURI } from 'util/lbryURI';
|
||||
|
||||
function getFilteredUris(uris, filterQuery) {
|
||||
if (filterQuery) {
|
||||
|
@ -18,60 +15,87 @@ function getFilteredUris(uris, filterQuery) {
|
|||
return null;
|
||||
}
|
||||
|
||||
function parseIdFromUri(uri) {
|
||||
try {
|
||||
const { channelClaimId } = parseURI(uri);
|
||||
return channelClaimId;
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// ChannelsFollowingManage
|
||||
// ****************************************************************************
|
||||
|
||||
const FOLLOW_PAGE_SIZE = 30;
|
||||
|
||||
type Props = {
|
||||
subscribedChannelUris: Array<string>,
|
||||
doResolveUris: (uris: Array<string>, returnCachedClaims: boolean, resolveReposts: boolean) => void,
|
||||
};
|
||||
|
||||
export default function ChannelsFollowingManage(props: Props) {
|
||||
const { subscribedChannelUris } = props;
|
||||
const { subscribedChannelUris, doResolveUris } = props;
|
||||
|
||||
// The locked-on-mount full set of subscribed uris.
|
||||
const [uris, setUris] = React.useState([]);
|
||||
|
||||
// Filtered query and their uris.
|
||||
const [filterQuery, setFilterQuery] = React.useState('');
|
||||
const filteredUris = getFilteredUris(uris, filterQuery);
|
||||
const [channelIds, setChannelIds] = React.useState(null);
|
||||
const [filteredUris, setFilteredUris] = React.useState(null);
|
||||
|
||||
// Infinite-scroll handling. 'page' is 0-indexed.
|
||||
const [page, setPage] = React.useState(-1);
|
||||
const lastPage = Math.max(0, Math.ceil(uris.length / FOLLOW_PAGE_SIZE) - 1);
|
||||
|
||||
async function resolveUris(uris) {
|
||||
return doResolveUris(uris, true, false);
|
||||
}
|
||||
|
||||
async function resolveNextPage(uris, currPage, pageSize = FOLLOW_PAGE_SIZE) {
|
||||
const nextPage = currPage + 1;
|
||||
const nextUriBatch = uris.slice(nextPage * pageSize, (nextPage + 1) * pageSize);
|
||||
return resolveUris(nextUriBatch);
|
||||
}
|
||||
|
||||
function bumpPage() {
|
||||
if (page < lastPage) {
|
||||
resolveNextPage(uris, page).finally(() => setPage(page + 1));
|
||||
}
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
setUris(subscribedChannelUris);
|
||||
setChannelIds(subscribedChannelUris.map((uri) => parseIdFromUri(uri)));
|
||||
resolveNextPage(subscribedChannelUris, -1).finally(() => setPage(0));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps, (lock list on mount so it doesn't shift when unfollow)
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
const filteredUris = getFilteredUris(uris, filterQuery);
|
||||
if (filteredUris) {
|
||||
resolveUris(filteredUris).finally(() => setFilteredUris(filteredUris));
|
||||
} else {
|
||||
setFilteredUris(filteredUris);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps, (only need to respond to 'filterQuery')
|
||||
}, [filterQuery]);
|
||||
|
||||
return (
|
||||
<Page className="followManage-wrapper" noFooter>
|
||||
<div className="card__title-section">
|
||||
<div className="card__title"> {__('Followed Channels')}</div>
|
||||
</div>
|
||||
|
||||
{channelIds === null ? (
|
||||
{page < 0 ? (
|
||||
<div className="main--empty">
|
||||
<Spinner />
|
||||
<Spinner delayed />
|
||||
</div>
|
||||
) : uris && uris.length === 0 ? (
|
||||
<Empty padded text="No followed channels." />
|
||||
) : (
|
||||
<>
|
||||
<DebouncedInput icon={ICONS.SEARCH} placeholder={__('Filter')} onChange={setFilterQuery} inline />
|
||||
|
||||
{filteredUris && <ClaimList uris={filteredUris} />}
|
||||
{!filteredUris && channelIds.length && (
|
||||
<ClaimListDiscover
|
||||
orderBy={CS.ORDER_BY_NAME_ASC}
|
||||
claimType={CS.CLAIM_CHANNEL}
|
||||
claimIds={channelIds}
|
||||
showHeader={false}
|
||||
hideFilters
|
||||
hideAdvancedFilter
|
||||
|
||||
{!filteredUris && uris.length > 0 && (
|
||||
<ClaimList
|
||||
uris={uris.slice(0, (page + 1) * FOLLOW_PAGE_SIZE)}
|
||||
onScrollBottom={bumpPage}
|
||||
page={page + 1}
|
||||
pageSize={FOLLOW_PAGE_SIZE}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
|
Loading…
Reference in a new issue