113 lines
2.9 KiB
TypeScript
113 lines
2.9 KiB
TypeScript
import { useMemo } from 'react';
|
|
import type { FC, ReactNode } from 'react';
|
|
|
|
import { AccountListItem } from '@/mastodon/components/account_list_item';
|
|
import { Column } from '@/mastodon/components/column';
|
|
import { ColumnBackButton } from '@/mastodon/components/column_back_button';
|
|
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
|
|
import ScrollableList from '@/mastodon/components/scrollable_list';
|
|
import BundleColumnError from '@/mastodon/features/ui/components/bundle_column_error';
|
|
import { useAccount } from '@/mastodon/hooks/useAccount';
|
|
import { useAccountVisibility } from '@/mastodon/hooks/useAccountVisibility';
|
|
import { useLayout } from '@/mastodon/hooks/useLayout';
|
|
|
|
import { RemoteHint } from './remote';
|
|
|
|
export interface AccountList {
|
|
hasMore: boolean;
|
|
isLoading: boolean;
|
|
items: string[];
|
|
}
|
|
|
|
interface AccountListProps {
|
|
accountId?: string | null;
|
|
append?: ReactNode;
|
|
emptyMessage: ReactNode;
|
|
header?: ReactNode;
|
|
footer?: ReactNode;
|
|
list?: AccountList | null;
|
|
loadMore: () => void;
|
|
prependAccountId?: string | null;
|
|
scrollKey: string;
|
|
}
|
|
|
|
export const AccountList: FC<AccountListProps> = ({
|
|
accountId,
|
|
append,
|
|
emptyMessage,
|
|
header,
|
|
footer,
|
|
list,
|
|
loadMore,
|
|
prependAccountId,
|
|
scrollKey,
|
|
}) => {
|
|
const account = useAccount(accountId);
|
|
|
|
const { blockedBy, hidden, suspended } = useAccountVisibility(accountId);
|
|
const forceEmptyState = blockedBy || hidden || suspended;
|
|
|
|
const children = useMemo(() => {
|
|
if (forceEmptyState) {
|
|
return [];
|
|
}
|
|
const children =
|
|
list?.items.map((followerId) => (
|
|
<AccountListItem
|
|
key={followerId}
|
|
accountId={followerId}
|
|
withBio={false}
|
|
/>
|
|
)) ?? [];
|
|
|
|
if (prependAccountId) {
|
|
children.unshift(
|
|
<AccountListItem
|
|
key={prependAccountId}
|
|
accountId={prependAccountId}
|
|
withBio={false}
|
|
/>,
|
|
);
|
|
}
|
|
return children;
|
|
}, [prependAccountId, list, forceEmptyState]);
|
|
|
|
const { multiColumn } = useLayout();
|
|
|
|
// Null means accountId does not exist (e.g. invalid acct). Undefined means loading.
|
|
if (accountId === null) {
|
|
return <BundleColumnError multiColumn={multiColumn} errorType='routing' />;
|
|
}
|
|
|
|
if (!accountId || !account) {
|
|
return (
|
|
<Column bindToDocument={!multiColumn}>
|
|
<LoadingIndicator />
|
|
</Column>
|
|
);
|
|
}
|
|
|
|
const domain = account.acct.split('@')[1];
|
|
|
|
return (
|
|
<Column>
|
|
<ColumnBackButton />
|
|
|
|
<ScrollableList
|
|
scrollKey={scrollKey}
|
|
hasMore={!forceEmptyState && list?.hasMore}
|
|
isLoading={list?.isLoading ?? true}
|
|
onLoadMore={loadMore}
|
|
prepend={header}
|
|
alwaysPrepend
|
|
append={append ?? <RemoteHint domain={domain} url={account.url} />}
|
|
emptyMessage={emptyMessage}
|
|
bindToDocument={!multiColumn}
|
|
footer={footer}
|
|
>
|
|
{children}
|
|
</ScrollableList>
|
|
</Column>
|
|
);
|
|
};
|