import React from 'react' import {View, StyleSheet, Pressable, ScrollView} from 'react-native' import Animated, { useSharedValue, withTiming, useAnimatedStyle, Easing, } from 'react-native-reanimated' import {AppBskyActorDefs, moderateProfile} from '@atproto/api' import { FontAwesomeIcon, FontAwesomeIconStyle, } from '@fortawesome/react-native-fontawesome' import * as Toast from '../util/Toast' import {usePalette} from 'lib/hooks/usePalette' import {Text} from 'view/com/util/text/Text' import {UserAvatar} from 'view/com/util/UserAvatar' 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' import {useModerationOpts} from '#/state/queries/preferences' import {useSuggestedFollowsByActorQuery} from '#/state/queries/suggested-follows' import {useProfileShadow} from '#/state/cache/profile-shadow' import {useProfileFollowMutationQueue} from '#/state/queries/profile' 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 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} = useSuggestedFollowsByActorQuery({ did: actorDid, }) return ( Suggested for you {isLoading ? ( <> ) : data ? ( data.suggestions.map(profile => ( )) ) : ( )} ) } function SuggestedFollowSkeleton() { const pal = usePalette('default') return ( ) } function SuggestedFollow({ profile: profileUnshadowed, }: { profile: AppBskyActorDefs.ProfileView }) { const {track} = useAnalytics() const pal = usePalette('default') const moderationOpts = useModerationOpts() const profile = useProfileShadow(profileUnshadowed) const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue(profile) const onPressFollow = React.useCallback(async () => { try { track('ProfileHeader:SuggestedFollowFollowed') await queueFollow() } catch (e: any) { if (e?.name !== 'AbortError') { Toast.show('An issue occurred, please try again.') } } }, [queueFollow, track]) const onPressUnfollow = React.useCallback(async () => { try { await queueUnfollow() } catch (e: any) { if (e?.name !== 'AbortError') { Toast.show('An issue occurred, please try again.') } } }, [queueUnfollow]) if (!moderationOpts) { return null } const moderation = moderateProfile(profile, moderationOpts) const following = profile.viewer?.following return ( {sanitizeDisplayName( profile.displayName || sanitizeHandle(profile.handle), moderation.profile, )} {sanitizeHandle(profile.handle, '@')}