diff --git a/src/components/FeedSuggestedFollows/index.tsx b/src/components/FeedSuggestedFollows/index.tsx
new file mode 100644
index 0000000000..0c8993f8ce
--- /dev/null
+++ b/src/components/FeedSuggestedFollows/index.tsx
@@ -0,0 +1,156 @@
+import React from 'react'
+import {View} from 'react-native'
+import {ScrollView} from 'react-native-gesture-handler'
+import {AppBskyActorDefs, moderateProfile} from '@atproto/api'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+
+import {useProfileShadow} from '#/state/cache/profile-shadow'
+import {useModerationOpts} from '#/state/queries/preferences'
+import {useSuggestedFollowsQuery} from '#/state/queries/suggested-follows'
+import {isJustAMute} from 'lib/moderation'
+import {sanitizeDisplayName} from 'lib/strings/display-names'
+import {sanitizeHandle} from 'lib/strings/handles'
+import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
+import {atoms as a, useTheme} from '#/alf'
+import {Button, ButtonIcon} from '#/components/Button'
+import {useFollowMethods} from '#/components/hooks/useFollowMethods'
+import {useRichText} from '#/components/hooks/useRichText'
+import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
+import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
+import {RichText} from '#/components/RichText'
+import {Text} from '#/components/Typography'
+
+export function SuggestedFollowCard({
+ profile: profileUnshadowed,
+}: {
+ profile: AppBskyActorDefs.ProfileViewBasic
+}) {
+ const t = useTheme()
+ const {_} = useLingui()
+ const profile = useProfileShadow(profileUnshadowed)
+ const moderationOpts = useModerationOpts()
+ const {follow, unfollow} = useFollowMethods({
+ profile,
+ // @ts-ignore TODO
+ logContext: 'FeedSuggestedFollowsCard',
+ })
+ // @ts-ignore TODO
+ const [descriptionRT] = useRichText(profileUnshadowed?.description ?? '')
+
+ if (!moderationOpts) return null
+ const moderation = moderateProfile(profile, moderationOpts)
+ const modui = moderation.ui('profileList')
+ if (modui.filter && !isJustAMute(modui)) return null
+
+ return (
+
+
+
+
+
+
+
+ {sanitizeDisplayName(
+ profile.displayName || sanitizeHandle(profile.handle),
+ moderation.ui('displayName'),
+ )}
+
+
+ {sanitizeHandle(profile.handle, '@')}
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export function FeedSuggestedFollows() {
+ const t = useTheme()
+ const {isLoading, data: suggestions, error} = useSuggestedFollowsQuery()
+
+ const profiles: AppBskyActorDefs.ProfileViewBasic[] = []
+ if (suggestions) {
+ // Currently the responses contain duplicate items.
+ // Needs to be fixed on backend, but let's dedupe to be safe.
+ let seen = new Set()
+ for (const page of suggestions.pages) {
+ for (const actor of page.actors) {
+ if (!seen.has(actor.did)) {
+ seen.add(actor.did)
+ profiles.push(actor)
+ }
+ }
+ }
+ }
+
+ return (
+
+
+
+ Suggested for you
+
+
+
+
+
+ {isLoading
+ ? null
+ : error || !profiles.length
+ ? null
+ : profiles.map((profile, i) => (
+
+ ))}
+
+
+
+ )
+}
diff --git a/src/view/com/posts/Feed.tsx b/src/view/com/posts/Feed.tsx
index fb67d35c5c..894be3b76f 100644
--- a/src/view/com/posts/Feed.tsx
+++ b/src/view/com/posts/Feed.tsx
@@ -29,6 +29,7 @@ import {useSession} from '#/state/session'
import {useAnalytics} from 'lib/analytics/analytics'
import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
import {useTheme} from 'lib/ThemeContext'
+import {FeedSuggestedFollows} from '#/components/FeedSuggestedFollows'
import {List, ListRef} from '../util/List'
import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
@@ -40,6 +41,7 @@ const LOADING_ITEM = {_reactKey: '__loading__'}
const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
const ERROR_ITEM = {_reactKey: '__error__'}
const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
+const SUGGESTED_FOLLOWS_ITEM = {_reactKey: '__suggested_follows__'}
// DISABLED need to check if this is causing random feed refreshes -prf
// const REFRESH_AFTER = STALE.HOURS.ONE
@@ -198,6 +200,7 @@ let Feed = ({
} else if (isEmpty) {
arr = arr.concat([EMPTY_FEED_ITEM])
} else if (data) {
+ arr = arr.concat(SUGGESTED_FOLLOWS_ITEM)
for (const page of data?.pages) {
arr = arr.concat(page.slices)
}
@@ -297,6 +300,8 @@ let Feed = ({
// see home.ts (feed api) for more info
// -prf
return
+ } else if (item === SUGGESTED_FOLLOWS_ITEM) {
+ return
}
return
},