Refactor ChatSearch and add various states
This commit is contained in:
parent
0952fe6dae
commit
0ae515ef18
|
@ -15,7 +15,7 @@ import useAccountSearch from 'soapbox/queries/search';
|
|||
|
||||
import ChatList from '../chat-list';
|
||||
import ChatPaneHeader from '../chat-pane-header';
|
||||
import ChatSearch from '../chat-search';
|
||||
import ChatSearch from '../chat-search/chat-search';
|
||||
import ChatWindow from '../chat-window';
|
||||
import { Pane } from '../ui';
|
||||
|
||||
|
@ -44,10 +44,11 @@ const ChatPane = () => {
|
|||
const unreadCount = sumBy(chats, (chat) => chat.unread);
|
||||
|
||||
const hasSearchValue = Number(value?.length) > 0;
|
||||
console.log('hasSearchValue', hasSearchValue);
|
||||
|
||||
|
||||
const handleClickChat = (chat: IChat) => setChat(chat);
|
||||
const handleClickChat = (chat: IChat) => {
|
||||
setChat(chat);
|
||||
setValue(undefined);
|
||||
};
|
||||
|
||||
const clearValue = () => {
|
||||
if (hasSearchValue) {
|
||||
|
@ -133,7 +134,10 @@ const ChatPane = () => {
|
|||
unreadCount={unreadCount}
|
||||
isOpen={isOpen}
|
||||
onToggle={toggleChatPane}
|
||||
secondaryAction={() => setSearching(true)}
|
||||
secondaryAction={() => {
|
||||
setSearching(true);
|
||||
setValue(undefined);
|
||||
}}
|
||||
secondaryActionIcon={require('@tabler/icons/edit.svg')}
|
||||
/>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import React from 'react';
|
|||
import { __stub } from 'soapbox/api';
|
||||
import { ChatProvider } from 'soapbox/contexts/chat-context';
|
||||
|
||||
import { render, screen, waitFor } from '../../../../jest/test-helpers';
|
||||
import { render, screen, waitFor } from '../../../../../jest/test-helpers';
|
||||
import ChatSearch from '../chat-search';
|
||||
|
||||
const renderComponent = () => render(
|
||||
|
@ -28,7 +28,7 @@ describe('<ChatSearch />', () => {
|
|||
});
|
||||
|
||||
describe('when the pane is open', () => {
|
||||
beforeEach(async() => {
|
||||
beforeEach(async () => {
|
||||
renderComponent();
|
||||
await userEvent.click(screen.getByTestId('icon-button'));
|
||||
});
|
||||
|
@ -50,7 +50,7 @@ describe('<ChatSearch />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('renders accounts', async() => {
|
||||
it('renders accounts', async () => {
|
||||
renderComponent();
|
||||
|
||||
const user = userEvent.setup();
|
|
@ -0,0 +1,14 @@
|
|||
import React from 'react';
|
||||
|
||||
import { Stack, Text } from 'soapbox/components/ui';
|
||||
|
||||
const Blankslate = () => (
|
||||
<Stack justifyContent='center' alignItems='center' space={2} className='h-full w-2/3 mx-auto'>
|
||||
<Text weight='bold' size='lg' align='center'>Search followers</Text>
|
||||
<Text theme='muted' align='center'>
|
||||
You can start a conversation with anyone that follows you.
|
||||
</Text>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
export default Blankslate;
|
|
@ -3,16 +3,19 @@ import { AxiosError } from 'axios';
|
|||
import React, { useState } from 'react';
|
||||
|
||||
import snackbar from 'soapbox/actions/snackbar';
|
||||
import { Avatar, HStack, Icon, Input, Stack, Text } from 'soapbox/components/ui';
|
||||
import VerificationBadge from 'soapbox/components/verification_badge';
|
||||
import { HStack, Icon, Input, Stack, Text } from 'soapbox/components/ui';
|
||||
import { useChatContext } from 'soapbox/contexts/chat-context';
|
||||
import { useAppDispatch, useDebounce } from 'soapbox/hooks';
|
||||
import { useChats } from 'soapbox/queries/chats';
|
||||
import { queryClient } from 'soapbox/queries/client';
|
||||
import useAccountSearch from 'soapbox/queries/search';
|
||||
|
||||
import ChatPaneHeader from './chat-pane-header';
|
||||
import { Pane } from './ui';
|
||||
import ChatPaneHeader from '../chat-pane-header';
|
||||
import { Pane } from '../ui';
|
||||
|
||||
import Blankslate from './blankslate';
|
||||
import EmptyResultsBlankslate from './empty-results-blankslate';
|
||||
import Results from './results';
|
||||
|
||||
const ChatSearch = () => {
|
||||
const debounce = useDebounce;
|
||||
|
@ -24,9 +27,10 @@ const ChatSearch = () => {
|
|||
const [value, setValue] = useState<string>();
|
||||
const debouncedValue = debounce(value as string, 300);
|
||||
|
||||
const { data: accounts } = useAccountSearch(debouncedValue);
|
||||
const { data: accounts, isFetching } = useAccountSearch(debouncedValue);
|
||||
|
||||
const hasSearchValue = value && value.length > 0;
|
||||
const hasSearchValue = debouncedValue && debouncedValue.length > 0;
|
||||
const hasSearchResults = (accounts || []).length > 0;
|
||||
|
||||
const handleClickOnSearchResult = useMutation((accountId: string) => {
|
||||
return getOrCreateChatByAccountId(accountId);
|
||||
|
@ -41,6 +45,24 @@ const ChatSearch = () => {
|
|||
},
|
||||
});
|
||||
|
||||
const renderBody = () => {
|
||||
if (hasSearchResults) {
|
||||
return (
|
||||
<Results
|
||||
accounts={accounts}
|
||||
onSelect={(id) => {
|
||||
handleClickOnSearchResult.mutate(id);
|
||||
clearValue();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else if (hasSearchValue && !hasSearchResults && !isFetching) {
|
||||
return <EmptyResultsBlankslate />;
|
||||
} else {
|
||||
return <Blankslate />;
|
||||
}
|
||||
};
|
||||
|
||||
const clearValue = () => {
|
||||
if (hasSearchValue) {
|
||||
setValue('');
|
||||
|
@ -93,30 +115,7 @@ const ChatSearch = () => {
|
|||
</div>
|
||||
|
||||
<Stack className='overflow-y-scroll flex-grow h-full' space={2}>
|
||||
{(accounts || []).map((account: any) => (
|
||||
<button
|
||||
key={account.id}
|
||||
type='button'
|
||||
className='px-4 py-2 w-full flex flex-col hover:bg-gray-100 dark:hover:bg-gray-800'
|
||||
onClick={() => {
|
||||
handleClickOnSearchResult.mutate(account.id);
|
||||
clearValue();
|
||||
}}
|
||||
data-testid='account'
|
||||
>
|
||||
<HStack alignItems='center' space={2}>
|
||||
<Avatar src={account.avatar} size={40} />
|
||||
|
||||
<Stack alignItems='start'>
|
||||
<div className='flex items-center space-x-1 flex-grow'>
|
||||
<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>
|
||||
))}
|
||||
{renderBody()}
|
||||
</Stack>
|
||||
</Stack>
|
||||
) : null}
|
|
@ -0,0 +1,14 @@
|
|||
import React from 'react';
|
||||
|
||||
import { Stack, Text } from 'soapbox/components/ui';
|
||||
|
||||
const EmptyResultsBlankslate = () => (
|
||||
<Stack justifyContent='center' alignItems='center' space={2} className='h-full w-2/3 mx-auto'>
|
||||
<Text weight='bold' size='lg' align='center'>No matches found</Text>
|
||||
<Text theme='muted' align='center'>
|
||||
Try searching for another name.
|
||||
</Text>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
export default EmptyResultsBlankslate;
|
|
@ -0,0 +1,43 @@
|
|||
import React from 'react';
|
||||
|
||||
import { Avatar, HStack, Stack, Text } from 'soapbox/components/ui';
|
||||
import VerificationBadge from 'soapbox/components/verification_badge';
|
||||
|
||||
interface IResults {
|
||||
accounts: {
|
||||
display_name: string
|
||||
acct: string
|
||||
id: string
|
||||
avatar: string
|
||||
verified: boolean
|
||||
}[]
|
||||
onSelect(id: string): void
|
||||
}
|
||||
|
||||
const Results = ({ accounts, onSelect }: IResults) => (
|
||||
<>
|
||||
{(accounts || []).map((account: any) => (
|
||||
<button
|
||||
key={account.id}
|
||||
type='button'
|
||||
className='px-4 py-2 w-full flex flex-col hover:bg-gray-100 dark:hover:bg-gray-800'
|
||||
onClick={() => onSelect(account.id)}
|
||||
data-testid='account'
|
||||
>
|
||||
<HStack alignItems='center' space={2}>
|
||||
<Avatar src={account.avatar} size={40} />
|
||||
|
||||
<Stack alignItems='start'>
|
||||
<div className='flex items-center space-x-1 flex-grow'>
|
||||
<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>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
||||
export default Results;
|
Loading…
Reference in New Issue