@@ -13,7 +13,10 @@ import {findAllProfilesInQueryData as findAllProfilesInListConvosQueryData} from
1313import { findAllProfilesInQueryData as findAllProfilesInMyBlockedAccountsQueryData } from '#/state/queries/my-blocked-accounts'
1414import { findAllProfilesInQueryData as findAllProfilesInMyMutedAccountsQueryData } from '#/state/queries/my-muted-accounts'
1515import { findAllProfilesInQueryData as findAllProfilesInNotifsQueryData } from '#/state/queries/notifications/feed'
16- import { findAllProfilesInQueryData as findAllProfilesInFeedsQueryData } from '#/state/queries/post-feed'
16+ import {
17+ type FeedPage ,
18+ findAllProfilesInQueryData as findAllProfilesInFeedsQueryData ,
19+ } from '#/state/queries/post-feed'
1720import { findAllProfilesInQueryData as findAllProfilesInPostLikedByQueryData } from '#/state/queries/post-liked-by'
1821import { findAllProfilesInQueryData as findAllProfilesInPostQuotesQueryData } from '#/state/queries/post-quotes'
1922import { findAllProfilesInQueryData as findAllProfilesInPostRepostedByQueryData } from '#/state/queries/post-reposted-by'
@@ -110,6 +113,81 @@ export function useMaybeProfileShadow<
110113 } , [ profile , shadow ] )
111114}
112115
116+ /**
117+ * Takes a list of posts, and returns a list of DIDs that should be filtered out
118+ *
119+ * Note: it doesn't retroactively scan the cache, but only listens to new updates.
120+ * The use case here is intended for removing a post from a feed after you mute the author
121+ */
122+ export function usePostAuthorShadowFilter ( data ?: FeedPage [ ] ) {
123+ const [ trackedDids , setTrackedDids ] = useState < string [ ] > (
124+ ( ) =>
125+ data ?. flatMap ( page =>
126+ page . slices . flatMap ( slice =>
127+ slice . items . map ( item => item . post . author . did ) ,
128+ ) ,
129+ ) ?? [ ] ,
130+ )
131+ const [ authors , setAuthors ] = useState (
132+ new Map < string , { muted : boolean ; blocked : boolean } > ( ) ,
133+ )
134+
135+ const [ prevData , setPrevData ] = useState ( data )
136+ if ( data !== prevData ) {
137+ const newAuthors = new Set ( trackedDids )
138+ let hasNew = false
139+ for ( const slice of data ?. flatMap ( page => page . slices ) ?? [ ] ) {
140+ for ( const item of slice . items ) {
141+ const author = item . post . author
142+ if ( ! newAuthors . has ( author . did ) ) {
143+ hasNew = true
144+ newAuthors . add ( author . did )
145+ }
146+ }
147+ }
148+ if ( hasNew ) setTrackedDids ( [ ...newAuthors ] )
149+ setPrevData ( data )
150+ }
151+
152+ useEffect ( ( ) => {
153+ const unsubs : Array < ( ) => void > = [ ]
154+
155+ for ( const did of trackedDids ) {
156+ function onUpdate ( value : Partial < ProfileShadow > ) {
157+ setAuthors ( prev => {
158+ const prevValue = prev . get ( did )
159+ const next = new Map ( prev )
160+ next . set ( did , {
161+ blocked : Boolean ( value . blockingUri ?? prevValue ?. blocked ?? false ) ,
162+ muted : Boolean ( value . muted ?? prevValue ?. muted ?? false ) ,
163+ } )
164+ return next
165+ } )
166+ }
167+ emitter . addListener ( did , onUpdate )
168+ unsubs . push ( ( ) => {
169+ emitter . removeListener ( did , onUpdate )
170+ } )
171+ }
172+
173+ return ( ) => {
174+ unsubs . map ( fn => fn ( ) )
175+ }
176+ } , [ trackedDids ] )
177+
178+ return useMemo ( ( ) => {
179+ const dids : Array < string > = [ ]
180+
181+ for ( const [ did , value ] of authors . entries ( ) ) {
182+ if ( value . blocked || value . muted ) {
183+ dids . push ( did )
184+ }
185+ }
186+
187+ return dids
188+ } , [ authors ] )
189+ }
190+
113191export function updateProfileShadow (
114192 queryClient : QueryClient ,
115193 did : string ,
0 commit comments