import React from 'react' import {View} from 'react-native' import {ScrollView} from 'react-native-gesture-handler' import {AppBskyActorDefs, AppBskyFeedDefs} 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 {logEvent} from '#/lib/statsig/statsig' import {useModerationOpts} from '#/state/preferences/moderation-opts' import {useGetPopularFeedsQuery} from '#/state/queries/feed' import {useSuggestedFollowsQuery} from '#/state/queries/suggested-follows' import {useProgressGuide} from '#/state/shell/progress-guide' import {atoms as a, useBreakpoints, useTheme, ViewStyleProp, web} from '#/alf' import {Button} from '#/components/Button' import * as FeedCard from '#/components/FeedCard' import {ArrowRight_Stroke2_Corner0_Rounded as Arrow} from '#/components/icons/Arrow' import {Hashtag_Stroke2_Corner0_Rounded as Hashtag} from '#/components/icons/Hashtag' import {PersonPlus_Stroke2_Corner0_Rounded as Person} from '#/components/icons/Person' import {InlineLinkText} from '#/components/Link' import * as ProfileCard from '#/components/ProfileCard' import {Text} from '#/components/Typography' import {ProgressGuideList} from './ProgressGuide/List' function CardOuter({ children, style, }: {children: React.ReactNode | React.ReactNode[]} & ViewStyleProp) { const t = useTheme() const {gtMobile} = useBreakpoints() return ( {children} ) } export function SuggestedFollowPlaceholder() { const t = useTheme() return ( ) } export function SuggestedFeedsCardPlaceholder() { const t = useTheme() return ( ) } export function SuggestedFollows() { const t = useTheme() const {_} = useLingui() const { isLoading: isSuggestionsLoading, data, error, } = useSuggestedFollowsQuery({limit: 6}) const moderationOpts = useModerationOpts() const navigation = useNavigation() const {gtMobile} = useBreakpoints() const isLoading = isSuggestionsLoading || !moderationOpts const maxLength = gtMobile ? 4 : 6 const profiles: AppBskyActorDefs.ProfileViewBasic[] = [] if (data) { // 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 data.pages) { for (const actor of page.actors) { if (!seen.has(actor.did)) { seen.add(actor.did) profiles.push(actor) } } } } const content = isLoading ? ( Array(maxLength) .fill(0) .map((_, i) => ( )) ) : error || !profiles.length ? null : ( <> {profiles.slice(0, maxLength).map(profile => ( { logEvent('feed:interstitial:profileCard:press', {}) }} style={[ a.flex_1, gtMobile && web([a.flex_0, {width: 'calc(50% - 6px)'}]), ]}> {({hovered, pressed}) => ( )} ))} ) return error ? null : ( Suggested for you {gtMobile ? ( {content} Browse more suggestions ) : ( {content} )} ) } export function SuggestedFeeds() { const numFeedsToDisplay = 3 const t = useTheme() const {_} = useLingui() const {data, isLoading, error} = useGetPopularFeedsQuery({ limit: numFeedsToDisplay, }) const navigation = useNavigation() const {gtMobile} = useBreakpoints() const feeds = React.useMemo(() => { const items: AppBskyFeedDefs.GeneratorView[] = [] if (!data) return items for (const page of data.pages) { for (const feed of page.feeds) { items.push(feed) } } return items }, [data]) const content = isLoading ? ( Array(numFeedsToDisplay) .fill(0) .map((_, i) => ) ) : error || !feeds ? null : ( <> {feeds.slice(0, numFeedsToDisplay).map(feed => ( { logEvent('feed:interstitial:feedCard:press', {}) }}> {({hovered, pressed}) => ( )} ))} ) return error ? null : ( Some other feeds you might like {gtMobile ? ( {content} Browse more suggestions ) : ( {content} )} ) } export function ProgressGuide() { const t = useTheme() const {isDesktop} = useWebMediaQueries() const guide = useProgressGuide('like-10-and-follow-7') if (isDesktop) { return null } return guide ? ( ) : null }