Remove getSuggestedFollowsByActor fallbacks and use recIdStr (#9988)
This commit is contained in:
@@ -75,6 +75,8 @@ let ProfileHeaderStandard = ({
|
||||
const [, queueUnblock] = useProfileBlockMutationQueue(profile)
|
||||
const unblockPromptControl = Prompt.usePromptControl()
|
||||
const [showSuggestedFollows, setShowSuggestedFollows] = useState(false)
|
||||
const [hasSeenAllSuggestedFollows, setHasSeenAllSuggestedFollows] =
|
||||
useState(false)
|
||||
const isBlockedUser =
|
||||
profile.viewer?.blocking ||
|
||||
profile.viewer?.blockedBy ||
|
||||
@@ -84,7 +86,8 @@ let ProfileHeaderStandard = ({
|
||||
try {
|
||||
await queueUnblock()
|
||||
Toast.show(_(msg({message: 'Account unblocked', context: 'toast'})))
|
||||
} catch (e: any) {
|
||||
} catch (err) {
|
||||
const e = err as Error
|
||||
if (e?.name !== 'AbortError') {
|
||||
logger.error('Failed to unblock account', {message: e})
|
||||
Toast.show(_(msg`There was an issue! ${e.toString()}`), {type: 'error'})
|
||||
@@ -92,6 +95,11 @@ let ProfileHeaderStandard = ({
|
||||
}
|
||||
}
|
||||
|
||||
const onRequestHide = () => {
|
||||
setHasSeenAllSuggestedFollows(true)
|
||||
setShowSuggestedFollows(false)
|
||||
}
|
||||
|
||||
const isMe = currentAccount?.did === profile.did
|
||||
|
||||
const {isActive: live} = useActorStatus(profile)
|
||||
@@ -192,7 +200,9 @@ let ProfileHeaderStandard = ({
|
||||
description={_(
|
||||
msg`The account will be able to interact with you after unblocking.`,
|
||||
)}
|
||||
onConfirm={unblockAccount}
|
||||
onConfirm={() => {
|
||||
void unblockAccount()
|
||||
}}
|
||||
confirmButtonCta={
|
||||
profile.viewer?.blocking ? _(msg`Unblock`) : _(msg`Block`)
|
||||
}
|
||||
@@ -201,8 +211,9 @@ let ProfileHeaderStandard = ({
|
||||
</ProfileHeaderShell>
|
||||
|
||||
<ProfileHeaderSuggestedFollows
|
||||
isExpanded={showSuggestedFollows}
|
||||
isExpanded={!hasSeenAllSuggestedFollows && showSuggestedFollows}
|
||||
actorDid={profile.did}
|
||||
onRequestHide={onRequestHide}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
@@ -254,7 +265,8 @@ export function HeaderStandardButtons({
|
||||
)}`,
|
||||
),
|
||||
)
|
||||
} catch (e: any) {
|
||||
} catch (err) {
|
||||
const e = err as Error
|
||||
if (e?.name !== 'AbortError') {
|
||||
logger.error('Failed to follow', {message: String(e)})
|
||||
Toast.show(_(msg`There was an issue! ${e.toString()}`), {
|
||||
@@ -280,7 +292,8 @@ export function HeaderStandardButtons({
|
||||
),
|
||||
{type: 'default'},
|
||||
)
|
||||
} catch (e: any) {
|
||||
} catch (err) {
|
||||
const e = err as Error
|
||||
if (e?.name !== 'AbortError') {
|
||||
logger.error('Failed to unfollow', {message: String(e)})
|
||||
Toast.show(_(msg`There was an issue! ${e.toString()}`), {
|
||||
@@ -295,7 +308,8 @@ export function HeaderStandardButtons({
|
||||
try {
|
||||
await queueUnblock()
|
||||
Toast.show(_(msg({message: 'Account unblocked', context: 'toast'})))
|
||||
} catch (e: any) {
|
||||
} catch (err) {
|
||||
const e = err as Error
|
||||
if (e?.name !== 'AbortError') {
|
||||
logger.error('Failed to unblock account', {message: e})
|
||||
Toast.show(_(msg`There was an issue! ${e.toString()}`), {type: 'error'})
|
||||
@@ -400,7 +414,9 @@ export function HeaderStandardButtons({
|
||||
description={_(
|
||||
msg`The account will be able to interact with you after unblocking.`,
|
||||
)}
|
||||
onConfirm={unblockAccount}
|
||||
onConfirm={() => {
|
||||
void unblockAccount()
|
||||
}}
|
||||
confirmButtonCta={_(msg`Unblock`)}
|
||||
confirmButtonColor="negative"
|
||||
/>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import {useCallback, useEffect, useMemo, useState} from 'react'
|
||||
import {useCallback, useMemo} from 'react'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {AccordionAnimation} from '#/lib/custom-animations/AccordionAnimation'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {
|
||||
suggestedFollowsByActorQueryKey,
|
||||
useSuggestedFollowsByActorQuery,
|
||||
useSuggestedFollowsQuery,
|
||||
} from '#/state/queries/suggested-follows'
|
||||
import {useBreakpoints} from '#/alf'
|
||||
import {ProfileGrid} from '#/components/FeedInterstitials'
|
||||
import {IS_ANDROID} from '#/env'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
@@ -14,15 +13,15 @@ import type * as bsky from '#/types/bsky'
|
||||
export function ProfileHeaderSuggestedFollows({
|
||||
isExpanded,
|
||||
actorDid,
|
||||
onRequestHide,
|
||||
}: {
|
||||
isExpanded: boolean
|
||||
actorDid: string
|
||||
onRequestHide: () => void
|
||||
}) {
|
||||
const {allProfiles, filteredProfiles, onDismiss, isLoading, error} =
|
||||
const {profiles, onDismiss, isLoading, error} =
|
||||
useProfileHeaderSuggestions(actorDid)
|
||||
|
||||
if (!allProfiles.length && !isLoading) return null
|
||||
|
||||
/* NOTE (caidanw):
|
||||
* Android does not work well with this feature yet.
|
||||
* This issue stems from Android not allowing dragging on clickable elements in the profile header.
|
||||
@@ -34,92 +33,51 @@ export function ProfileHeaderSuggestedFollows({
|
||||
<AccordionAnimation isExpanded={isExpanded}>
|
||||
<ProfileGrid
|
||||
isSuggestionsLoading={isLoading}
|
||||
profiles={filteredProfiles}
|
||||
totalProfileCount={allProfiles.length}
|
||||
profiles={profiles}
|
||||
totalProfileCount={profiles.length}
|
||||
error={error}
|
||||
viewContext="profileHeader"
|
||||
onDismiss={onDismiss}
|
||||
isVisible={isExpanded}
|
||||
onRequestHide={onRequestHide}
|
||||
/>
|
||||
</AccordionAnimation>
|
||||
)
|
||||
}
|
||||
|
||||
function useProfileHeaderSuggestions(actorDid: string) {
|
||||
const {gtMobile} = useBreakpoints()
|
||||
const moderationOpts = useModerationOpts()
|
||||
const maxLength = gtMobile ? 4 : 12
|
||||
const {isLoading, data, error} = useSuggestedFollowsByActorQuery({
|
||||
did: actorDid,
|
||||
})
|
||||
const {
|
||||
data: moreSuggestions,
|
||||
fetchNextPage,
|
||||
hasNextPage,
|
||||
isFetchingNextPage,
|
||||
} = useSuggestedFollowsQuery({limit: 25})
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const [dismissedDids, setDismissedDids] = useState<Set<string>>(new Set())
|
||||
const onDismiss = useCallback(
|
||||
(dismissedDid: string) => {
|
||||
queryClient.setQueryData(
|
||||
suggestedFollowsByActorQueryKey(actorDid),
|
||||
(previous: typeof data) => {
|
||||
if (!previous) return previous
|
||||
return {
|
||||
...previous,
|
||||
suggestions: previous.suggestions.filter(
|
||||
s => s.did !== dismissedDid,
|
||||
),
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
[actorDid, queryClient],
|
||||
)
|
||||
|
||||
const onDismiss = useCallback((did: string) => {
|
||||
setDismissedDids(prev => new Set(prev).add(did))
|
||||
}, [])
|
||||
|
||||
// Combine profiles from the actor-specific query with fallback suggestions
|
||||
const allProfiles = useMemo(() => {
|
||||
const actorProfiles = data?.suggestions ?? []
|
||||
const fallbackProfiles =
|
||||
moreSuggestions?.pages.flatMap(page =>
|
||||
page.actors.map(actor => ({actor, recId: page.recId})),
|
||||
) ?? []
|
||||
|
||||
// Dedupe by did, preferring actor-specific profiles
|
||||
const seen = new Set<string>()
|
||||
const combined: {actor: bsky.profile.AnyProfileView; recId?: number}[] = []
|
||||
|
||||
for (const profile of actorProfiles) {
|
||||
if (!seen.has(profile.did)) {
|
||||
seen.add(profile.did)
|
||||
combined.push({actor: profile, recId: data?.recId})
|
||||
}
|
||||
}
|
||||
|
||||
for (const profile of fallbackProfiles) {
|
||||
if (!seen.has(profile.actor.did) && profile.actor.did !== actorDid) {
|
||||
seen.add(profile.actor.did)
|
||||
combined.push(profile)
|
||||
}
|
||||
}
|
||||
|
||||
return combined
|
||||
}, [data?.suggestions, moreSuggestions?.pages, actorDid, data?.recId])
|
||||
|
||||
const filteredProfiles = useMemo(() => {
|
||||
return allProfiles.filter(p => !dismissedDids.has(p.actor.did))
|
||||
}, [allProfiles, dismissedDids])
|
||||
|
||||
// Fetch more when running low
|
||||
useEffect(() => {
|
||||
if (
|
||||
moderationOpts &&
|
||||
filteredProfiles.length < maxLength &&
|
||||
hasNextPage &&
|
||||
!isFetchingNextPage
|
||||
) {
|
||||
void fetchNextPage()
|
||||
}
|
||||
}, [
|
||||
filteredProfiles.length,
|
||||
maxLength,
|
||||
hasNextPage,
|
||||
isFetchingNextPage,
|
||||
fetchNextPage,
|
||||
moderationOpts,
|
||||
])
|
||||
const profiles = useMemo(() => {
|
||||
return (data?.suggestions ?? []).map(profile => ({
|
||||
actor: profile as bsky.profile.AnyProfileView,
|
||||
recId: data?.recId,
|
||||
}))
|
||||
}, [data?.suggestions, data?.recId])
|
||||
|
||||
return {
|
||||
allProfiles,
|
||||
filteredProfiles,
|
||||
profiles,
|
||||
onDismiss,
|
||||
isLoading,
|
||||
error,
|
||||
|
||||
Reference in New Issue
Block a user