Add useBatchedEntities hook for relationships

This commit is contained in:
Alex Gleason
2023-06-25 15:57:13 -05:00
parent a5e213eca0
commit 989d99f908
9 changed files with 231 additions and 119 deletions

View File

@@ -8,7 +8,7 @@ import { useAccountLookup } from 'soapbox/api/hooks';
import LoadMore from 'soapbox/components/load-more';
import MissingIndicator from 'soapbox/components/missing-indicator';
import { Column, Spinner } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector, useFeatures, useLoggedIn } from 'soapbox/hooks';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import { getAccountGallery } from 'soapbox/selectors';
import MediaItem from './components/media-item';
@@ -34,17 +34,13 @@ const LoadMoreMedia: React.FC<ILoadMoreMedia> = ({ maxId, onLoadMore }) => {
const AccountGallery = () => {
const dispatch = useAppDispatch();
const { username } = useParams<{ username: string }>();
const features = useFeatures();
const { me } = useLoggedIn();
const {
account,
isLoading: accountLoading,
isUnavailable,
} = useAccountLookup(username, { withRelationship: true });
const isBlocked = account?.relationship?.blocked_by === true;
const unavailable = (me === account?.id) ? false : (isBlocked && !features.blockersVisible);
const attachments: ImmutableList<Attachment> = useAppSelector((state) => getAccountGallery(state, account!.id));
const isLoading = useAppSelector((state) => state.timelines.get(`account:${account?.id}:media`)?.isLoading);
const hasMore = useAppSelector((state) => state.timelines.get(`account:${account?.id}:media`)?.hasMore);
@@ -106,7 +102,7 @@ const AccountGallery = () => {
loadOlder = <LoadMore className='my-auto' visible={!isLoading} onClick={handleLoadOlder} />;
}
if (unavailable) {
if (isUnavailable) {
return (
<Column>
<div className='empty-column-indicator'>

View File

@@ -1,20 +1,12 @@
import { OrderedSet as ImmutableOrderedSet } from 'immutable';
import debounce from 'lodash/debounce';
import React, { useCallback, useEffect, useState } from 'react';
import React from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import {
fetchAccount,
fetchFollowing,
expandFollowing,
fetchAccountByUsername,
} from 'soapbox/actions/accounts';
import { useAccountLookup } from 'soapbox/api/hooks';
import { useFollowing } from 'soapbox/api/hooks/accounts/useFollowing';
import Account from 'soapbox/components/account';
import MissingIndicator from 'soapbox/components/missing-indicator';
import ScrollableList from 'soapbox/components/scrollable-list';
import { Column, Spinner } from 'soapbox/components/ui';
import AccountContainer from 'soapbox/containers/account-container';
import { useAppDispatch, useAppSelector, useFeatures, useOwnAccount } from 'soapbox/hooks';
const messages = defineMessages({
heading: { id: 'column.following', defaultMessage: 'Following' },
@@ -27,53 +19,19 @@ interface IFollowing {
}
/** Displays a list of accounts the given user is following. */
const Following: React.FC<IFollowing> = (props) => {
const Following: React.FC<IFollowing> = ({ params }) => {
const intl = useIntl();
const dispatch = useAppDispatch();
const features = useFeatures();
const { account: ownAccount } = useOwnAccount();
const [loading, setLoading] = useState(true);
const { account, isUnavailable } = useAccountLookup(params?.username);
const username = props.params?.username || '';
const { account } = useAccountLookup(username);
const isOwnAccount = username.toLowerCase() === ownAccount?.username?.toLowerCase();
const {
accounts,
hasNextPage,
fetchNextPage,
isLoading,
} = useFollowing(account?.id);
const accountIds = useAppSelector(state => state.user_lists.following.get(account!?.id)?.items || ImmutableOrderedSet<string>());
const hasMore = useAppSelector(state => !!state.user_lists.following.get(account!?.id)?.next);
const isUnavailable = useAppSelector(state => {
const blockedBy = state.relationships.getIn([account?.id, 'blocked_by']) === true;
return isOwnAccount ? false : (blockedBy && !features.blockersVisible);
});
const handleLoadMore = useCallback(debounce(() => {
if (account) {
dispatch(expandFollowing(account.id));
}
}, 300, { leading: true }), [account?.id]);
useEffect(() => {
let promises = [];
if (account) {
promises = [
dispatch(fetchAccount(account.id)),
dispatch(fetchFollowing(account.id)),
];
} else {
promises = [
dispatch(fetchAccountByUsername(username)),
];
}
Promise.all(promises)
.then(() => setLoading(false))
.catch(() => setLoading(false));
}, [account?.id, username]);
if (loading && accountIds.isEmpty()) {
if (isLoading) {
return (
<Spinner />
);
@@ -97,14 +55,14 @@ const Following: React.FC<IFollowing> = (props) => {
<Column label={intl.formatMessage(messages.heading)} transparent>
<ScrollableList
scrollKey='following'
hasMore={hasMore}
onLoadMore={handleLoadMore}
hasMore={hasNextPage}
onLoadMore={fetchNextPage}
emptyMessage={<FormattedMessage id='account.follows.empty' defaultMessage="This user doesn't follow anyone yet." />}
itemClassName='pb-4'
>
{accountIds.map(id =>
<AccountContainer key={id} id={id} />,
)}
{accounts.map((account) => (
<Account key={account.id} account={account} />
))}
</ScrollableList>
</Column>
);