mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at update-sentry 157 lines 6.1 kB view raw
1import {useEffect, useMemo, useState} from 'react' 2import {QueryClient} from '@tanstack/react-query' 3import EventEmitter from 'eventemitter3' 4 5import {batchedUpdates} from '#/lib/batchedUpdates' 6import * as bsky from '#/types/bsky' 7import {findAllProfilesInQueryData as findAllProfilesInActorSearchQueryData} from '../queries/actor-search' 8import {findAllProfilesInQueryData as findAllProfilesInKnownFollowersQueryData} from '../queries/known-followers' 9import {findAllProfilesInQueryData as findAllProfilesInListMembersQueryData} from '../queries/list-members' 10import {findAllProfilesInQueryData as findAllProfilesInListConvosQueryData} from '../queries/messages/list-conversations' 11import {findAllProfilesInQueryData as findAllProfilesInMyBlockedAccountsQueryData} from '../queries/my-blocked-accounts' 12import {findAllProfilesInQueryData as findAllProfilesInMyMutedAccountsQueryData} from '../queries/my-muted-accounts' 13import {findAllProfilesInQueryData as findAllProfilesInFeedsQueryData} from '../queries/post-feed' 14import {findAllProfilesInQueryData as findAllProfilesInPostLikedByQueryData} from '../queries/post-liked-by' 15import {findAllProfilesInQueryData as findAllProfilesInPostQuotesQueryData} from '../queries/post-quotes' 16import {findAllProfilesInQueryData as findAllProfilesInPostRepostedByQueryData} from '../queries/post-reposted-by' 17import {findAllProfilesInQueryData as findAllProfilesInPostThreadQueryData} from '../queries/post-thread' 18import {findAllProfilesInQueryData as findAllProfilesInProfileQueryData} from '../queries/profile' 19import {findAllProfilesInQueryData as findAllProfilesInProfileFollowersQueryData} from '../queries/profile-followers' 20import {findAllProfilesInQueryData as findAllProfilesInProfileFollowsQueryData} from '../queries/profile-follows' 21import {findAllProfilesInQueryData as findAllProfilesInSuggestedFollowsQueryData} from '../queries/suggested-follows' 22import {castAsShadow, Shadow} from './types' 23 24export type {Shadow} from './types' 25 26export interface ProfileShadow { 27 followingUri: string | undefined 28 muted: boolean | undefined 29 blockingUri: string | undefined 30} 31 32const shadows: WeakMap< 33 bsky.profile.AnyProfileView, 34 Partial<ProfileShadow> 35> = new WeakMap() 36const emitter = new EventEmitter() 37 38export function useProfileShadow< 39 TProfileView extends bsky.profile.AnyProfileView, 40>(profile: TProfileView): Shadow<TProfileView> { 41 const [shadow, setShadow] = useState(() => shadows.get(profile)) 42 const [prevPost, setPrevPost] = useState(profile) 43 if (profile !== prevPost) { 44 setPrevPost(profile) 45 setShadow(shadows.get(profile)) 46 } 47 48 useEffect(() => { 49 function onUpdate() { 50 setShadow(shadows.get(profile)) 51 } 52 emitter.addListener(profile.did, onUpdate) 53 return () => { 54 emitter.removeListener(profile.did, onUpdate) 55 } 56 }, [profile]) 57 58 return useMemo(() => { 59 if (shadow) { 60 return mergeShadow(profile, shadow) 61 } else { 62 return castAsShadow(profile) 63 } 64 }, [profile, shadow]) 65} 66 67/** 68 * Same as useProfileShadow, but allows for the profile to be undefined. 69 * This is useful for when the profile is not guaranteed to be loaded yet. 70 */ 71export function useMaybeProfileShadow< 72 TProfileView extends bsky.profile.AnyProfileView, 73>(profile?: TProfileView): Shadow<TProfileView> | undefined { 74 const [shadow, setShadow] = useState(() => 75 profile ? shadows.get(profile) : undefined, 76 ) 77 const [prevPost, setPrevPost] = useState(profile) 78 if (profile !== prevPost) { 79 setPrevPost(profile) 80 setShadow(profile ? shadows.get(profile) : undefined) 81 } 82 83 useEffect(() => { 84 if (!profile) return 85 function onUpdate() { 86 if (!profile) return 87 setShadow(shadows.get(profile)) 88 } 89 emitter.addListener(profile.did, onUpdate) 90 return () => { 91 emitter.removeListener(profile.did, onUpdate) 92 } 93 }, [profile]) 94 95 return useMemo(() => { 96 if (!profile) return undefined 97 if (shadow) { 98 return mergeShadow(profile, shadow) 99 } else { 100 return castAsShadow(profile) 101 } 102 }, [profile, shadow]) 103} 104 105export function updateProfileShadow( 106 queryClient: QueryClient, 107 did: string, 108 value: Partial<ProfileShadow>, 109) { 110 const cachedProfiles = findProfilesInCache(queryClient, did) 111 for (let post of cachedProfiles) { 112 shadows.set(post, {...shadows.get(post), ...value}) 113 } 114 batchedUpdates(() => { 115 emitter.emit(did, value) 116 }) 117} 118 119function mergeShadow<TProfileView extends bsky.profile.AnyProfileView>( 120 profile: TProfileView, 121 shadow: Partial<ProfileShadow>, 122): Shadow<TProfileView> { 123 return castAsShadow({ 124 ...profile, 125 viewer: { 126 ...(profile.viewer || {}), 127 following: 128 'followingUri' in shadow 129 ? shadow.followingUri 130 : profile.viewer?.following, 131 muted: 'muted' in shadow ? shadow.muted : profile.viewer?.muted, 132 blocking: 133 'blockingUri' in shadow ? shadow.blockingUri : profile.viewer?.blocking, 134 }, 135 }) 136} 137 138function* findProfilesInCache( 139 queryClient: QueryClient, 140 did: string, 141): Generator<bsky.profile.AnyProfileView, void> { 142 yield* findAllProfilesInListMembersQueryData(queryClient, did) 143 yield* findAllProfilesInMyBlockedAccountsQueryData(queryClient, did) 144 yield* findAllProfilesInMyMutedAccountsQueryData(queryClient, did) 145 yield* findAllProfilesInPostLikedByQueryData(queryClient, did) 146 yield* findAllProfilesInPostRepostedByQueryData(queryClient, did) 147 yield* findAllProfilesInPostQuotesQueryData(queryClient, did) 148 yield* findAllProfilesInProfileQueryData(queryClient, did) 149 yield* findAllProfilesInProfileFollowersQueryData(queryClient, did) 150 yield* findAllProfilesInProfileFollowsQueryData(queryClient, did) 151 yield* findAllProfilesInSuggestedFollowsQueryData(queryClient, did) 152 yield* findAllProfilesInActorSearchQueryData(queryClient, did) 153 yield* findAllProfilesInListConvosQueryData(queryClient, did) 154 yield* findAllProfilesInFeedsQueryData(queryClient, did) 155 yield* findAllProfilesInPostThreadQueryData(queryClient, did) 156 yield* findAllProfilesInKnownFollowersQueryData(queryClient, did) 157}