import React, { useCallback, useEffect, useImperativeHandle, useState, } from 'react' import { findNodeHandle, type ListRenderItemInfo, type StyleProp, View, type ViewStyle, } from 'react-native' import {type AppBskyGraphDefs} from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useNavigation} from '@react-navigation/native' import {useGenerateStarterPackMutation} from '#/lib/generate-starterpack' import {useBottomBarOffset} from '#/lib/hooks/useBottomBarOffset' import {useRequireEmailVerification} from '#/lib/hooks/useRequireEmailVerification' import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' import {type NavigationProp} from '#/lib/routes/types' import {parseStarterPackUri} from '#/lib/strings/starter-pack' import {logger} from '#/logger' import {isIOS} from '#/platform/detection' import {useActorStarterPacksQuery} from '#/state/queries/actor-starter-packs' import {List, type ListRef} from '#/view/com/util/List' import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' import {atoms as a, ios, useTheme} from '#/alf' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {useDialogControl} from '#/components/Dialog' import {PlusSmall_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus' import {LinearGradientBackground} from '#/components/LinearGradientBackground' import {Loader} from '#/components/Loader' import * as Prompt from '#/components/Prompt' import {Default as StarterPackCard} from '#/components/StarterPack/StarterPackCard' import {Text} from '#/components/Typography' interface SectionRef { scrollToTop: () => void } interface ProfileFeedgensProps { scrollElRef: ListRef did: string headerOffset: number enabled?: boolean style?: StyleProp testID?: string setScrollViewTag: (tag: number | null) => void isMe: boolean } function keyExtractor(item: AppBskyGraphDefs.StarterPackView) { return item.uri } export const ProfileStarterPacks = React.forwardRef< SectionRef, ProfileFeedgensProps >(function ProfileFeedgensImpl( { scrollElRef, did, headerOffset, enabled, style, testID, setScrollViewTag, isMe, }, ref, ) { const t = useTheme() const bottomBarOffset = useBottomBarOffset(100) const [isPTRing, setIsPTRing] = useState(false) const { data, refetch, isError, hasNextPage, isFetchingNextPage, fetchNextPage, } = useActorStarterPacksQuery({did, enabled}) const {isTabletOrDesktop} = useWebMediaQueries() const items = data?.pages.flatMap(page => page.starterPacks) useImperativeHandle(ref, () => ({ scrollToTop: () => {}, })) const onRefresh = useCallback(async () => { setIsPTRing(true) try { await refetch() } catch (err) { logger.error('Failed to refresh starter packs', {message: err}) } setIsPTRing(false) }, [refetch, setIsPTRing]) const onEndReached = React.useCallback(async () => { if (isFetchingNextPage || !hasNextPage || isError) return try { await fetchNextPage() } catch (err) { logger.error('Failed to load more starter packs', {message: err}) } }, [isFetchingNextPage, hasNextPage, isError, fetchNextPage]) useEffect(() => { if (isIOS && enabled && scrollElRef.current) { const nativeTag = findNodeHandle(scrollElRef.current) setScrollViewTag(nativeTag) } }, [enabled, scrollElRef, setScrollViewTag]) const renderItem = useCallback( ({item, index}: ListRenderItemInfo) => { return ( ) }, [isTabletOrDesktop, t.atoms.border_contrast_low], ) return ( ) }) function CreateAnother() { const {_} = useLingui() const t = useTheme() const navigation = useNavigation() return ( ) } function Empty() { const {_} = useLingui() const navigation = useNavigation() const confirmDialogControl = useDialogControl() const followersDialogControl = useDialogControl() const errorDialogControl = useDialogControl() const requireEmailVerification = useRequireEmailVerification() const [isGenerating, setIsGenerating] = useState(false) const {mutate: generateStarterPack} = useGenerateStarterPackMutation({ onSuccess: ({uri}) => { const parsed = parseStarterPackUri(uri) if (parsed) { navigation.push('StarterPack', { name: parsed.name, rkey: parsed.rkey, }) } setIsGenerating(false) }, onError: e => { logger.error('Failed to generate starter pack', {safeMessage: e}) setIsGenerating(false) if (e.name === 'NOT_ENOUGH_FOLLOWERS') { followersDialogControl.open() } else { errorDialogControl.open() } }, }) const generate = () => { setIsGenerating(true) generateStarterPack() } const openConfirmDialog = useCallback(() => { confirmDialogControl.open() }, [confirmDialogControl]) const wrappedOpenConfirmDialog = requireEmailVerification(openConfirmDialog, { instructions: [ Before creating a starter pack, you must first verify your email. , ], }) const navToWizard = useCallback(() => { navigation.navigate('StarterPackWizard', {}) }, [navigation]) const wrappedNavToWizard = requireEmailVerification(navToWizard, { instructions: [ Before creating a starter pack, you must first verify your email. , ], }) return ( You haven't created a starter pack yet! Starter packs let you easily share your favorite feeds and people with your friends. Generate a starter pack Bluesky will choose a set of recommended accounts from people in your network. { navigation.navigate('StarterPackWizard', {}) }} /> {}} showCancel={false} /> ) }