2023-02-06 10:01:03 -08:00
|
|
|
import clsx from 'clsx';
|
2022-12-08 11:37:04 -08:00
|
|
|
import React, { useCallback, useState } from 'react';
|
|
|
|
import { Virtuoso } from 'react-virtuoso';
|
2022-09-13 08:55:13 -07:00
|
|
|
|
|
|
|
import { Avatar, HStack, Stack, Text } from 'soapbox/components/ui';
|
2022-11-17 07:58:34 -08:00
|
|
|
import VerificationBadge from 'soapbox/components/verification-badge';
|
2022-12-08 11:37:04 -08:00
|
|
|
import useAccountSearch from 'soapbox/queries/search';
|
2022-09-13 08:55:13 -07:00
|
|
|
|
2023-01-10 15:03:15 -08:00
|
|
|
import type { Account } from 'soapbox/types/entities';
|
|
|
|
|
2022-09-13 08:55:13 -07:00
|
|
|
interface IResults {
|
2022-12-08 11:37:04 -08:00
|
|
|
accountSearchResult: ReturnType<typeof useAccountSearch>
|
2022-09-13 08:55:13 -07:00
|
|
|
onSelect(id: string): void
|
|
|
|
}
|
|
|
|
|
2022-12-08 11:37:04 -08:00
|
|
|
const Results = ({ accountSearchResult, onSelect }: IResults) => {
|
|
|
|
const { data: accounts, isFetching, hasNextPage, fetchNextPage } = accountSearchResult;
|
|
|
|
|
|
|
|
const [isNearBottom, setNearBottom] = useState<boolean>(false);
|
|
|
|
const [isNearTop, setNearTop] = useState<boolean>(true);
|
|
|
|
|
|
|
|
const handleLoadMore = () => {
|
|
|
|
if (hasNextPage && !isFetching) {
|
|
|
|
fetchNextPage();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-01-10 15:03:15 -08:00
|
|
|
const renderAccount = useCallback((_index: number, account: Account) => (
|
2022-12-08 11:37:04 -08:00
|
|
|
<button
|
|
|
|
key={account.id}
|
|
|
|
type='button'
|
2023-02-01 14:13:42 -08:00
|
|
|
className='flex w-full flex-col rounded-lg px-2 py-3 hover:bg-gray-100 dark:hover:bg-gray-800'
|
2022-12-08 11:37:04 -08:00
|
|
|
onClick={() => onSelect(account.id)}
|
|
|
|
data-testid='account'
|
|
|
|
>
|
|
|
|
<HStack alignItems='center' space={2}>
|
|
|
|
<Avatar src={account.avatar} size={40} />
|
|
|
|
|
|
|
|
<Stack alignItems='start'>
|
2023-02-01 14:13:42 -08:00
|
|
|
<div className='flex grow items-center space-x-1'>
|
2022-12-08 11:37:04 -08:00
|
|
|
<Text weight='bold' size='sm' truncate>{account.display_name}</Text>
|
|
|
|
{account.verified && <VerificationBadge />}
|
|
|
|
</div>
|
|
|
|
<Text size='sm' weight='medium' theme='muted' truncate>@{account.acct}</Text>
|
|
|
|
</Stack>
|
|
|
|
</HStack>
|
|
|
|
</button>
|
|
|
|
), []);
|
|
|
|
|
|
|
|
return (
|
2023-02-01 14:13:42 -08:00
|
|
|
<div className='relative grow'>
|
2022-12-08 11:37:04 -08:00
|
|
|
<Virtuoso
|
|
|
|
data={accounts}
|
|
|
|
itemContent={(index, chat) => (
|
|
|
|
<div className='px-2'>
|
|
|
|
{renderAccount(index, chat)}
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
endReached={handleLoadMore}
|
|
|
|
atTopStateChange={(atTop) => setNearTop(atTop)}
|
|
|
|
atBottomStateChange={(atBottom) => setNearBottom(atBottom)}
|
|
|
|
/>
|
|
|
|
|
|
|
|
<>
|
|
|
|
<div
|
2023-02-06 10:06:44 -08:00
|
|
|
className={clsx('pointer-events-none absolute inset-x-0 top-0 flex justify-center rounded-t-lg bg-gradient-to-b from-white to-transparent pb-12 pt-8 transition-opacity duration-500 dark:from-gray-900', {
|
2022-12-08 11:37:04 -08:00
|
|
|
'opacity-0': isNearTop,
|
|
|
|
'opacity-100': !isNearTop,
|
|
|
|
})}
|
|
|
|
/>
|
|
|
|
<div
|
2023-04-01 11:37:34 -07:00
|
|
|
className={clsx('pointer-events-none absolute inset-x-0 bottom-0 flex justify-center rounded-b-lg bg-gradient-to-t from-white to-transparent pb-8 pt-12 transition-opacity duration-500 dark:from-gray-900', {
|
2022-12-08 11:37:04 -08:00
|
|
|
'opacity-0': isNearBottom,
|
|
|
|
'opacity-100': !isNearBottom,
|
|
|
|
})}
|
|
|
|
/>
|
|
|
|
</>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default Results;
|