diff --git a/src/webapp/features/feeds/components/feedControls/FeedControls.tsx b/src/webapp/features/feeds/components/feedControls/FeedControls.tsx index 2be1e62f..8cb72c1b 100644 --- a/src/webapp/features/feeds/components/feedControls/FeedControls.tsx +++ b/src/webapp/features/feeds/components/feedControls/FeedControls.tsx @@ -37,6 +37,11 @@ const feedOptions = [ { value: 'following' as const, label: 'Following' }, ]; +const botFilterOptions = [ + { value: false, label: 'Hide bots' }, + { value: true, label: 'Include bots' }, +]; + const activityTypeOptions = [ { value: ActivityType.CARD_COLLECTED, @@ -66,6 +71,8 @@ export default function FeedControls() { .getAll('activityTypes') .map(paramToActivityType) .filter((t): t is ActivityType => t !== undefined); + const includeKnownBotsFromUrl = + searchParams.get('includeKnownBots') === 'true'; const [optimisticSource, setOptimisticSource] = useOptimistic(sourceFromUrl); @@ -77,6 +84,8 @@ export default function FeedControls() { ); const [optimisticActivityTypes, setOptimisticActivityTypes] = useOptimistic(activityTypesFromUrl); + const [optimisticIncludeKnownBots, setOptimisticIncludeKnownBots] = + useOptimistic(includeKnownBotsFromUrl); const [typePopoverOpened, setTypePopoverOpened] = useState(false); @@ -160,11 +169,27 @@ export default function FeedControls() { }); }; + const handleBotFilterClick = (includeKnownBots: boolean) => { + startTransition(() => { + setOptimisticIncludeKnownBots(includeKnownBots); + + const params = new URLSearchParams(searchParams.toString()); + if (includeKnownBots) { + params.set('includeKnownBots', 'true'); + } else { + params.delete('includeKnownBots'); + } + + router.push(`?${params.toString()}`, { scroll: false }); + }); + }; + const hasActiveFilters = optimisticSource !== null || optimisticFeed !== 'global' || optimisticType !== null || - optimisticActivityTypes.length > 0; + optimisticActivityTypes.length > 0 || + optimisticIncludeKnownBots !== false; const handleClear = () => { startTransition(() => { @@ -172,6 +197,7 @@ export default function FeedControls() { setOptimisticFeed('global'); setOptimisticType(null); setOptimisticActivityTypes([]); + setOptimisticIncludeKnownBots(false); router.push('?', { scroll: false }); }); @@ -228,6 +254,24 @@ export default function FeedControls() { ))} + <> + Accounts + {botFilterOptions.map((option) => ( + handleBotFilterClick(option.value)} + rightSection={ + option.value === optimisticIncludeKnownBots ? ( + + ) : null + } + closeMenuOnClick={false} + > + {option.label} + + ))} + + Card Type { @@ -19,6 +20,7 @@ export const getGlobalFeed = cache(async (params?: PageParams) => { urlType: params?.urlType, source: params?.source, activityTypes: params?.activityTypes, + includeKnownBots: params?.includeKnownBots, }); return response; @@ -48,6 +50,7 @@ export const getFollowingFeed = cache(async (params?: PageParams) => { urlType: params?.urlType, source: params?.source, activityTypes: params?.activityTypes, + includeKnownBots: params?.includeKnownBots, }); return response; diff --git a/src/webapp/features/feeds/lib/feedKeys.ts b/src/webapp/features/feeds/lib/feedKeys.ts index aa90b84b..12a683b9 100644 --- a/src/webapp/features/feeds/lib/feedKeys.ts +++ b/src/webapp/features/feeds/lib/feedKeys.ts @@ -7,13 +7,23 @@ export const feedKeys = { urlType?: UrlType, source?: ActivitySource, activityTypes?: ActivityType[], - ) => [...feedKeys.all(), 'infinite', limit, urlType, source, activityTypes], + includeKnownBots?: boolean, + ) => [ + ...feedKeys.all(), + 'infinite', + limit, + urlType, + source, + activityTypes, + includeKnownBots, + ], gems: () => [...feedKeys.all(), 'gems'] as const, gemsInfinite: ( limit?: number, urlType?: UrlType, source?: ActivitySource, activityTypes?: ActivityType[], + includeKnownBots?: boolean, ) => [ ...feedKeys.gems(), [...feedKeys.infinite()], @@ -21,6 +31,7 @@ export const feedKeys = { limit, source, activityTypes, + includeKnownBots, ], following: () => [...feedKeys.all(), 'following'] as const, followingInfinite: ( @@ -28,6 +39,7 @@ export const feedKeys = { urlType?: UrlType, source?: ActivitySource, activityTypes?: ActivityType[], + includeKnownBots?: boolean, ) => [ ...feedKeys.following(), @@ -36,5 +48,6 @@ export const feedKeys = { urlType, source, activityTypes, + includeKnownBots, ] as const, }; diff --git a/src/webapp/features/feeds/lib/queries/useFollowingFeed.tsx b/src/webapp/features/feeds/lib/queries/useFollowingFeed.tsx index fdfd42a7..58161960 100644 --- a/src/webapp/features/feeds/lib/queries/useFollowingFeed.tsx +++ b/src/webapp/features/feeds/lib/queries/useFollowingFeed.tsx @@ -8,6 +8,7 @@ interface Props { urlType?: UrlType; source?: ActivitySource; activityTypes?: ActivityType[]; + includeKnownBots?: boolean; enabled?: boolean; } @@ -21,6 +22,7 @@ export default function useFollowingFeed(props?: Props) { props?.urlType, props?.source, props?.activityTypes, + props?.includeKnownBots, ), staleTime: 10000, initialPageParam: 1, @@ -33,6 +35,7 @@ export default function useFollowingFeed(props?: Props) { urlType: props?.urlType, source: props?.source, activityTypes: props?.activityTypes, + includeKnownBots: props?.includeKnownBots, }); }, getNextPageParam: (lastPage) => { diff --git a/src/webapp/features/feeds/lib/queries/useGlobalFeed.tsx b/src/webapp/features/feeds/lib/queries/useGlobalFeed.tsx index 27f6321e..5396b479 100644 --- a/src/webapp/features/feeds/lib/queries/useGlobalFeed.tsx +++ b/src/webapp/features/feeds/lib/queries/useGlobalFeed.tsx @@ -8,6 +8,7 @@ interface Props { urlType?: UrlType; source?: ActivitySource; activityTypes?: ActivityType[]; + includeKnownBots?: boolean; } export default function useGlobalFeed(props?: Props) { @@ -19,6 +20,7 @@ export default function useGlobalFeed(props?: Props) { props?.urlType, props?.source, props?.activityTypes, + props?.includeKnownBots, ), staleTime: 10000, initialPageParam: 1, @@ -30,6 +32,7 @@ export default function useGlobalFeed(props?: Props) { urlType: props?.urlType, source: props?.source, activityTypes: props?.activityTypes, + includeKnownBots: props?.includeKnownBots, }); }, getNextPageParam: (lastPage) => {