Suggested follows by actor (on profiles) updates (#5243)

* If fallback, return nothing

* Compress size a bit

* Hide on own profile

* Match load state

* Remove gcTime

* Filter out followed users

* Feedback
zio/stable^2^2
Eric Bailey 2024-09-12 16:34:10 -05:00 committed by GitHub
parent 47bea32061
commit d60a8f26c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 61 additions and 49 deletions

View File

@ -60,16 +60,13 @@ function CardOuter({
export function SuggestedFollowPlaceholder() { export function SuggestedFollowPlaceholder() {
const t = useTheme() const t = useTheme()
return ( return (
<CardOuter style={[a.gap_sm, t.atoms.border_contrast_low]}> <CardOuter style={[a.gap_md, t.atoms.border_contrast_low]}>
<ProfileCard.Header> <ProfileCard.Header>
<ProfileCard.AvatarPlaceholder /> <ProfileCard.AvatarPlaceholder />
<ProfileCard.NameAndHandlePlaceholder />
</ProfileCard.Header> </ProfileCard.Header>
<View style={[a.py_xs]}> <ProfileCard.DescriptionPlaceholder numberOfLines={2} />
<ProfileCard.NameAndHandlePlaceholder />
</View>
<ProfileCard.DescriptionPlaceholder />
</CardOuter> </CardOuter>
) )
} }
@ -176,9 +173,14 @@ function useExperimentalSuggestedUsersQuery() {
} }
export function SuggestedFollows({feed}: {feed: FeedDescriptor}) { export function SuggestedFollows({feed}: {feed: FeedDescriptor}) {
const [feedType, feedUri] = feed.split('|') const {currentAccount} = useSession()
const [feedType, feedUriOrDid] = feed.split('|')
if (feedType === 'author') { if (feedType === 'author') {
return <SuggestedFollowsProfile did={feedUri} /> if (currentAccount?.did === feedUriOrDid) {
return null
} else {
return <SuggestedFollowsProfile did={feedUriOrDid} />
}
} else { } else {
return <SuggestedFollowsHome /> return <SuggestedFollowsHome />
} }
@ -197,6 +199,7 @@ export function SuggestedFollowsProfile({did}: {did: string}) {
isSuggestionsLoading={isSuggestionsLoading} isSuggestionsLoading={isSuggestionsLoading}
profiles={data?.suggestions ?? []} profiles={data?.suggestions ?? []}
error={error} error={error}
viewContext="profile"
/> />
) )
} }
@ -212,6 +215,7 @@ export function SuggestedFollowsHome() {
isSuggestionsLoading={isSuggestionsLoading} isSuggestionsLoading={isSuggestionsLoading}
profiles={profiles} profiles={profiles}
error={error} error={error}
viewContext="feed"
/> />
) )
} }
@ -220,10 +224,12 @@ export function ProfileGrid({
isSuggestionsLoading, isSuggestionsLoading,
error, error,
profiles, profiles,
viewContext = 'feed',
}: { }: {
isSuggestionsLoading: boolean isSuggestionsLoading: boolean
profiles: AppBskyActorDefs.ProfileViewDetailed[] profiles: AppBskyActorDefs.ProfileViewDetailed[]
error: Error | null error: Error | null
viewContext: 'profile' | 'feed'
}) { }) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {_} = useLingui()
@ -280,7 +286,7 @@ export function ProfileGrid({
shape="round" shape="round"
/> />
</ProfileCard.Header> </ProfileCard.Header>
<ProfileCard.Description profile={profile} /> <ProfileCard.Description profile={profile} numberOfLines={2} />
</ProfileCard.Outer> </ProfileCard.Outer>
</CardOuter> </CardOuter>
)} )}
@ -297,33 +303,31 @@ export function ProfileGrid({
return ( return (
<View <View
style={[a.border_t, t.atoms.border_contrast_low, t.atoms.bg_contrast_25]}> style={[a.border_t, t.atoms.border_contrast_low, t.atoms.bg_contrast_25]}>
<View style={[a.pt_2xl, a.px_lg, a.flex_row, a.pb_xs]}> <View
<Text
style={[ style={[
a.flex_1, a.p_lg,
a.text_lg, a.pb_xs,
a.font_bold, a.flex_row,
t.atoms.text_contrast_medium, a.align_center,
a.justify_between,
]}> ]}>
<Text style={[a.text_sm, a.font_bold, t.atoms.text_contrast_medium]}>
{viewContext === 'profile' ? (
<Trans>Similar accounts</Trans>
) : (
<Trans>Suggested for you</Trans> <Trans>Suggested for you</Trans>
)}
</Text> </Text>
<Person fill={t.atoms.text_contrast_low.color} /> <Person fill={t.atoms.text_contrast_low.color} size="sm" />
</View> </View>
{gtMobile ? ( {gtMobile ? (
<View style={[a.flex_1, a.px_lg, a.pt_md, a.pb_xl, a.gap_md]}> <View style={[a.flex_1, a.px_lg, a.pt_sm, a.pb_lg, a.gap_md]}>
<View style={[a.flex_1, a.flex_row, a.flex_wrap, a.gap_md]}> <View style={[a.flex_1, a.flex_row, a.flex_wrap, a.gap_sm]}>
{content} {content}
</View> </View>
<View <View style={[a.flex_row, a.justify_end, a.align_center, a.gap_md]}>
style={[
a.flex_row,
a.justify_end,
a.align_center,
a.pt_xs,
a.gap_md,
]}>
<InlineLinkText <InlineLinkText
label={_(msg`Browse more suggestions`)} label={_(msg`Browse more suggestions`)}
to="/search" to="/search"
@ -339,7 +343,7 @@ export function ProfileGrid({
showsHorizontalScrollIndicator={false} showsHorizontalScrollIndicator={false}
snapToInterval={MOBILE_CARD_WIDTH + a.gap_md.gap} snapToInterval={MOBILE_CARD_WIDTH + a.gap_md.gap}
decelerationRate="fast"> decelerationRate="fast">
<View style={[a.px_lg, a.pt_md, a.pb_xl, a.flex_row, a.gap_md]}> <View style={[a.px_lg, a.pt_sm, a.pb_lg, a.flex_row, a.gap_md]}>
{content} {content}
<Button <Button

View File

@ -220,8 +220,10 @@ export function NameAndHandlePlaceholder() {
export function Description({ export function Description({
profile: profileUnshadowed, profile: profileUnshadowed,
numberOfLines = 3,
}: { }: {
profile: AppBskyActorDefs.ProfileViewDetailed profile: AppBskyActorDefs.ProfileViewDetailed
numberOfLines?: number
}) { }) {
const profile = useProfileShadow(profileUnshadowed) const profile = useProfileShadow(profileUnshadowed)
const {description} = profile const {description} = profile
@ -244,31 +246,34 @@ export function Description({
<RichText <RichText
value={rt} value={rt}
style={[a.leading_snug]} style={[a.leading_snug]}
numberOfLines={3} numberOfLines={numberOfLines}
disableLinks disableLinks
/> />
</View> </View>
) )
} }
export function DescriptionPlaceholder() { export function DescriptionPlaceholder({
numberOfLines = 3,
}: {
numberOfLines?: number
}) {
const t = useTheme() const t = useTheme()
return ( return (
<View style={[a.gap_xs]}> <View style={[{gap: 8}]}>
<View {Array(numberOfLines)
style={[a.rounded_xs, a.w_full, t.atoms.bg_contrast_50, {height: 12}]} .fill(0)
/> .map((_, i) => (
<View
style={[a.rounded_xs, a.w_full, t.atoms.bg_contrast_50, {height: 12}]}
/>
<View <View
key={i}
style={[ style={[
a.rounded_xs, a.rounded_xs,
a.w_full, a.w_full,
t.atoms.bg_contrast_50, t.atoms.bg_contrast_50,
{height: 12, width: 100}, {height: 12, width: i + 1 === numberOfLines ? '60%' : '100%'},
]} ]}
/> />
))}
</View> </View>
) )
} }

View File

@ -106,13 +106,16 @@ export function useSuggestedFollowsQuery(options?: SuggestedFollowsOptions) {
export function useSuggestedFollowsByActorQuery({did}: {did: string}) { export function useSuggestedFollowsByActorQuery({did}: {did: string}) {
const agent = useAgent() const agent = useAgent()
return useQuery<AppBskyGraphGetSuggestedFollowsByActor.OutputSchema, Error>({ return useQuery<AppBskyGraphGetSuggestedFollowsByActor.OutputSchema, Error>({
gcTime: 0,
queryKey: suggestedFollowsByActorQueryKey(did), queryKey: suggestedFollowsByActorQueryKey(did),
queryFn: async () => { queryFn: async () => {
const res = await agent.app.bsky.graph.getSuggestedFollowsByActor({ const res = await agent.app.bsky.graph.getSuggestedFollowsByActor({
actor: did, actor: did,
}) })
return res.data const data = res.data.isFallback ? {suggestions: []} : res.data
data.suggestions = data.suggestions.filter(profile => {
return !profile.viewer?.following
})
return data
}, },
}) })
} }