diff options
Diffstat (limited to 'src/view/screens/Profile.tsx')
-rw-r--r-- | src/view/screens/Profile.tsx | 115 |
1 files changed, 68 insertions, 47 deletions
diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx index 734230c6c..946f6ac54 100644 --- a/src/view/screens/Profile.tsx +++ b/src/view/screens/Profile.tsx @@ -1,7 +1,8 @@ -import React, {useMemo} from 'react' +import React, {useCallback, useMemo} from 'react' import {StyleSheet} from 'react-native' import { AppBskyActorDefs, + AppBskyGraphGetActorStarterPacks, moderateProfile, ModerationOpts, RichText as RichTextAPI, @@ -9,7 +10,11 @@ import { import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useFocusEffect} from '@react-navigation/native' -import {useQueryClient} from '@tanstack/react-query' +import { + InfiniteData, + UseInfiniteQueryResult, + useQueryClient, +} from '@tanstack/react-query' import {cleanError} from '#/lib/strings/errors' import {useProfileShadow} from '#/state/cache/profile-shadow' @@ -22,18 +27,23 @@ import {useAgent, useSession} from '#/state/session' import {useSetDrawerSwipeDisabled, useSetMinimalShellMode} from '#/state/shell' import {useComposerControls} from '#/state/shell/composer' import {useAnalytics} from 'lib/analytics/analytics' +import {IS_DEV, IS_TESTFLIGHT} from 'lib/app-info' import {useSetTitle} from 'lib/hooks/useSetTitle' import {ComposeIcon2} from 'lib/icons' import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types' +import {useGate} from 'lib/statsig/statsig' import {combinedDisplayName} from 'lib/strings/display-names' import {isInvalidHandle} from 'lib/strings/handles' import {colors, s} from 'lib/styles' +import {isWeb} from 'platform/detection' import {listenSoftReset} from 'state/events' +import {useActorStarterPacksQuery} from 'state/queries/actor-starter-packs' import {PagerWithHeader} from 'view/com/pager/PagerWithHeader' import {ProfileHeader, ProfileHeaderLoading} from '#/screens/Profile/Header' import {ProfileFeedSection} from '#/screens/Profile/Sections/Feed' import {ProfileLabelsSection} from '#/screens/Profile/Sections/Labels' import {ScreenHider} from '#/components/moderation/ScreenHider' +import {ProfileStarterPacks} from '#/components/StarterPack/ProfileStarterPacks' import {ExpoScrollForwarderView} from '../../../modules/expo-scroll-forwarder' import {ProfileFeedgens} from '../com/feeds/ProfileFeedgens' import {ProfileLists} from '../com/lists/ProfileLists' @@ -69,6 +79,7 @@ export function ProfileScreen({route}: Props) { } = useProfileQuery({ did: resolvedDid, }) + const starterPacksQuery = useActorStarterPacksQuery({did: resolvedDid}) const onPressTryAgain = React.useCallback(() => { if (resolveError) { @@ -86,7 +97,7 @@ export function ProfileScreen({route}: Props) { }, [queryClient, profile?.viewer?.blockedBy, resolvedDid]) // Most pushes will happen here, since we will have only placeholder data - if (isLoadingDid || isLoadingProfile) { + if (isLoadingDid || isLoadingProfile || starterPacksQuery.isLoading) { return ( <CenteredView> <ProfileHeaderLoading /> @@ -108,6 +119,7 @@ export function ProfileScreen({route}: Props) { return ( <ProfileScreenLoaded profile={profile} + starterPacksQuery={starterPacksQuery} moderationOpts={moderationOpts} isPlaceholderProfile={isPlaceholderProfile} hideBackButton={!!route.params.hideBackButton} @@ -131,11 +143,16 @@ function ProfileScreenLoaded({ isPlaceholderProfile, moderationOpts, hideBackButton, + starterPacksQuery, }: { profile: AppBskyActorDefs.ProfileViewDetailed moderationOpts: ModerationOpts hideBackButton: boolean isPlaceholderProfile: boolean + starterPacksQuery: UseInfiniteQueryResult< + InfiniteData<AppBskyGraphGetActorStarterPacks.OutputSchema, unknown>, + Error + > }) { const profile = useProfileShadow(profileUnshadowed) const {hasSession, currentAccount} = useSession() @@ -153,6 +170,9 @@ function ProfileScreenLoaded({ const [currentPage, setCurrentPage] = React.useState(0) const {_} = useLingui() const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled() + const gate = useGate() + const starterPacksEnabled = + IS_DEV || IS_TESTFLIGHT || (!isWeb && gate('starter_packs_enabled')) const [scrollViewTag, setScrollViewTag] = React.useState<number | null>(null) @@ -162,6 +182,7 @@ function ProfileScreenLoaded({ const likesSectionRef = React.useRef<SectionRef>(null) const feedsSectionRef = React.useRef<SectionRef>(null) const listsSectionRef = React.useRef<SectionRef>(null) + const starterPacksSectionRef = React.useRef<SectionRef>(null) const labelsSectionRef = React.useRef<SectionRef>(null) useSetTitle(combinedDisplayName(profile)) @@ -183,31 +204,23 @@ function ProfileScreenLoaded({ const showMediaTab = !hasLabeler const showLikesTab = isMe const showFeedsTab = isMe || (profile.associated?.feedgens || 0) > 0 + const showStarterPacksTab = + starterPacksEnabled && + (isMe || !!starterPacksQuery.data?.pages?.[0].starterPacks.length) const showListsTab = hasSession && (isMe || (profile.associated?.lists || 0) > 0) - const sectionTitles = useMemo<string[]>(() => { - return [ - showFiltersTab ? _(msg`Labels`) : undefined, - showListsTab && hasLabeler ? _(msg`Lists`) : undefined, - showPostsTab ? _(msg`Posts`) : undefined, - showRepliesTab ? _(msg`Replies`) : undefined, - showMediaTab ? _(msg`Media`) : undefined, - showLikesTab ? _(msg`Likes`) : undefined, - showFeedsTab ? _(msg`Feeds`) : undefined, - showListsTab && !hasLabeler ? _(msg`Lists`) : undefined, - ].filter(Boolean) as string[] - }, [ - showPostsTab, - showRepliesTab, - showMediaTab, - showLikesTab, - showFeedsTab, - showListsTab, - showFiltersTab, - hasLabeler, - _, - ]) + const sectionTitles = [ + showFiltersTab ? _(msg`Labels`) : undefined, + showListsTab && hasLabeler ? _(msg`Lists`) : undefined, + showPostsTab ? _(msg`Posts`) : undefined, + showRepliesTab ? _(msg`Replies`) : undefined, + showMediaTab ? _(msg`Media`) : undefined, + showLikesTab ? _(msg`Likes`) : undefined, + showFeedsTab ? _(msg`Feeds`) : undefined, + showStarterPacksTab ? _(msg`Starter Packs`) : undefined, + showListsTab && !hasLabeler ? _(msg`Lists`) : undefined, + ].filter(Boolean) as string[] let nextIndex = 0 let filtersIndex: number | null = null @@ -216,6 +229,7 @@ function ProfileScreenLoaded({ let mediaIndex: number | null = null let likesIndex: number | null = null let feedsIndex: number | null = null + let starterPacksIndex: number | null = null let listsIndex: number | null = null if (showFiltersTab) { filtersIndex = nextIndex++ @@ -235,11 +249,14 @@ function ProfileScreenLoaded({ if (showFeedsTab) { feedsIndex = nextIndex++ } + if (showStarterPacksTab) { + starterPacksIndex = nextIndex++ + } if (showListsTab) { listsIndex = nextIndex++ } - const scrollSectionToTop = React.useCallback( + const scrollSectionToTop = useCallback( (index: number) => { if (index === filtersIndex) { labelsSectionRef.current?.scrollToTop() @@ -253,6 +270,8 @@ function ProfileScreenLoaded({ likesSectionRef.current?.scrollToTop() } else if (index === feedsIndex) { feedsSectionRef.current?.scrollToTop() + } else if (index === starterPacksIndex) { + starterPacksSectionRef.current?.scrollToTop() } else if (index === listsIndex) { listsSectionRef.current?.scrollToTop() } @@ -265,6 +284,7 @@ function ProfileScreenLoaded({ likesIndex, feedsIndex, listsIndex, + starterPacksIndex, ], ) @@ -290,7 +310,7 @@ function ProfileScreenLoaded({ // events // = - const onPressCompose = React.useCallback(() => { + const onPressCompose = () => { track('ProfileScreen:PressCompose') const mention = profile.handle === currentAccount?.handle || @@ -298,23 +318,20 @@ function ProfileScreenLoaded({ ? undefined : profile.handle openComposer({mention}) - }, [openComposer, currentAccount, track, profile]) + } - const onPageSelected = React.useCallback((i: number) => { + const onPageSelected = (i: number) => { setCurrentPage(i) - }, []) + } - const onCurrentPageSelected = React.useCallback( - (index: number) => { - scrollSectionToTop(index) - }, - [scrollSectionToTop], - ) + const onCurrentPageSelected = (index: number) => { + scrollSectionToTop(index) + } // rendering // = - const renderHeader = React.useCallback(() => { + const renderHeader = () => { return ( <ExpoScrollForwarderView scrollViewTag={scrollViewTag}> <ProfileHeader @@ -327,16 +344,7 @@ function ProfileScreenLoaded({ /> </ExpoScrollForwarderView> ) - }, [ - scrollViewTag, - profile, - labelerInfo, - hasDescription, - descriptionRT, - moderationOpts, - hideBackButton, - showPlaceholder, - ]) + } return ( <ScreenHider @@ -442,6 +450,19 @@ function ProfileScreenLoaded({ /> ) : null} + {showStarterPacksTab + ? ({headerHeight, isFocused, scrollElRef}) => ( + <ProfileStarterPacks + ref={starterPacksSectionRef} + isMe={isMe} + starterPacksQuery={starterPacksQuery} + scrollElRef={scrollElRef as ListRef} + headerOffset={headerHeight} + enabled={isFocused} + setScrollViewTag={setScrollViewTag} + /> + ) + : null} {showListsTab && !profile.associated?.labeler ? ({headerHeight, isFocused, scrollElRef}) => ( <ProfileLists |