import React from 'react' import {View, StyleSheet, Pressable, ScrollView} from 'react-native' import Animated, { useSharedValue, withTiming, useAnimatedStyle, Easing, } from 'react-native-reanimated' import {useQuery} from '@tanstack/react-query' import {AppBskyActorDefs, moderateProfile} from '@atproto/api' import {observer} from 'mobx-react-lite' import { FontAwesomeIcon, FontAwesomeIconStyle, } from '@fortawesome/react-native-fontawesome' import * as Toast from '../util/Toast' import {useStores} from 'state/index' import {usePalette} from 'lib/hooks/usePalette' import {Text} from 'view/com/util/text/Text' import {UserAvatar} from 'view/com/util/UserAvatar' import {useFollowProfile} from 'lib/hooks/useFollowProfile' import {Button} from 'view/com/util/forms/Button' import {sanitizeDisplayName} from 'lib/strings/display-names' import {sanitizeHandle} from 'lib/strings/handles' import {makeProfileLink} from 'lib/routes/links' import {Link} from 'view/com/util/Link' import {useAnalytics} from 'lib/analytics/analytics' import {isWeb} from 'platform/detection' const OUTER_PADDING = 10 const INNER_PADDING = 14 const TOTAL_HEIGHT = 250 export function ProfileHeaderSuggestedFollows({ actorDid, active, requestDismiss, }: { actorDid: string active: boolean requestDismiss: () => void }) { const {track} = useAnalytics() const pal = usePalette('default') const store = useStores() const animatedHeight = useSharedValue(0) const animatedStyles = useAnimatedStyle(() => ({ opacity: animatedHeight.value / TOTAL_HEIGHT, height: animatedHeight.value, })) React.useEffect(() => { if (active) { track('ProfileHeader:SuggestedFollowsOpened') animatedHeight.value = withTiming(TOTAL_HEIGHT, { duration: 500, easing: Easing.inOut(Easing.exp), }) } else { animatedHeight.value = withTiming(0, { duration: 500, easing: Easing.inOut(Easing.exp), }) } }, [active, animatedHeight, track]) const {isLoading, data: suggestedFollows} = useQuery({ enabled: active, cacheTime: 0, staleTime: 0, queryKey: ['suggested_follows_by_actor', actorDid], async queryFn() { try { const { data: {suggestions}, success, } = await store.agent.app.bsky.graph.getSuggestedFollowsByActor({ actor: actorDid, }) if (!success) { return [] } store.me.follows.hydrateMany(suggestions) return suggestions } catch (e) { return [] } }, }) return ( Suggested for you {isLoading ? ( <> ) : suggestedFollows ? ( suggestedFollows.map(profile => ( )) ) : ( )} ) } function SuggestedFollowSkeleton() { const pal = usePalette('default') return ( ) } const SuggestedFollow = observer(function SuggestedFollowImpl({ profile, }: { profile: AppBskyActorDefs.ProfileView }) { const {track} = useAnalytics() const pal = usePalette('default') const store = useStores() const {following, toggle} = useFollowProfile(profile) const moderation = moderateProfile(profile, store.preferences.moderationOpts) const onPress = React.useCallback(async () => { try { const {following: isFollowing} = await toggle() if (isFollowing) { track('ProfileHeader:SuggestedFollowFollowed') } } catch (e: any) { Toast.show('An issue occurred, please try again.') } }, [toggle, track]) return ( {sanitizeDisplayName( profile.displayName || sanitizeHandle(profile.handle), moderation.profile, )} {sanitizeHandle(profile.handle, '@')}