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