about summary refs log tree commit diff
path: root/src/state/queries/pinned-post.ts
blob: c3d9fd68755efc832ff7dd2f186b3f16bc63a54a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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 signed 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({message: 'Post pinned', context: 'toast'})))
        } else {
          Toast.show(_(msg({message: 'Post unpinned', context: 'toast'})))
        }

        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})
        }
      }
    },
  })
}