From dc3f01591fccaa0510f80bf8d248854b41de8fbe Mon Sep 17 00:00:00 2001 From: Spence Pope Date: Thu, 5 Feb 2026 10:36:19 -0500 Subject: [PATCH] [APP-1794] respect mute words for live event feed banners (#9831) * respect mute words for live event feed banners * linting --- src/features/liveEvents/context.tsx | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/features/liveEvents/context.tsx b/src/features/liveEvents/context.tsx index b39195539a..3de2534a8e 100644 --- a/src/features/liveEvents/context.tsx +++ b/src/features/liveEvents/context.tsx @@ -1,4 +1,5 @@ import {createContext, useContext, useMemo} from 'react' +import {hasMutedWord} from '@atproto/api' import {QueryClient, useQuery} from '@tanstack/react-query' import {useOnAppStateChange} from '#/lib/appState' @@ -8,7 +9,8 @@ import { isBskyCustomFeedUrl, makeRecordUri, } from '#/lib/strings/url-helpers' -import {LIVE_EVENTS_URL} from '#/env' +import {usePreferencesQuery} from '#/state/queries/preferences' +import {IS_DEV, LIVE_EVENTS_URL} from '#/env' import {useLiveEventPreferences} from '#/features/liveEvents/preferences' import {type LiveEventsWorkerResponse} from '#/features/liveEvents/types' import {useDevMode} from '#/storage/hooks/dev-mode' @@ -36,6 +38,12 @@ const Context = createContext(DEFAULT_LIVE_EVENTS) export function Provider({children}: React.PropsWithChildren<{}>) { const [isDevMode] = useDevMode() const isBskyTeam = useIsBskyTeam() + const {data: preferences} = usePreferencesQuery() + const mutedWords = useMemo( + () => preferences?.moderationPrefs?.mutedWords ?? [], + [preferences?.moderationPrefs?.mutedWords], + ) + const {data, refetch} = useQuery( { // keep this, prefectching handles initial load @@ -50,13 +58,24 @@ export function Provider({children}: React.PropsWithChildren<{}>) { ) useOnAppStateChange(state => { - if (state === 'active') refetch() + if (state === 'active') void refetch() }) const ctx = useMemo(() => { if (!data) return DEFAULT_LIVE_EVENTS + const skipMuteFilter = isBskyTeam || IS_DEV const feeds = data.feeds.filter(f => { if (f.preview && !isBskyTeam) return false + if (!skipMuteFilter && mutedWords.length > 0) { + const text = [ + f.title, + f.layouts?.wide?.title, + f.layouts?.compact?.title, + ] + .filter(Boolean) + .join(' ') + if (hasMutedWord({mutedWords, text})) return false + } return true }) return { @@ -64,7 +83,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) { // only one at a time for now, unless bsky team and dev mode feeds: isBskyTeam && isDevMode ? feeds : feeds.slice(0, 1), } - }, [data, isBskyTeam, isDevMode]) + }, [data, isBskyTeam, isDevMode, mutedWords]) return {children} }