diff options
Diffstat (limited to 'src/state/queries/profile.ts')
-rw-r--r-- | src/state/queries/profile.ts | 80 |
1 files changed, 77 insertions, 3 deletions
diff --git a/src/state/queries/profile.ts b/src/state/queries/profile.ts index affb8295c..e81ea0f3f 100644 --- a/src/state/queries/profile.ts +++ b/src/state/queries/profile.ts @@ -4,6 +4,9 @@ import { AppBskyActorDefs, AppBskyActorProfile, AppBskyActorGetProfile, + AppBskyFeedDefs, + AppBskyEmbedRecord, + AppBskyEmbedRecordWithMedia, } from '@atproto/api' import { useQuery, @@ -23,9 +26,14 @@ import {RQKEY as RQKEY_MY_MUTED} from './my-muted-accounts' import {RQKEY as RQKEY_MY_BLOCKED} from './my-blocked-accounts' import {STALE} from '#/state/queries' import {track} from '#/lib/analytics/analytics' +import {ThreadNode} from './post-thread' export const RQKEY = (did: string) => ['profile', did] export const profilesQueryKey = (handles: string[]) => ['profiles', handles] +export const profileBasicQueryKey = (didOrHandle: string) => [ + 'profileBasic', + didOrHandle, +] export function useProfileQuery({ did, @@ -34,18 +42,26 @@ export function useProfileQuery({ did: string | undefined staleTime?: number }) { - return useQuery({ + const queryClient = useQueryClient() + return useQuery<AppBskyActorDefs.ProfileViewDetailed>({ // WARNING // this staleTime is load-bearing // if you remove it, the UI infinite-loops // -prf staleTime, refetchOnWindowFocus: true, - queryKey: RQKEY(did || ''), + queryKey: RQKEY(did ?? ''), queryFn: async () => { - const res = await getAgent().getProfile({actor: did || ''}) + const res = await getAgent().getProfile({actor: did ?? ''}) return res.data }, + placeholderData: () => { + if (!did) return + + return queryClient.getQueryData<AppBskyActorDefs.ProfileViewBasic>( + profileBasicQueryKey(did), + ) + }, enabled: !!did, }) } @@ -405,6 +421,64 @@ function useProfileUnblockMutation() { }) } +export function precacheProfile( + queryClient: QueryClient, + profile: AppBskyActorDefs.ProfileViewBasic, +) { + queryClient.setQueryData(profileBasicQueryKey(profile.handle), profile) + queryClient.setQueryData(profileBasicQueryKey(profile.did), profile) +} + +export function precacheFeedPostProfiles( + queryClient: QueryClient, + posts: AppBskyFeedDefs.FeedViewPost[], +) { + for (const post of posts) { + // Save the author of the post every time + precacheProfile(queryClient, post.post.author) + precachePostEmbedProfile(queryClient, post.post.embed) + + // Cache parent author and embeds + const parent = post.reply?.parent + if (AppBskyFeedDefs.isPostView(parent)) { + precacheProfile(queryClient, parent.author) + precachePostEmbedProfile(queryClient, parent.embed) + } + } +} + +function precachePostEmbedProfile( + queryClient: QueryClient, + embed: AppBskyFeedDefs.PostView['embed'], +) { + if (AppBskyEmbedRecord.isView(embed)) { + if (AppBskyEmbedRecord.isViewRecord(embed.record)) { + precacheProfile(queryClient, embed.record.author) + } + } else if (AppBskyEmbedRecordWithMedia.isView(embed)) { + if (AppBskyEmbedRecord.isViewRecord(embed.record.record)) { + precacheProfile(queryClient, embed.record.record.author) + } + } +} + +export function precacheThreadPostProfiles( + queryClient: QueryClient, + node: ThreadNode, +) { + if (node.type === 'post') { + precacheProfile(queryClient, node.post.author) + if (node.parent) { + precacheThreadPostProfiles(queryClient, node.parent) + } + if (node.replies?.length) { + for (const reply of node.replies) { + precacheThreadPostProfiles(queryClient, reply) + } + } + } +} + async function whenAppViewReady( actor: string, fn: (res: AppBskyActorGetProfile.Response) => boolean, |