sforkowany z mirror/soapbox
Improve error handling for Groups Discover page
rodzic
e7b3af5260
commit
287fda6d6c
|
@ -1,4 +1,5 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import { Carousel, Stack, Text } from 'soapbox/components/ui';
|
import { Carousel, Stack, Text } from 'soapbox/components/ui';
|
||||||
import PlaceholderGroupDiscover from 'soapbox/features/placeholder/components/placeholder-group-discover';
|
import PlaceholderGroupDiscover from 'soapbox/features/placeholder/components/placeholder-group-discover';
|
||||||
|
@ -7,46 +8,59 @@ import { usePopularGroups } from 'soapbox/queries/groups';
|
||||||
import Group from './group';
|
import Group from './group';
|
||||||
|
|
||||||
const PopularGroups = () => {
|
const PopularGroups = () => {
|
||||||
const { groups, isFetching } = usePopularGroups();
|
const { groups, isFetching, isFetched, isError } = usePopularGroups();
|
||||||
|
const isEmpty = (isFetched && groups.length === 0) || isError;
|
||||||
|
|
||||||
const [groupCover, setGroupCover] = useState<HTMLDivElement | null>(null);
|
const [groupCover, setGroupCover] = useState<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack space={4}>
|
<Stack space={4}>
|
||||||
<Text size='xl' weight='bold'>
|
<Text size='xl' weight='bold'>
|
||||||
Popular Groups
|
<FormattedMessage
|
||||||
|
id='groups.discover.popular.title'
|
||||||
|
defaultMessage='Popular Groups'
|
||||||
|
/>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Carousel
|
{isEmpty ? (
|
||||||
itemWidth={250}
|
<Text theme='muted'>
|
||||||
itemCount={groups.length}
|
<FormattedMessage
|
||||||
controlsHeight={groupCover?.clientHeight}
|
id='groups.discover.popular.empty'
|
||||||
>
|
defaultMessage='Unable to fetch popular groups at this time. Please check back later.'
|
||||||
{({ width }: { width: number }) => (
|
/>
|
||||||
<>
|
</Text>
|
||||||
{isFetching ? (
|
) : (
|
||||||
new Array(20).fill(0).map((_, idx) => (
|
<Carousel
|
||||||
<div
|
itemWidth={250}
|
||||||
className='relative flex shrink-0 flex-col space-y-2 px-0.5'
|
itemCount={groups.length}
|
||||||
style={{ width: width || 'auto' }}
|
controlsHeight={groupCover?.clientHeight}
|
||||||
key={idx}
|
>
|
||||||
>
|
{({ width }: { width: number }) => (
|
||||||
<PlaceholderGroupDiscover />
|
<>
|
||||||
</div>
|
{isFetching ? (
|
||||||
))
|
new Array(20).fill(0).map((_, idx) => (
|
||||||
) : (
|
<div
|
||||||
groups.map((group) => (
|
className='relative flex shrink-0 flex-col space-y-2 px-0.5'
|
||||||
<Group
|
style={{ width: width || 'auto' }}
|
||||||
key={group.id}
|
key={idx}
|
||||||
group={group}
|
>
|
||||||
width={width}
|
<PlaceholderGroupDiscover />
|
||||||
ref={setGroupCover}
|
</div>
|
||||||
/>
|
))
|
||||||
))
|
) : (
|
||||||
)}
|
groups.map((group) => (
|
||||||
</>
|
<Group
|
||||||
)}
|
key={group.id}
|
||||||
</Carousel>
|
group={group}
|
||||||
|
width={width}
|
||||||
|
ref={setGroupCover}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Carousel>
|
||||||
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { Stack, Text } from 'soapbox/components/ui';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
title: React.ReactNode | string
|
||||||
|
subtitle: React.ReactNode | string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ({ title, subtitle }: Props) => (
|
||||||
|
<Stack space={2} className='px-4 py-2' data-testid='no-results'>
|
||||||
|
<Text weight='bold' size='lg'>
|
||||||
|
{title}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text theme='muted'>
|
||||||
|
{subtitle}
|
||||||
|
</Text>
|
||||||
|
</Stack>
|
||||||
|
);
|
|
@ -1,22 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
|
||||||
|
|
||||||
import { Stack, Text } from 'soapbox/components/ui';
|
|
||||||
|
|
||||||
export default () => (
|
|
||||||
<Stack space={2} className='px-4 py-2' data-testid='no-results'>
|
|
||||||
<Text weight='bold' size='lg'>
|
|
||||||
<FormattedMessage
|
|
||||||
id='groups.discover.search.no_results.title'
|
|
||||||
defaultMessage='No matches found'
|
|
||||||
/>
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Text theme='muted'>
|
|
||||||
<FormattedMessage
|
|
||||||
id='groups.discover.search.no_results.subtitle'
|
|
||||||
defaultMessage='Try searching for another group.'
|
|
||||||
/>
|
|
||||||
</Text>
|
|
||||||
</Stack>
|
|
||||||
);
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import { Stack } from 'soapbox/components/ui';
|
import { Stack } from 'soapbox/components/ui';
|
||||||
import PlaceholderGroupSearch from 'soapbox/features/placeholder/components/placeholder-group-search';
|
import PlaceholderGroupSearch from 'soapbox/features/placeholder/components/placeholder-group-search';
|
||||||
|
@ -6,7 +7,7 @@ import { useDebounce, useOwnAccount } from 'soapbox/hooks';
|
||||||
import { useGroupSearch } from 'soapbox/queries/groups/search';
|
import { useGroupSearch } from 'soapbox/queries/groups/search';
|
||||||
import { saveGroupSearch } from 'soapbox/utils/groups';
|
import { saveGroupSearch } from 'soapbox/utils/groups';
|
||||||
|
|
||||||
import NoResultsBlankslate from './no-results-blankslate';
|
import Blankslate from './blankslate';
|
||||||
import RecentSearches from './recent-searches';
|
import RecentSearches from './recent-searches';
|
||||||
import Results from './results';
|
import Results from './results';
|
||||||
|
|
||||||
|
@ -25,7 +26,7 @@ export default (props: Props) => {
|
||||||
const debouncedValueToSave = debounce(searchValue as string, 1000);
|
const debouncedValueToSave = debounce(searchValue as string, 1000);
|
||||||
|
|
||||||
const groupSearchResult = useGroupSearch(debouncedValue);
|
const groupSearchResult = useGroupSearch(debouncedValue);
|
||||||
const { groups, isFetching, isFetched } = groupSearchResult;
|
const { groups, isFetching, isFetched, isError } = groupSearchResult;
|
||||||
|
|
||||||
const hasSearchResults = isFetched && groups.length > 0;
|
const hasSearchResults = isFetched && groups.length > 0;
|
||||||
const hasNoSearchResults = isFetched && groups.length === 0;
|
const hasNoSearchResults = isFetched && groups.length === 0;
|
||||||
|
@ -46,8 +47,42 @@ export default (props: Props) => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isError) {
|
||||||
|
return (
|
||||||
|
<Blankslate
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='groups.discover.search.error.title'
|
||||||
|
defaultMessage='An error occurred'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
subtitle={
|
||||||
|
<FormattedMessage
|
||||||
|
id='groups.discover.search.error.subtitle'
|
||||||
|
defaultMessage='Please try again later.'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (hasNoSearchResults) {
|
if (hasNoSearchResults) {
|
||||||
return <NoResultsBlankslate />;
|
return (
|
||||||
|
<Blankslate
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='groups.discover.search.no_results.title'
|
||||||
|
defaultMessage='No matches found'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
subtitle={
|
||||||
|
<FormattedMessage
|
||||||
|
id='groups.discover.search.no_results.subtitle'
|
||||||
|
defaultMessage='Try searching for another group.'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasSearchResults) {
|
if (hasSearchResults) {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import { Carousel, Stack, Text } from 'soapbox/components/ui';
|
import { Carousel, Stack, Text } from 'soapbox/components/ui';
|
||||||
import PlaceholderGroupDiscover from 'soapbox/features/placeholder/components/placeholder-group-discover';
|
import PlaceholderGroupDiscover from 'soapbox/features/placeholder/components/placeholder-group-discover';
|
||||||
|
@ -7,46 +8,59 @@ import { useSuggestedGroups } from 'soapbox/queries/groups';
|
||||||
import Group from './group';
|
import Group from './group';
|
||||||
|
|
||||||
const SuggestedGroups = () => {
|
const SuggestedGroups = () => {
|
||||||
const { groups, isFetching } = useSuggestedGroups();
|
const { groups, isFetching, isFetched, isError } = useSuggestedGroups();
|
||||||
|
const isEmpty = (isFetched && groups.length === 0) || isError;
|
||||||
|
|
||||||
const [groupCover, setGroupCover] = useState<HTMLDivElement | null>(null);
|
const [groupCover, setGroupCover] = useState<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack space={4}>
|
<Stack space={4}>
|
||||||
<Text size='xl' weight='bold'>
|
<Text size='xl' weight='bold'>
|
||||||
Suggested For You
|
<FormattedMessage
|
||||||
|
id='groups.discover.suggested.title'
|
||||||
|
defaultMessage='Suggested For You'
|
||||||
|
/>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Carousel
|
{isEmpty ? (
|
||||||
itemWidth={250}
|
<Text theme='muted'>
|
||||||
itemCount={groups.length}
|
<FormattedMessage
|
||||||
controlsHeight={groupCover?.clientHeight}
|
id='groups.discover.suggested.empty'
|
||||||
>
|
defaultMessage='Unable to fetch suggested groups at this time. Please check back later.'
|
||||||
{({ width }: { width: number }) => (
|
/>
|
||||||
<>
|
</Text>
|
||||||
{isFetching ? (
|
) : (
|
||||||
new Array(20).fill(0).map((_, idx) => (
|
<Carousel
|
||||||
<div
|
itemWidth={250}
|
||||||
className='relative flex shrink-0 flex-col space-y-2 px-0.5'
|
itemCount={groups.length}
|
||||||
style={{ width: width || 'auto' }}
|
controlsHeight={groupCover?.clientHeight}
|
||||||
key={idx}
|
>
|
||||||
>
|
{({ width }: { width: number }) => (
|
||||||
<PlaceholderGroupDiscover />
|
<>
|
||||||
</div>
|
{isFetching ? (
|
||||||
))
|
new Array(20).fill(0).map((_, idx) => (
|
||||||
) : (
|
<div
|
||||||
groups.map((group) => (
|
className='relative flex shrink-0 flex-col space-y-2 px-0.5'
|
||||||
<Group
|
style={{ width: width || 'auto' }}
|
||||||
key={group.id}
|
key={idx}
|
||||||
group={group}
|
>
|
||||||
width={width}
|
<PlaceholderGroupDiscover />
|
||||||
ref={setGroupCover}
|
</div>
|
||||||
/>
|
))
|
||||||
))
|
) : (
|
||||||
)}
|
groups.map((group) => (
|
||||||
</>
|
<Group
|
||||||
)}
|
key={group.id}
|
||||||
</Carousel>
|
group={group}
|
||||||
|
width={width}
|
||||||
|
ref={setGroupCover}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Carousel>
|
||||||
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -803,6 +803,8 @@
|
||||||
"group.user_subheading": "Users",
|
"group.user_subheading": "Users",
|
||||||
"groups.discover.search.no_results.subtitle": "Try searching for another group.",
|
"groups.discover.search.no_results.subtitle": "Try searching for another group.",
|
||||||
"groups.discover.search.no_results.title": "No matches found",
|
"groups.discover.search.no_results.title": "No matches found",
|
||||||
|
"groups.discover.search.error.subtitle": "Please try again later.",
|
||||||
|
"groups.discover.search.error.title": "An error occurred",
|
||||||
"groups.discover.search.placeholder": "Search",
|
"groups.discover.search.placeholder": "Search",
|
||||||
"groups.discover.search.recent_searches.blankslate.subtitle": "Search group names, topics or keywords",
|
"groups.discover.search.recent_searches.blankslate.subtitle": "Search group names, topics or keywords",
|
||||||
"groups.discover.search.recent_searches.blankslate.title": "No recent searches",
|
"groups.discover.search.recent_searches.blankslate.title": "No recent searches",
|
||||||
|
@ -810,6 +812,10 @@
|
||||||
"groups.discover.search.recent_searches.title": "Recent searches",
|
"groups.discover.search.recent_searches.title": "Recent searches",
|
||||||
"groups.discover.search.results.groups": "Groups",
|
"groups.discover.search.results.groups": "Groups",
|
||||||
"groups.discover.search.results.member_count": "{members, plural, one {member} other {members}}",
|
"groups.discover.search.results.member_count": "{members, plural, one {member} other {members}}",
|
||||||
|
"groups.discover.popular.title": "Popular Groups",
|
||||||
|
"groups.discover.popular.empty": "Unable to fetch popular groups at this time. Please check back later.",
|
||||||
|
"groups.discover.suggested.title": "Suggested For You",
|
||||||
|
"groups.discover.suggested.empty": "Unable to fetch suggested groups at this time. Please check back later.",
|
||||||
"groups.empty.subtitle": "Start discovering groups to join or create your own.",
|
"groups.empty.subtitle": "Start discovering groups to join or create your own.",
|
||||||
"groups.empty.title": "No Groups yet",
|
"groups.empty.title": "No Groups yet",
|
||||||
"hashtag.column_header.tag_mode.all": "and {additional}",
|
"hashtag.column_header.tag_mode.all": "and {additional}",
|
||||||
|
|
Ładowanie…
Reference in New Issue