about summary refs log tree commit diff
path: root/src/view
diff options
context:
space:
mode:
Diffstat (limited to 'src/view')
-rw-r--r--src/view/com/auth/onboarding/RecommendedFollowsItem.tsx35
-rw-r--r--src/view/com/profile/FollowButton.tsx31
-rw-r--r--src/view/com/profile/ProfileHeader.tsx100
-rw-r--r--src/view/com/profile/ProfileHeaderSuggestedFollows.tsx34
4 files changed, 80 insertions, 120 deletions
diff --git a/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx b/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx
index 192923886..eadc3caff 100644
--- a/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx
+++ b/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx
@@ -13,10 +13,7 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {useAnalytics} from 'lib/analytics/analytics'
 import {Trans} from '@lingui/macro'
 import {Shadow, useProfileShadow} from '#/state/cache/profile-shadow'
-import {
-  useProfileFollowMutation,
-  useProfileUnfollowMutation,
-} from '#/state/queries/profile'
+import {useProfileFollowMutationQueue} from '#/state/queries/profile'
 import {logger} from '#/logger'
 
 type Props = {
@@ -77,35 +74,32 @@ export function ProfileCard({
   const pal = usePalette('default')
   const [addingMoreSuggestions, setAddingMoreSuggestions] =
     React.useState(false)
-  const {mutateAsync: follow} = useProfileFollowMutation()
-  const {mutateAsync: unfollow} = useProfileUnfollowMutation()
+  const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue(profile)
 
   const onToggleFollow = React.useCallback(async () => {
     try {
-      if (
-        profile.viewer?.following &&
-        profile.viewer?.following !== 'pending'
-      ) {
-        await unfollow({did: profile.did, followUri: profile.viewer.following})
-      } else if (
-        !profile.viewer?.following &&
-        profile.viewer?.following !== 'pending'
-      ) {
+      if (profile.viewer?.following) {
+        await queueUnfollow()
+      } else {
         setAddingMoreSuggestions(true)
-        await follow({did: profile.did})
+        await queueFollow()
         await onFollowStateChange({did: profile.did, following: true})
         setAddingMoreSuggestions(false)
         track('Onboarding:SuggestedFollowFollowed')
       }
-    } catch (e) {
-      logger.error('RecommendedFollows: failed to toggle following', {error: e})
+    } catch (e: any) {
+      if (e?.name !== 'AbortError') {
+        logger.error('RecommendedFollows: failed to toggle following', {
+          error: e,
+        })
+      }
     } finally {
       setAddingMoreSuggestions(false)
     }
   }, [
     profile,
-    follow,
-    unfollow,
+    queueFollow,
+    queueUnfollow,
     setAddingMoreSuggestions,
     track,
     onFollowStateChange,
@@ -142,7 +136,6 @@ export function ProfileCard({
           labelStyle={styles.followButton}
           onPress={onToggleFollow}
           label={profile.viewer?.following ? 'Unfollow' : 'Follow'}
-          withLoading={true}
         />
       </View>
       {profile.description ? (
diff --git a/src/view/com/profile/FollowButton.tsx b/src/view/com/profile/FollowButton.tsx
index 032a910c7..1252f8ca8 100644
--- a/src/view/com/profile/FollowButton.tsx
+++ b/src/view/com/profile/FollowButton.tsx
@@ -3,10 +3,7 @@ import {StyleProp, TextStyle, View} from 'react-native'
 import {AppBskyActorDefs} from '@atproto/api'
 import {Button, ButtonType} from '../util/forms/Button'
 import * as Toast from '../util/Toast'
-import {
-  useProfileFollowMutation,
-  useProfileUnfollowMutation,
-} from '#/state/queries/profile'
+import {useProfileFollowMutationQueue} from '#/state/queries/profile'
 import {Shadow} from '#/state/cache/types'
 
 export function FollowButton({
@@ -20,31 +17,25 @@ export function FollowButton({
   profile: Shadow<AppBskyActorDefs.ProfileViewBasic>
   labelStyle?: StyleProp<TextStyle>
 }) {
-  const followMutation = useProfileFollowMutation()
-  const unfollowMutation = useProfileUnfollowMutation()
+  const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue(profile)
 
   const onPressFollow = async () => {
-    if (profile.viewer?.following) {
-      return
-    }
     try {
-      await followMutation.mutateAsync({did: profile.did})
+      await queueFollow()
     } catch (e: any) {
-      Toast.show(`An issue occurred, please try again.`)
+      if (e?.name !== 'AbortError') {
+        Toast.show(`An issue occurred, please try again.`)
+      }
     }
   }
 
   const onPressUnfollow = async () => {
-    if (!profile.viewer?.following) {
-      return
-    }
     try {
-      await unfollowMutation.mutateAsync({
-        did: profile.did,
-        followUri: profile.viewer?.following,
-      })
+      await queueUnfollow()
     } catch (e: any) {
-      Toast.show(`An issue occurred, please try again.`)
+      if (e?.name !== 'AbortError') {
+        Toast.show(`An issue occurred, please try again.`)
+      }
     }
   }
 
@@ -59,7 +50,6 @@ export function FollowButton({
         labelStyle={labelStyle}
         onPress={onPressUnfollow}
         label="Unfollow"
-        withLoading={true}
       />
     )
   } else {
@@ -69,7 +59,6 @@ export function FollowButton({
         labelStyle={labelStyle}
         onPress={onPressFollow}
         label="Follow"
-        withLoading={true}
       />
     )
   }
diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx
index a6c978fd4..60311a0b2 100644
--- a/src/view/com/profile/ProfileHeader.tsx
+++ b/src/view/com/profile/ProfileHeader.tsx
@@ -32,12 +32,9 @@ import {ProfileHeaderSuggestedFollows} from './ProfileHeaderSuggestedFollows'
 import {useModalControls} from '#/state/modals'
 import {useLightboxControls, ProfileImageLightbox} from '#/state/lightbox'
 import {
-  useProfileFollowMutation,
-  useProfileUnfollowMutation,
-  useProfileMuteMutation,
-  useProfileUnmuteMutation,
-  useProfileBlockMutation,
-  useProfileUnblockMutation,
+  useProfileMuteMutationQueue,
+  useProfileBlockMutationQueue,
+  useProfileFollowMutationQueue,
 } from '#/state/queries/profile'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useAnalytics} from 'lib/analytics/analytics'
@@ -130,12 +127,9 @@ function ProfileHeaderLoaded({
         : undefined,
     [profile],
   )
-  const followMutation = useProfileFollowMutation()
-  const unfollowMutation = useProfileUnfollowMutation()
-  const muteMutation = useProfileMuteMutation()
-  const unmuteMutation = useProfileUnmuteMutation()
-  const blockMutation = useProfileBlockMutation()
-  const unblockMutation = useProfileUnblockMutation()
+  const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue(profile)
+  const [queueMute, queueUnmute] = useProfileMuteMutationQueue(profile)
+  const [queueBlock, queueUnblock] = useProfileBlockMutationQueue(profile)
 
   const onPressBack = React.useCallback(() => {
     if (navigation.canGoBack()) {
@@ -154,44 +148,39 @@ function ProfileHeaderLoaded({
     }
   }, [openLightbox, profile, moderation])
 
-  const onPressFollow = React.useCallback(async () => {
-    if (profile.viewer?.following) {
-      return
-    }
+  const onPressFollow = async () => {
     try {
       track('ProfileHeader:FollowButtonClicked')
-      await followMutation.mutateAsync({did: profile.did})
+      await queueFollow()
       Toast.show(
         `Following ${sanitizeDisplayName(
           profile.displayName || profile.handle,
         )}`,
       )
     } catch (e: any) {
-      logger.error('Failed to follow', {error: String(e)})
-      Toast.show(`There was an issue! ${e.toString()}`)
+      if (e?.name !== 'AbortError') {
+        logger.error('Failed to follow', {error: String(e)})
+        Toast.show(`There was an issue! ${e.toString()}`)
+      }
     }
-  }, [followMutation, profile, track])
+  }
 
-  const onPressUnfollow = React.useCallback(async () => {
-    if (!profile.viewer?.following) {
-      return
-    }
+  const onPressUnfollow = async () => {
     try {
       track('ProfileHeader:UnfollowButtonClicked')
-      await unfollowMutation.mutateAsync({
-        did: profile.did,
-        followUri: profile.viewer?.following,
-      })
+      await queueUnfollow()
       Toast.show(
         `No longer following ${sanitizeDisplayName(
           profile.displayName || profile.handle,
         )}`,
       )
     } catch (e: any) {
-      logger.error('Failed to unfollow', {error: String(e)})
-      Toast.show(`There was an issue! ${e.toString()}`)
+      if (e?.name !== 'AbortError') {
+        logger.error('Failed to unfollow', {error: String(e)})
+        Toast.show(`There was an issue! ${e.toString()}`)
+      }
     }
-  }, [unfollowMutation, profile, track])
+  }
 
   const onPressEditProfile = React.useCallback(() => {
     track('ProfileHeader:EditProfileButtonClicked')
@@ -218,24 +207,28 @@ function ProfileHeaderLoaded({
   const onPressMuteAccount = React.useCallback(async () => {
     track('ProfileHeader:MuteAccountButtonClicked')
     try {
-      await muteMutation.mutateAsync({did: profile.did})
+      await queueMute()
       Toast.show('Account muted')
     } catch (e: any) {
-      logger.error('Failed to mute account', {error: e})
-      Toast.show(`There was an issue! ${e.toString()}`)
+      if (e?.name !== 'AbortError') {
+        logger.error('Failed to mute account', {error: e})
+        Toast.show(`There was an issue! ${e.toString()}`)
+      }
     }
-  }, [track, muteMutation, profile])
+  }, [track, queueMute])
 
   const onPressUnmuteAccount = React.useCallback(async () => {
     track('ProfileHeader:UnmuteAccountButtonClicked')
     try {
-      await unmuteMutation.mutateAsync({did: profile.did})
+      await queueUnmute()
       Toast.show('Account unmuted')
     } catch (e: any) {
-      logger.error('Failed to unmute account', {error: e})
-      Toast.show(`There was an issue! ${e.toString()}`)
+      if (e?.name !== 'AbortError') {
+        logger.error('Failed to unmute account', {error: e})
+        Toast.show(`There was an issue! ${e.toString()}`)
+      }
     }
-  }, [track, unmuteMutation, profile])
+  }, [track, queueUnmute])
 
   const onPressBlockAccount = React.useCallback(async () => {
     track('ProfileHeader:BlockAccountButtonClicked')
@@ -245,19 +238,18 @@ function ProfileHeaderLoaded({
       message:
         'Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you.',
       onPressConfirm: async () => {
-        if (profile.viewer?.blocking) {
-          return
-        }
         try {
-          await blockMutation.mutateAsync({did: profile.did})
+          await queueBlock()
           Toast.show('Account blocked')
         } catch (e: any) {
-          logger.error('Failed to block account', {error: e})
-          Toast.show(`There was an issue! ${e.toString()}`)
+          if (e?.name !== 'AbortError') {
+            logger.error('Failed to block account', {error: e})
+            Toast.show(`There was an issue! ${e.toString()}`)
+          }
         }
       },
     })
-  }, [track, blockMutation, profile, openModal])
+  }, [track, queueBlock, openModal])
 
   const onPressUnblockAccount = React.useCallback(async () => {
     track('ProfileHeader:UnblockAccountButtonClicked')
@@ -267,22 +259,18 @@ function ProfileHeaderLoaded({
       message:
         'The account will be able to interact with you after unblocking.',
       onPressConfirm: async () => {
-        if (!profile.viewer?.blocking) {
-          return
-        }
         try {
-          await unblockMutation.mutateAsync({
-            did: profile.did,
-            blockUri: profile.viewer.blocking,
-          })
+          await queueUnblock()
           Toast.show('Account unblocked')
         } catch (e: any) {
-          logger.error('Failed to unblock account', {error: e})
-          Toast.show(`There was an issue! ${e.toString()}`)
+          if (e?.name !== 'AbortError') {
+            logger.error('Failed to unblock account', {error: e})
+            Toast.show(`There was an issue! ${e.toString()}`)
+          }
         }
       },
     })
-  }, [track, unblockMutation, profile, openModal])
+  }, [track, queueUnblock, openModal])
 
   const onPressReportAccount = React.useCallback(() => {
     track('ProfileHeader:ReportAccountButtonClicked')
diff --git a/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx b/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx
index a34f2b5fe..6e060af49 100644
--- a/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx
+++ b/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx
@@ -26,10 +26,7 @@ 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 {
-  useProfileFollowMutation,
-  useProfileUnfollowMutation,
-} from '#/state/queries/profile'
+import {useProfileFollowMutationQueue} from '#/state/queries/profile'
 
 const OUTER_PADDING = 10
 const INNER_PADDING = 14
@@ -208,34 +205,28 @@ function SuggestedFollow({
   const pal = usePalette('default')
   const moderationOpts = useModerationOpts()
   const profile = useProfileShadow(profileUnshadowed, dataUpdatedAt)
-  const followMutation = useProfileFollowMutation()
-  const unfollowMutation = useProfileUnfollowMutation()
+  const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue(profile)
 
   const onPressFollow = React.useCallback(async () => {
-    if (profile.viewer?.following) {
-      return
-    }
     try {
       track('ProfileHeader:SuggestedFollowFollowed')
-      await followMutation.mutateAsync({did: profile.did})
+      await queueFollow()
     } catch (e: any) {
-      Toast.show('An issue occurred, please try again.')
+      if (e?.name !== 'AbortError') {
+        Toast.show('An issue occurred, please try again.')
+      }
     }
-  }, [followMutation, profile, track])
+  }, [queueFollow, track])
 
   const onPressUnfollow = React.useCallback(async () => {
-    if (!profile.viewer?.following) {
-      return
-    }
     try {
-      await unfollowMutation.mutateAsync({
-        did: profile.did,
-        followUri: profile.viewer?.following,
-      })
+      await queueUnfollow()
     } catch (e: any) {
-      Toast.show('An issue occurred, please try again.')
+      if (e?.name !== 'AbortError') {
+        Toast.show('An issue occurred, please try again.')
+      }
     }
-  }, [unfollowMutation, profile])
+  }, [queueUnfollow])
 
   if (!moderationOpts) {
     return null
@@ -284,7 +275,6 @@ function SuggestedFollow({
           type="inverted"
           labelStyle={{textAlign: 'center'}}
           onPress={following ? onPressUnfollow : onPressFollow}
-          withLoading
         />
       </View>
     </Link>