diff --git a/src/components/FeedInterstitials.tsx b/src/components/FeedInterstitials.tsx
index e37d2c3e..65e981f7 100644
--- a/src/components/FeedInterstitials.tsx
+++ b/src/components/FeedInterstitials.tsx
@@ -1,18 +1,21 @@
import React from 'react'
import {View} from 'react-native'
import {ScrollView} from 'react-native-gesture-handler'
-import {AppBskyFeedDefs, AtUri} from '@atproto/api'
+import {AppBskyActorDefs, AppBskyFeedDefs, AtUri} from '@atproto/api'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useNavigation} from '@react-navigation/native'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {NavigationProp} from '#/lib/routes/types'
+import {useGate} from '#/lib/statsig/statsig'
import {logEvent} from '#/lib/statsig/statsig'
import {logger} from '#/logger'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {useGetPopularFeedsQuery} from '#/state/queries/feed'
+import {FeedDescriptor} from '#/state/queries/post-feed'
import {useProfilesQuery} from '#/state/queries/profile'
+import {useSuggestedFollowsByActorQuery} from '#/state/queries/suggested-follows'
import {useSession} from '#/state/session'
import {useProgressGuide} from '#/state/shell/progress-guide'
import * as userActionHistory from '#/state/userActionHistory'
@@ -173,14 +176,63 @@ function useExperimentalSuggestedUsersQuery() {
}
}
-export function SuggestedFollows() {
- const t = useTheme()
- const {_} = useLingui()
+export function SuggestedFollows({feed}: {feed: FeedDescriptor}) {
+ const gate = useGate()
+ const [feedType, feedUri] = feed.split('|')
+ if (feedType === 'author') {
+ if (gate('show_follow_suggestions_in_profile')) {
+ return
+ } else {
+ return null
+ }
+ } else {
+ return
+ }
+}
+
+export function SuggestedFollowsProfile({did}: {did: string}) {
+ const {
+ isLoading: isSuggestionsLoading,
+ data,
+ error,
+ } = useSuggestedFollowsByActorQuery({
+ did,
+ })
+ return (
+
+ )
+}
+
+export function SuggestedFollowsHome() {
const {
isLoading: isSuggestionsLoading,
profiles,
error,
} = useExperimentalSuggestedUsersQuery()
+ return (
+
+ )
+}
+
+export function ProfileGrid({
+ isSuggestionsLoading,
+ error,
+ profiles,
+}: {
+ isSuggestionsLoading: boolean
+ profiles: AppBskyActorDefs.ProfileViewDetailed[]
+ error: Error | null
+}) {
+ const t = useTheme()
+ const {_} = useLingui()
const moderationOpts = useModerationOpts()
const navigation = useNavigation()
const {gtMobile} = useBreakpoints()
diff --git a/src/lib/statsig/gates.ts b/src/lib/statsig/gates.ts
index d4478477..f45be0b7 100644
--- a/src/lib/statsig/gates.ts
+++ b/src/lib/statsig/gates.ts
@@ -4,5 +4,6 @@ export type Gate =
| 'fixed_bottom_bar'
| 'onboarding_minimum_interests'
| 'suggested_feeds_interstitial'
+ | 'show_follow_suggestions_in_profile'
| 'video_debug'
| 'videos'
diff --git a/src/screens/Profile/Header/ProfileHeaderStandard.tsx b/src/screens/Profile/Header/ProfileHeaderStandard.tsx
index 2b6353b2..2036023c 100644
--- a/src/screens/Profile/Header/ProfileHeaderStandard.tsx
+++ b/src/screens/Profile/Header/ProfileHeaderStandard.tsx
@@ -10,6 +10,7 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
+import {useGate} from '#/lib/statsig/statsig'
import {logger} from '#/logger'
import {isIOS} from '#/platform/detection'
import {Shadow} from '#/state/cache/types'
@@ -59,6 +60,7 @@ let ProfileHeaderStandard = ({
const profile: Shadow =
useProfileShadow(profileUnshadowed)
const t = useTheme()
+ const gate = useGate()
const {currentAccount, hasSession} = useSession()
const {_} = useLingui()
const {openModal} = useModalControls()
@@ -203,27 +205,29 @@ let ProfileHeaderStandard = ({
{hasSession && (
<>
-
+ label={_(msg`Show follows similar to ${profile.handle}`)}
+ style={{width: 36, height: 36}}>
+
+
+ )}
>
)}
diff --git a/src/view/com/posts/Feed.tsx b/src/view/com/posts/Feed.tsx
index f0709a3e..bad6ccfe 100644
--- a/src/view/com/posts/Feed.tsx
+++ b/src/view/com/posts/Feed.tsx
@@ -101,7 +101,7 @@ const feedInterstitialType = 'interstitialFeeds'
const followInterstitialType = 'interstitialFollows'
const progressGuideInterstitialType = 'interstitialProgressGuide'
const interstials: Record<
- 'following' | 'discover',
+ 'following' | 'discover' | 'profile',
(FeedItem & {
type:
| 'interstitialFeeds'
@@ -128,6 +128,16 @@ const interstials: Record<
slot: 20,
},
],
+ profile: [
+ {
+ type: followInterstitialType,
+ params: {
+ variant: 'default',
+ },
+ key: followInterstitialType,
+ slot: 5,
+ },
+ ],
}
export function getFeedPostSlice(feedItem: FeedItem): FeedPostSlice | null {
@@ -193,9 +203,7 @@ let Feed = ({
const [isPTRing, setIsPTRing] = React.useState(false)
const checkForNewRef = React.useRef<(() => void) | null>(null)
const lastFetchRef = React.useRef(Date.now())
- const [feedType, feedUri] = feed.split('|')
- const feedIsDiscover = feedUri === DISCOVER_FEED_URI
- const feedIsFollowing = feedType === 'following'
+ const [feedType, feedUri, feedTab] = feed.split('|')
const gate = useGate()
const opts = React.useMemo(
@@ -339,14 +347,21 @@ let Feed = ({
}
if (hasSession) {
- const feedType = feedIsFollowing
- ? 'following'
- : feedIsDiscover
- ? 'discover'
- : undefined
+ let feedKind: 'following' | 'discover' | 'profile' | undefined
+ if (feedType === 'following') {
+ feedKind = 'following'
+ } else if (feedUri === DISCOVER_FEED_URI) {
+ feedKind = 'discover'
+ } else if (
+ feedType === 'author' &&
+ (feedTab === 'posts_and_author_threads' ||
+ feedTab === 'posts_with_replies')
+ ) {
+ feedKind = 'profile'
+ }
- if (feedType) {
- for (const interstitial of interstials[feedType]) {
+ if (feedKind) {
+ for (const interstitial of interstials[feedKind]) {
const shouldShow =
(interstitial.type === feedInterstitialType &&
gate('suggested_feeds_interstitial')) ||
@@ -377,9 +392,9 @@ let Feed = ({
isEmpty,
lastFetchedAt,
data,
+ feedType,
feedUri,
- feedIsDiscover,
- feedIsFollowing,
+ feedTab,
gate,
hasSession,
])
@@ -470,7 +485,7 @@ let Feed = ({
} else if (item.type === feedInterstitialType) {
return
} else if (item.type === followInterstitialType) {
- return
+ return
} else if (item.type === progressGuideInterstitialType) {
return
} else if (item.type === 'slice') {