diff --git a/src/state/queries/profile.ts b/src/state/queries/profile.ts index fad9a1fd73..1bd28d5b1c 100644 --- a/src/state/queries/profile.ts +++ b/src/state/queries/profile.ts @@ -3,10 +3,12 @@ import {useQuery, useMutation} from '@tanstack/react-query' import {useSession} from '../session' import {updateProfileShadow} from '../cache/profile-shadow' +export const RQKEY = (did: string) => ['profile', did] + export function useProfileQuery({did}: {did: string | undefined}) { const {agent} = useSession() return useQuery({ - queryKey: ['profile', did], + queryKey: RQKEY(did), queryFn: async () => { const res = await agent.getProfile({actor: did || ''}) return res.data diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx index eb8ca6cabb..ea3b863013 100644 --- a/src/view/com/profile/ProfileHeader.tsx +++ b/src/view/com/profile/ProfileHeader.tsx @@ -31,7 +31,6 @@ import {NativeDropdown, DropdownItem} from '../util/forms/NativeDropdown' import {Link} from '../util/Link' import {ProfileHeaderSuggestedFollows} from './ProfileHeaderSuggestedFollows' import {useStores} from 'state/index' -import {FollowState} from 'state/models/cache/my-follows' import {useModalControls} from '#/state/modals' import { useProfileFollowMutation, @@ -59,7 +58,6 @@ import {useSession} from '#/state/session' interface Props { profile: AppBskyActorDefs.ProfileViewDetailed moderation: ProfileModeration - onRefreshAll: () => void hideBackButton?: boolean isProfilePreview?: boolean } @@ -67,7 +65,6 @@ interface Props { export function ProfileHeader({ profile, moderation, - onRefreshAll, hideBackButton = false, isProfilePreview, }: Props) { @@ -103,7 +100,6 @@ export function ProfileHeader({ @@ -113,7 +109,6 @@ export function ProfileHeader({ function ProfileHeaderLoaded({ profile, moderation, - onRefreshAll, hideBackButton = false, isProfilePreview, }: Props) { @@ -203,9 +198,8 @@ function ProfileHeaderLoaded({ openModal({ name: 'edit-profile', profileView: profile, - onUpdate: onRefreshAll, }) - }, [track, openModal, profile, onRefreshAll]) + }, [track, openModal, profile]) const onPressShare = React.useCallback(() => { track('ProfileHeader:ShareButtonClicked') @@ -256,7 +250,6 @@ function ProfileHeaderLoaded({ } try { await blockMutation.mutateAsync({did: profile.did}) - onRefreshAll() Toast.show('Account blocked') } catch (e: any) { logger.error('Failed to block account', {error: e}) @@ -264,7 +257,7 @@ function ProfileHeaderLoaded({ } }, }) - }, [track, blockMutation, profile, openModal, onRefreshAll]) + }, [track, blockMutation, profile, openModal]) const onPressUnblockAccount = React.useCallback(async () => { track('ProfileHeader:UnblockAccountButtonClicked') @@ -282,7 +275,6 @@ function ProfileHeaderLoaded({ did: profile.did, blockUri: profile.viewer.blocking, }) - onRefreshAll() Toast.show('Account unblocked') } catch (e: any) { logger.error('Failed to unblock account', {error: e}) @@ -290,7 +282,7 @@ function ProfileHeaderLoaded({ } }, }) - }, [track, unblockMutation, profile, openModal, onRefreshAll]) + }, [track, unblockMutation, profile, openModal]) const onPressReportAccount = React.useCallback(() => { track('ProfileHeader:ReportAccountButtonClicked') diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx index 73a4c9d172..dab8988ad5 100644 --- a/src/view/screens/Profile.tsx +++ b/src/view/screens/Profile.tsx @@ -1,38 +1,26 @@ -import React, {useEffect, useMemo, useState} from 'react' +import React, {useMemo} from 'react' import {ActivityIndicator, StyleSheet, View} from 'react-native' import {useFocusEffect} from '@react-navigation/native' import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api' -import {Trans, msg} from '@lingui/macro' +import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {withAuthRequired} from 'view/com/auth/withAuthRequired' -import {ViewSelector, ViewSelectorHandle} from '../com/util/ViewSelector' +import {ViewSelectorHandle} from '../com/util/ViewSelector' import {CenteredView} from '../com/util/Views' import {ScreenHider} from 'view/com/util/moderation/ScreenHider' -import {ProfileUiModel, Sections} from 'state/models/ui/profile' import {Feed} from 'view/com/posts/Feed' import {useStores} from 'state/index' import {ProfileHeader} from '../com/profile/ProfileHeader' -import {FeedSlice} from '../com/posts/FeedSlice' import {PagerWithHeader} from 'view/com/pager/PagerWithHeader' -import {ListCard} from 'view/com/lists/ListCard' -import { - PostFeedLoadingPlaceholder, - ProfileCardFeedLoadingPlaceholder, -} from '../com/util/LoadingPlaceholder' import {ErrorScreen} from '../com/util/error/ErrorScreen' -import {ErrorMessage} from '../com/util/error/ErrorMessage' import {EmptyState} from '../com/util/EmptyState' -import {Text} from '../com/util/text/Text' import {FAB} from '../com/util/fab/FAB' import {s, colors} from 'lib/styles' import {useAnalytics} from 'lib/analytics/analytics' import {ComposeIcon2} from 'lib/icons' -import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard' -import {FeedSourceModel} from 'state/models/content/feed-source' import {useSetTitle} from 'lib/hooks/useSetTitle' import {combinedDisplayName} from 'lib/strings/display-names' -import {logger} from '#/logger' import {OnScrollHandler} from '#/lib/hooks/useOnMainScroll' import {FeedDescriptor} from '#/state/queries/post-feed' import {useResolveDidQuery} from '#/state/queries/resolve-uri' @@ -53,14 +41,39 @@ export const ProfileScreen = withAuthRequired(function ProfileScreenImpl({ const name = route.params.name === 'me' ? currentAccount?.did : route.params.name const moderationOpts = useModerationOpts() - const {data: resolvedDid, error: resolveError} = useResolveDidQuery(name) + const { + data: resolvedDid, + error: resolveError, + refetch: refetchDid, + isFetching: isFetchingDid, + } = useResolveDidQuery(name) const { data: profile, dataUpdatedAt, error: profileError, + refetch: refetchProfile, + isFetching: isFetchingProfile, } = useProfileQuery({ did: resolvedDid?.did, }) + + const onPressTryAgain = React.useCallback(() => { + if (resolveError) { + refetchDid() + } else { + refetchProfile() + } + }, [resolveError, refetchDid, refetchProfile]) + + if (isFetchingDid || isFetchingProfile) { + return ( + + + + + + ) + } if (resolveError || profileError) { return ( @@ -68,6 +81,7 @@ export const ProfileScreen = withAuthRequired(function ProfileScreenImpl({ testID="profileErrorScreen" title="Oops!" message={cleanError(resolveError || profileError)} + onPressTryAgain={onPressTryAgain} /> ) @@ -82,11 +96,15 @@ export const ProfileScreen = withAuthRequired(function ProfileScreenImpl({ /> ) } + // should never happen return ( - - - + ) }) @@ -112,6 +130,8 @@ function ProfileScreenLoaded({ const viewSelectorRef = React.useRef(null) const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled() + useSetTitle(combinedDisplayName(profile)) + const moderation = useMemo( () => moderateProfile(profile, moderationOpts), [profile, moderationOpts], @@ -126,11 +146,12 @@ function ProfileScreenLoaded({ useFocusEffect( React.useCallback(() => { setMinimalShellMode(false) + screen('Profile') const softResetSub = store.onScreenSoftReset(() => { viewSelectorRef.current?.scrollToTop() }) return () => softResetSub.remove() - }, [store, viewSelectorRef, setMinimalShellMode]), + }, [store, viewSelectorRef, setMinimalShellMode, screen]), ) useFocusEffect( @@ -155,14 +176,6 @@ function ProfileScreenLoaded({ store.shell.openComposer({mention}) }, [store, currentAccount, track, profile]) - const onRefresh = React.useCallback(() => { - // TODO - }, []) - - const onPressTryAgain = React.useCallback(() => { - // TODO - }, []) - const onPageSelected = React.useCallback( i => { setCurrentPage(i) @@ -178,11 +191,10 @@ function ProfileScreenLoaded({ ) - }, [profile, moderation, onRefresh, hideBackButton]) + }, [profile, moderation, hideBackButton]) return ( ( return ( ( }, ) -function LoadingMoreFooter() { - return ( - - - - ) -} - const styles = StyleSheet.create({ container: { flexDirection: 'column',