mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import {useEffect, useMemo, useState} from 'react'
2import {AppBskyActorDefs} from '@atproto/api'
3import {QueryClient} from '@tanstack/react-query'
4import EventEmitter from 'eventemitter3'
5
6import {batchedUpdates} from '#/lib/batchedUpdates'
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-converations'
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 findAllProfilesInPostRepostedByQueryData} from '../queries/post-reposted-by'
16import {findAllProfilesInQueryData as findAllProfilesInPostThreadQueryData} from '../queries/post-thread'
17import {findAllProfilesInQueryData as findAllProfilesInProfileQueryData} from '../queries/profile'
18import {findAllProfilesInQueryData as findAllProfilesInProfileFollowersQueryData} from '../queries/profile-followers'
19import {findAllProfilesInQueryData as findAllProfilesInProfileFollowsQueryData} from '../queries/profile-follows'
20import {findAllProfilesInQueryData as findAllProfilesInSuggestedFollowsQueryData} from '../queries/suggested-follows'
21import {castAsShadow, Shadow} from './types'
22export type {Shadow} from './types'
23
24export interface ProfileShadow {
25 followingUri: string | undefined
26 muted: boolean | undefined
27 blockingUri: string | undefined
28}
29
30const shadows: WeakMap<
31 AppBskyActorDefs.ProfileView,
32 Partial<ProfileShadow>
33> = new WeakMap()
34const emitter = new EventEmitter()
35
36export function useProfileShadow<
37 TProfileView extends AppBskyActorDefs.ProfileView,
38>(profile: TProfileView): Shadow<TProfileView> {
39 const [shadow, setShadow] = useState(() => shadows.get(profile))
40 const [prevPost, setPrevPost] = useState(profile)
41 if (profile !== prevPost) {
42 setPrevPost(profile)
43 setShadow(shadows.get(profile))
44 }
45
46 useEffect(() => {
47 function onUpdate() {
48 setShadow(shadows.get(profile))
49 }
50 emitter.addListener(profile.did, onUpdate)
51 return () => {
52 emitter.removeListener(profile.did, onUpdate)
53 }
54 }, [profile])
55
56 return useMemo(() => {
57 if (shadow) {
58 return mergeShadow(profile, shadow)
59 } else {
60 return castAsShadow(profile)
61 }
62 }, [profile, shadow])
63}
64
65export function updateProfileShadow(
66 queryClient: QueryClient,
67 did: string,
68 value: Partial<ProfileShadow>,
69) {
70 const cachedProfiles = findProfilesInCache(queryClient, did)
71 for (let post of cachedProfiles) {
72 shadows.set(post, {...shadows.get(post), ...value})
73 }
74 batchedUpdates(() => {
75 emitter.emit(did, value)
76 })
77}
78
79function mergeShadow<TProfileView extends AppBskyActorDefs.ProfileView>(
80 profile: TProfileView,
81 shadow: Partial<ProfileShadow>,
82): Shadow<TProfileView> {
83 return castAsShadow({
84 ...profile,
85 viewer: {
86 ...(profile.viewer || {}),
87 following:
88 'followingUri' in shadow
89 ? shadow.followingUri
90 : profile.viewer?.following,
91 muted: 'muted' in shadow ? shadow.muted : profile.viewer?.muted,
92 blocking:
93 'blockingUri' in shadow ? shadow.blockingUri : profile.viewer?.blocking,
94 },
95 })
96}
97
98function* findProfilesInCache(
99 queryClient: QueryClient,
100 did: string,
101): Generator<AppBskyActorDefs.ProfileView, void> {
102 yield* findAllProfilesInListMembersQueryData(queryClient, did)
103 yield* findAllProfilesInMyBlockedAccountsQueryData(queryClient, did)
104 yield* findAllProfilesInMyMutedAccountsQueryData(queryClient, did)
105 yield* findAllProfilesInPostLikedByQueryData(queryClient, did)
106 yield* findAllProfilesInPostRepostedByQueryData(queryClient, did)
107 yield* findAllProfilesInProfileQueryData(queryClient, did)
108 yield* findAllProfilesInProfileFollowersQueryData(queryClient, did)
109 yield* findAllProfilesInProfileFollowsQueryData(queryClient, did)
110 yield* findAllProfilesInSuggestedFollowsQueryData(queryClient, did)
111 yield* findAllProfilesInActorSearchQueryData(queryClient, did)
112 yield* findAllProfilesInListConvosQueryData(queryClient, did)
113 yield* findAllProfilesInFeedsQueryData(queryClient, did)
114 yield* findAllProfilesInPostThreadQueryData(queryClient, did)
115 yield* findAllProfilesInKnownFollowersQueryData(queryClient, did)
116}