about summary refs log tree commit diff
path: root/src/state/queries/pinned-post.ts
diff options
context:
space:
mode:
authorSamuel Newman <mozzius@protonmail.com>2024-09-27 22:50:32 +0100
committerGitHub <noreply@github.com>2024-09-28 00:50:32 +0300
commit4b5d6e6efb09a714d82e2093dec39c85400a2de6 (patch)
tree981d0e08b30549234e02be49dbb190e55740556f /src/state/queries/pinned-post.ts
parentf68b15219fd02e23d965015201400138ed69d59d (diff)
downloadvoidsky-4b5d6e6efb09a714d82e2093dec39c85400a2de6.tar.zst
Pinned posts (#5055)
* add to dropdown menu

* use normal profile mutation hook

* add pin as reason

* request pins

* shadow update

* rm logs

* get prev pinned from getProfile

* fix toasts

* invalidate after appview ready

* don't mutate params

* rm log

* use checkCommited rather than manual whenAppViewReady

* move to mutation

* even more optimistic optimistic update

* allow pins in `posts_and_author_threads`

* update @atproto/api

* add reasonPin type

* fix strange type error in unrelated query

* another missing type
Diffstat (limited to 'src/state/queries/pinned-post.ts')
-rw-r--r--src/state/queries/pinned-post.ts87
1 files changed, 87 insertions, 0 deletions
diff --git a/src/state/queries/pinned-post.ts b/src/state/queries/pinned-post.ts
new file mode 100644
index 000000000..7e2c8ee79
--- /dev/null
+++ b/src/state/queries/pinned-post.ts
@@ -0,0 +1,87 @@
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+import {useMutation, useQueryClient} from '@tanstack/react-query'
+
+import {logger} from '#/logger'
+import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
+import * as Toast from '#/view/com/util/Toast'
+import {updatePostShadow} from '../cache/post-shadow'
+import {useAgent, useSession} from '../session'
+import {useProfileUpdateMutation} from './profile'
+
+export function usePinnedPostMutation() {
+  const {_} = useLingui()
+  const {currentAccount} = useSession()
+  const agent = useAgent()
+  const queryClient = useQueryClient()
+  const {mutateAsync: profileUpdateMutate} = useProfileUpdateMutation()
+
+  return useMutation({
+    mutationFn: async ({
+      postUri,
+      postCid,
+      action,
+    }: {
+      postUri: string
+      postCid: string
+      action: 'pin' | 'unpin'
+    }) => {
+      const pinCurrentPost = action === 'pin'
+      let prevPinnedPost: string | undefined
+      try {
+        updatePostShadow(queryClient, postUri, {pinned: pinCurrentPost})
+
+        // get the currently pinned post so we can optimistically remove the pin from it
+        if (!currentAccount) throw new Error('Not logged in')
+        const {data: profile} = await agent.getProfile({
+          actor: currentAccount.did,
+        })
+        prevPinnedPost = profile.pinnedPost?.uri
+        if (prevPinnedPost && prevPinnedPost !== postUri) {
+          updatePostShadow(queryClient, prevPinnedPost, {pinned: false})
+        }
+
+        await profileUpdateMutate({
+          profile,
+          updates: existing => {
+            existing.pinnedPost = pinCurrentPost
+              ? {uri: postUri, cid: postCid}
+              : undefined
+            return existing
+          },
+          checkCommitted: res =>
+            pinCurrentPost
+              ? res.data.pinnedPost?.uri === postUri
+              : !res.data.pinnedPost,
+        })
+
+        if (pinCurrentPost) {
+          Toast.show(_(msg`Post pinned`))
+        } else {
+          Toast.show(_(msg`Post unpinned`))
+        }
+
+        queryClient.invalidateQueries({
+          queryKey: FEED_RQKEY(
+            `author|${currentAccount.did}|posts_and_author_threads`,
+          ),
+        })
+        queryClient.invalidateQueries({
+          queryKey: FEED_RQKEY(
+            `author|${currentAccount.did}|posts_with_replies`,
+          ),
+        })
+      } catch (e: any) {
+        Toast.show(_(msg`Failed to pin post`))
+        logger.error('Failed to pin post', {message: String(e)})
+        // revert optimistic update
+        updatePostShadow(queryClient, postUri, {
+          pinned: !pinCurrentPost,
+        })
+        if (prevPinnedPost && prevPinnedPost !== postUri) {
+          updatePostShadow(queryClient, prevPinnedPost, {pinned: true})
+        }
+      }
+    },
+  })
+}